From bda87f82a8f76b9245bded0ef2b89f1ed652dbaa Mon Sep 17 00:00:00 2001 From: hailin Date: Tue, 13 May 2025 14:08:13 +0800 Subject: [PATCH] . --- internal/start/start.go | 475 ---------------------------------------- 1 file changed, 475 deletions(-) diff --git a/internal/start/start.go b/internal/start/start.go index 5402283..fce8e80 100644 --- a/internal/start/start.go +++ b/internal/start/start.go @@ -5,8 +5,6 @@ import ( "context" _ "embed" "fmt" - "net" - "net/url" "os" "path" "path/filepath" @@ -17,14 +15,12 @@ import ( "github.com/docker/docker/api/types/container" "github.com/docker/docker/api/types/network" - "github.com/docker/docker/client" "github.com/docker/go-connections/nat" "github.com/go-errors/errors" "github.com/jackc/pgconn" "github.com/jackc/pgx/v4" "github.com/spf13/afero" "github.com/supabase/cli/internal/db/start" - "github.com/supabase/cli/internal/functions/serve" "github.com/supabase/cli/internal/seed/buckets" "github.com/supabase/cli/internal/services" "github.com/supabase/cli/internal/status" @@ -173,173 +169,6 @@ func run(p utils.Program, ctx context.Context, fsys afero.Fs, excludedContainers utils.Config.Storage.ImageTransformation.Enabled && !isContainerExcluded(utils.Config.Storage.ImgProxyImage, excluded) p.Send(utils.StatusMsg("Starting containers...")) - // Start Logflare - if utils.Config.Analytics.Enabled && !isContainerExcluded(utils.Config.Analytics.Image, excluded) { - env := []string{ - "DB_DATABASE=_supabase", - "DB_HOSTNAME=" + dbConfig.Host, - fmt.Sprintf("DB_PORT=%d", dbConfig.Port), - "DB_SCHEMA=_analytics", - "DB_USERNAME=supabase_admin", - "DB_PASSWORD=" + dbConfig.Password, - "LOGFLARE_MIN_CLUSTER_SIZE=1", - "LOGFLARE_SINGLE_TENANT=true", - "LOGFLARE_SUPABASE_MODE=true", - "LOGFLARE_API_KEY=" + utils.Config.Analytics.ApiKey, - "LOGFLARE_LOG_LEVEL=warn", - "LOGFLARE_NODE_HOST=127.0.0.1", - "LOGFLARE_FEATURE_FLAG_OVERRIDE='multibackend=true'", - "RELEASE_COOKIE=cookie", - } - bind := []string{} - - switch utils.Config.Analytics.Backend { - case config.LogflareBigQuery: - workdir, err := os.Getwd() - if err != nil { - return errors.Errorf("failed to get working directory: %w", err) - } - hostJwtPath := filepath.Join(workdir, utils.Config.Analytics.GcpJwtPath) - bind = append(bind, hostJwtPath+":/opt/app/rel/logflare/bin/gcloud.json") - // This is hardcoded in studio frontend - env = append(env, - "GOOGLE_DATASET_ID_APPEND=_prod", - "GOOGLE_PROJECT_ID="+utils.Config.Analytics.GcpProjectId, - "GOOGLE_PROJECT_NUMBER="+utils.Config.Analytics.GcpProjectNumber, - ) - case config.LogflarePostgres: - env = append(env, - fmt.Sprintf("POSTGRES_BACKEND_URL=postgresql://%s:%s@%s:%d/%s", dbConfig.User, dbConfig.Password, dbConfig.Host, dbConfig.Port, "_supabase"), - "POSTGRES_BACKEND_SCHEMA=_analytics", - ) - } - - if _, err := utils.DockerStart( - ctx, - container.Config{ - Hostname: "127.0.0.1", - Image: utils.Config.Analytics.Image, - Env: env, - // Original entrypoint conflicts with healthcheck due to 15 seconds sleep: - // https://github.com/Logflare/logflare/blob/staging/run.sh#L35 - Entrypoint: []string{"sh", "-c", `cat <<'EOF' > run.sh && sh run.sh -./logflare eval Logflare.Release.migrate -./logflare start --sname logflare -EOF -`}, - Healthcheck: &container.HealthConfig{ - Test: []string{"CMD", "curl", "-sSfL", "--head", "-o", "/dev/null", - "http://127.0.0.1:4000/health", - }, - Interval: 10 * time.Second, - Timeout: 2 * time.Second, - Retries: 3, - StartPeriod: 10 * time.Second, - }, - ExposedPorts: nat.PortSet{"4000/tcp": {}}, - }, - container.HostConfig{ - Binds: bind, - PortBindings: nat.PortMap{"4000/tcp": []nat.PortBinding{{HostPort: strconv.FormatUint(uint64(utils.Config.Analytics.Port), 10)}}}, - RestartPolicy: container.RestartPolicy{Name: "always"}, - }, - network.NetworkingConfig{ - EndpointsConfig: map[string]*network.EndpointSettings{ - utils.NetId: { - Aliases: utils.LogflareAliases, - }, - }, - }, - utils.LogflareId, - ); err != nil { - return err - } - started = append(started, utils.LogflareId) - } - - // Start vector - if utils.Config.Analytics.Enabled && !isContainerExcluded(utils.Config.Analytics.VectorImage, excluded) { - var vectorConfigBuf bytes.Buffer - if err := vectorConfigTemplate.Option("missingkey=error").Execute(&vectorConfigBuf, vectorConfig{ - ApiKey: utils.Config.Analytics.ApiKey, - VectorId: utils.VectorId, - LogflareId: utils.LogflareId, - KongId: utils.KongId, - GotrueId: utils.GotrueId, - RestId: utils.RestId, - RealtimeId: utils.RealtimeId, - StorageId: utils.StorageId, - EdgeRuntimeId: utils.EdgeRuntimeId, - DbId: utils.DbId, - }); err != nil { - return errors.Errorf("failed to exec template: %w", err) - } - var binds, env, securityOpts []string - // Special case for GitLab pipeline - parsed, err := client.ParseHostURL(utils.Docker.DaemonHost()) - if err != nil { - return errors.Errorf("failed to parse docker host: %w", err) - } - // Ref: https://vector.dev/docs/reference/configuration/sources/docker_logs/#docker_host - dindHost := &url.URL{Scheme: "http", Host: net.JoinHostPort(utils.DinDHost, "2375")} - switch parsed.Scheme { - case "tcp": - if _, port, err := net.SplitHostPort(parsed.Host); err == nil { - dindHost.Host = net.JoinHostPort(utils.DinDHost, port) - } - env = append(env, "DOCKER_HOST="+dindHost.String()) - case "npipe": - fmt.Fprintln(os.Stderr, utils.Yellow("WARNING:"), "analytics requires docker daemon exposed on tcp://localhost:2375") - env = append(env, "DOCKER_HOST="+dindHost.String()) - case "unix": - if dindHost, err = client.ParseHostURL(client.DefaultDockerHost); err != nil { - return errors.Errorf("failed to parse default host: %w", err) - } else if strings.HasSuffix(parsed.Host, "/.docker/run/docker.sock") { - fmt.Fprintln(os.Stderr, utils.Yellow("WARNING:"), "analytics requires mounting default docker socket:", dindHost.Host) - binds = append(binds, fmt.Sprintf("%[1]s:%[1]s:ro", dindHost.Host)) - } else { - // Podman and OrbStack can mount root-less socket without issue - binds = append(binds, fmt.Sprintf("%s:%s:ro", parsed.Host, dindHost.Host)) - securityOpts = append(securityOpts, "label:disable") - } - } - if _, err := utils.DockerStart( - ctx, - container.Config{ - Image: utils.Config.Analytics.VectorImage, - Env: env, - Entrypoint: []string{"sh", "-c", `cat <<'EOF' > /etc/vector/vector.yaml && vector --config /etc/vector/vector.yaml -` + vectorConfigBuf.String() + ` -EOF -`}, - Healthcheck: &container.HealthConfig{ - Test: []string{"CMD", "wget", "--no-verbose", "--tries=1", "--spider", - "http://127.0.0.1:9001/health", - }, - Interval: 10 * time.Second, - Timeout: 2 * time.Second, - Retries: 3, - }, - }, - container.HostConfig{ - Binds: binds, - RestartPolicy: container.RestartPolicy{Name: "always"}, - SecurityOpt: securityOpts, - }, - network.NetworkingConfig{ - EndpointsConfig: map[string]*network.EndpointSettings{ - utils.NetId: { - Aliases: utils.VectorAliases, - }, - }, - }, - utils.VectorId, - ); err != nil { - return err - } - started = append(started, utils.VectorId) - } - // Start Kong. if !isContainerExcluded(utils.Config.Api.KongImage, excluded) { var kongConfigBuf bytes.Buffer @@ -700,100 +529,6 @@ EOF started = append(started, utils.GotrueId) } - // Start Inbucket. - if utils.Config.Inbucket.Enabled && !isContainerExcluded(utils.Config.Inbucket.Image, excluded) { - inbucketPortBindings := nat.PortMap{"9000/tcp": []nat.PortBinding{{HostPort: strconv.FormatUint(uint64(utils.Config.Inbucket.Port), 10)}}} - if utils.Config.Inbucket.SmtpPort != 0 { - inbucketPortBindings["2500/tcp"] = []nat.PortBinding{{HostPort: strconv.FormatUint(uint64(utils.Config.Inbucket.SmtpPort), 10)}} - } - if utils.Config.Inbucket.Pop3Port != 0 { - inbucketPortBindings["1100/tcp"] = []nat.PortBinding{{HostPort: strconv.FormatUint(uint64(utils.Config.Inbucket.Pop3Port), 10)}} - } - if _, err := utils.DockerStart( - ctx, - container.Config{ - Image: utils.Config.Inbucket.Image, - }, - container.HostConfig{ - Binds: []string{ - // Override default mount points to avoid creating multiple anonymous volumes - // Ref: https://github.com/inbucket/inbucket/blob/v3.0.4/Dockerfile#L52 - utils.InbucketId + ":/config", - utils.InbucketId + ":/storage", - }, - PortBindings: inbucketPortBindings, - RestartPolicy: container.RestartPolicy{Name: "always"}, - }, - network.NetworkingConfig{ - EndpointsConfig: map[string]*network.EndpointSettings{ - utils.NetId: { - Aliases: utils.InbucketAliases, - }, - }, - }, - utils.InbucketId, - ); err != nil { - return err - } - started = append(started, utils.InbucketId) - } - - // Start Realtime. - if utils.Config.Realtime.Enabled && !isContainerExcluded(utils.Config.Realtime.Image, excluded) { - if _, err := utils.DockerStart( - ctx, - container.Config{ - Image: utils.Config.Realtime.Image, - Env: []string{ - "PORT=4000", - "DB_HOST=" + dbConfig.Host, - fmt.Sprintf("DB_PORT=%d", dbConfig.Port), - "DB_USER=supabase_admin", - "DB_PASSWORD=" + dbConfig.Password, - "DB_NAME=" + dbConfig.Database, - "DB_AFTER_CONNECT_QUERY=SET search_path TO _realtime", - "DB_ENC_KEY=" + utils.Config.Realtime.EncryptionKey, - "API_JWT_SECRET=" + utils.Config.Auth.JwtSecret, - fmt.Sprintf("API_JWT_JWKS=%s", jwks), - "METRICS_JWT_SECRET=" + utils.Config.Auth.JwtSecret, - "APP_NAME=realtime", - "SECRET_KEY_BASE=" + utils.Config.Realtime.SecretKeyBase, - "ERL_AFLAGS=" + utils.ToRealtimeEnv(utils.Config.Realtime.IpVersion), - "DNS_NODES=''", - "RLIMIT_NOFILE=", - "SEED_SELF_HOST=true", - "RUN_JANITOR=true", - fmt.Sprintf("MAX_HEADER_LENGTH=%d", utils.Config.Realtime.MaxHeaderLength), - }, - ExposedPorts: nat.PortSet{"4000/tcp": {}}, - Healthcheck: &container.HealthConfig{ - // Podman splits command by spaces unless it's quoted, but curl header can't be quoted. - Test: []string{"CMD", "curl", "-sSfL", "--head", "-o", "/dev/null", - "-H", "Host:" + utils.Config.Realtime.TenantId, - "http://127.0.0.1:4000/api/ping", - }, - Interval: 10 * time.Second, - Timeout: 2 * time.Second, - Retries: 3, - }, - }, - container.HostConfig{ - RestartPolicy: container.RestartPolicy{Name: "always"}, - }, - network.NetworkingConfig{ - EndpointsConfig: map[string]*network.EndpointSettings{ - utils.NetId: { - Aliases: utils.RealtimeAliases, - }, - }, - }, - utils.RealtimeId, - ); err != nil { - return err - } - started = append(started, utils.RealtimeId) - } - // Start PostgREST. if utils.Config.Api.Enabled && !isContainerExcluded(utils.Config.Api.Image, excluded) { if _, err := utils.DockerStart( @@ -886,216 +621,6 @@ EOF started = append(started, utils.StorageId) } - // Start Storage ImgProxy. - if isStorageEnabled && isImgProxyEnabled { - if _, err := utils.DockerStart( - ctx, - container.Config{ - Image: utils.Config.Storage.ImgProxyImage, - Env: []string{ - "IMGPROXY_BIND=:5001", - "IMGPROXY_LOCAL_FILESYSTEM_ROOT=/", - "IMGPROXY_USE_ETAG=/", - "IMGPROXY_MAX_SRC_RESOLUTION=50", - "IMGPROXY_MAX_SRC_FILE_SIZE=25000000", - "IMGPROXY_MAX_ANIMATION_FRAMES=60", - "IMGPROXY_ENABLE_WEBP_DETECTION=true", - }, - Healthcheck: &container.HealthConfig{ - Test: []string{"CMD", "imgproxy", "health"}, - Interval: 10 * time.Second, - Timeout: 2 * time.Second, - Retries: 3, - }, - }, - container.HostConfig{ - VolumesFrom: []string{utils.StorageId}, - RestartPolicy: container.RestartPolicy{Name: "always"}, - }, - network.NetworkingConfig{ - EndpointsConfig: map[string]*network.EndpointSettings{ - utils.NetId: { - Aliases: utils.ImgProxyAliases, - }, - }, - }, - utils.ImgProxyId, - ); err != nil { - return err - } - started = append(started, utils.ImgProxyId) - } - - // Start all functions. - if utils.Config.EdgeRuntime.Enabled && !isContainerExcluded(utils.Config.EdgeRuntime.Image, excluded) { - dbUrl := fmt.Sprintf("postgresql://%s:%s@%s:%d/%s", dbConfig.User, dbConfig.Password, dbConfig.Host, dbConfig.Port, dbConfig.Database) - if err := serve.ServeFunctions(ctx, "", nil, "", dbUrl, serve.RuntimeOption{}, fsys); err != nil { - return err - } - started = append(started, utils.EdgeRuntimeId) - } - - // Start pg-meta. - if utils.Config.Studio.Enabled && !isContainerExcluded(utils.Config.Studio.PgmetaImage, excluded) { - if _, err := utils.DockerStart( - ctx, - container.Config{ - Image: utils.Config.Studio.PgmetaImage, - Env: []string{ - "PG_META_PORT=8080", - "PG_META_DB_HOST=" + dbConfig.Host, - "PG_META_DB_NAME=" + dbConfig.Database, - "PG_META_DB_USER=" + dbConfig.User, - fmt.Sprintf("PG_META_DB_PORT=%d", dbConfig.Port), - "PG_META_DB_PASSWORD=" + dbConfig.Password, - }, - Healthcheck: &container.HealthConfig{ - Test: []string{"CMD-SHELL", `node --eval="fetch('http://127.0.0.1:8080/health').then((r) => {if (!r.ok) throw new Error(r.status)})"`}, - Interval: 10 * time.Second, - Timeout: 2 * time.Second, - Retries: 3, - }, - }, - container.HostConfig{ - RestartPolicy: container.RestartPolicy{Name: "always"}, - }, - network.NetworkingConfig{ - EndpointsConfig: map[string]*network.EndpointSettings{ - utils.NetId: { - Aliases: utils.PgmetaAliases, - }, - }, - }, - utils.PgmetaId, - ); err != nil { - return err - } - started = append(started, utils.PgmetaId) - } - - // Start Studio. - if utils.Config.Studio.Enabled && !isContainerExcluded(utils.Config.Studio.Image, excluded) { - if _, err := utils.DockerStart( - ctx, - container.Config{ - Image: utils.Config.Studio.Image, - Env: []string{ - "STUDIO_PG_META_URL=http://" + utils.PgmetaId + ":8080", - "POSTGRES_PASSWORD=" + dbConfig.Password, - "SUPABASE_URL=http://" + utils.KongId + ":8000", - "SUPABASE_PUBLIC_URL=" + utils.Config.Studio.ApiUrl, - "AUTH_JWT_SECRET=" + utils.Config.Auth.JwtSecret, - "SUPABASE_ANON_KEY=" + utils.Config.Auth.AnonKey, - "SUPABASE_SERVICE_KEY=" + utils.Config.Auth.ServiceRoleKey, - "LOGFLARE_API_KEY=" + utils.Config.Analytics.ApiKey, - "OPENAI_API_KEY=" + utils.Config.Studio.OpenaiApiKey, - fmt.Sprintf("LOGFLARE_URL=http://%v:4000", utils.LogflareId), - fmt.Sprintf("NEXT_PUBLIC_ENABLE_LOGS=%v", utils.Config.Analytics.Enabled), - fmt.Sprintf("NEXT_ANALYTICS_BACKEND_PROVIDER=%v", utils.Config.Analytics.Backend), - // Ref: https://github.com/vercel/next.js/issues/51684#issuecomment-1612834913 - "HOSTNAME=0.0.0.0", - }, - Healthcheck: &container.HealthConfig{ - Test: []string{"CMD-SHELL", `node --eval="fetch('http://127.0.0.1:3000/api/platform/profile').then((r) => {if (!r.ok) throw new Error(r.status)})"`}, - Interval: 10 * time.Second, - Timeout: 2 * time.Second, - Retries: 3, - }, - }, - container.HostConfig{ - PortBindings: nat.PortMap{"3000/tcp": []nat.PortBinding{{HostPort: strconv.FormatUint(uint64(utils.Config.Studio.Port), 10)}}}, - RestartPolicy: container.RestartPolicy{Name: "always"}, - }, - network.NetworkingConfig{ - EndpointsConfig: map[string]*network.EndpointSettings{ - utils.NetId: { - Aliases: utils.StudioAliases, - }, - }, - }, - utils.StudioId, - ); err != nil { - return err - } - started = append(started, utils.StudioId) - } - - // Start pooler. - if utils.Config.Db.Pooler.Enabled && !isContainerExcluded(utils.Config.Db.Pooler.Image, excluded) { - portSession := uint16(5432) - portTransaction := uint16(6543) - dockerPort := portTransaction - if utils.Config.Db.Pooler.PoolMode == config.SessionMode { - dockerPort = portSession - } - // Create pooler tenant - var poolerTenantBuf bytes.Buffer - if err := poolerTenantTemplate.Option("missingkey=error").Execute(&poolerTenantBuf, poolerTenant{ - DbHost: dbConfig.Host, - DbPort: dbConfig.Port, - DbDatabase: dbConfig.Database, - DbPassword: dbConfig.Password, - ExternalId: utils.Config.Db.Pooler.TenantId, - ModeType: utils.Config.Db.Pooler.PoolMode, - DefaultMaxClients: utils.Config.Db.Pooler.MaxClientConn, - DefaultPoolSize: utils.Config.Db.Pooler.DefaultPoolSize, - }); err != nil { - return errors.Errorf("failed to exec template: %w", err) - } - if _, err := utils.DockerStart( - ctx, - container.Config{ - Image: utils.Config.Db.Pooler.Image, - Env: []string{ - "PORT=4000", - fmt.Sprintf("PROXY_PORT_SESSION=%d", portSession), - fmt.Sprintf("PROXY_PORT_TRANSACTION=%d", portTransaction), - fmt.Sprintf("DATABASE_URL=ecto://%s:%s@%s:%d/%s", dbConfig.User, dbConfig.Password, dbConfig.Host, dbConfig.Port, "_supabase"), - "CLUSTER_POSTGRES=true", - "SECRET_KEY_BASE=" + utils.Config.Db.Pooler.SecretKeyBase, - "VAULT_ENC_KEY=" + utils.Config.Db.Pooler.EncryptionKey, - "API_JWT_SECRET=" + utils.Config.Auth.JwtSecret, - "METRICS_JWT_SECRET=" + utils.Config.Auth.JwtSecret, - "REGION=local", - "RUN_JANITOR=true", - "ERL_AFLAGS=-proto_dist inet_tcp", - }, - Cmd: []string{ - "/bin/sh", "-c", - fmt.Sprintf("/app/bin/migrate && /app/bin/supavisor eval '%s' && /app/bin/server", poolerTenantBuf.String()), - }, - ExposedPorts: nat.PortSet{ - "4000/tcp": {}, - nat.Port(fmt.Sprintf("%d/tcp", portSession)): {}, - nat.Port(fmt.Sprintf("%d/tcp", portTransaction)): {}, - }, - Healthcheck: &container.HealthConfig{ - Test: []string{"CMD", "curl", "-sSfL", "--head", "-o", "/dev/null", "http://127.0.0.1:4000/api/health"}, - Interval: 10 * time.Second, - Timeout: 2 * time.Second, - Retries: 3, - }, - }, - container.HostConfig{ - PortBindings: nat.PortMap{nat.Port(fmt.Sprintf("%d/tcp", dockerPort)): []nat.PortBinding{{ - HostPort: strconv.FormatUint(uint64(utils.Config.Db.Pooler.Port), 10)}, - }}, - RestartPolicy: container.RestartPolicy{Name: "always"}, - }, - network.NetworkingConfig{ - EndpointsConfig: map[string]*network.EndpointSettings{ - utils.NetId: { - Aliases: utils.PoolerAliases, - }, - }, - }, - utils.PoolerId, - ); err != nil { - return err - } - started = append(started, utils.PoolerId) - } - p.Send(utils.StatusMsg("Waiting for health checks...")) if utils.NoBackupVolume && utils.SliceContains(started, utils.StorageId) { if err := start.WaitForHealthyService(ctx, serviceTimeout, utils.StorageId); err != nil {