This commit is contained in:
parent
e9b25a11e3
commit
bda87f82a8
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Reference in New Issue