docker-compose.local.yml
Rama main · réplica de lectura del repositorio original.
services:
control-plane-db:
image: postgres:16-alpine
environment:
POSTGRES_USER: butterbase
POSTGRES_PASSWORD: butterbase_dev
POSTGRES_DB: butterbase_control
ports:
- "5433:5432"
volumes:
- control-plane-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U butterbase -d butterbase_control"]
interval: 5s
timeout: 3s
retries: 5
networks:
- butterbase
data-plane-db:
image: pgvector/pgvector:pg16
environment:
POSTGRES_USER: butterbase
POSTGRES_PASSWORD: butterbase_dev
POSTGRES_DB: postgres
POSTGRES_HOST_AUTH_METHOD: md5
POSTGRES_INITDB_ARGS: "--auth-host=md5"
command: ["postgres", "-c", "wal_level=logical", "-c", "max_replication_slots=10", "-c", "max_wal_senders=10"]
ports:
- "5435:5432"
volumes:
- data-plane-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U butterbase -d postgres"]
interval: 5s
timeout: 3s
retries: 5
networks:
- butterbase
runtime-plane-db:
image: postgres:17
environment:
POSTGRES_USER: butterbase
POSTGRES_PASSWORD: butterbase_dev
POSTGRES_DB: butterbase_runtime_us
ports:
- "5437:5432"
volumes:
- runtime_plane_db_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U butterbase -d butterbase_runtime_us"]
interval: 5s
timeout: 3s
retries: 5
networks:
- butterbase
pgbouncer:
image: edoburu/pgbouncer:latest
ports:
- "6432:6432"
volumes:
- ./infra/pgbouncer/pgbouncer.ini:/etc/pgbouncer/pgbouncer.ini:ro
- ./infra/pgbouncer/userlist.txt:/etc/pgbouncer/userlist.txt:ro
depends_on:
data-plane-db:
condition: service_healthy
networks:
- butterbase
redis:
image: redis:7-alpine
ports:
- "6379:6379"
volumes:
- redis-data:/data
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
networks:
- butterbase
# Pinned to a community-edition release; 2026.03+ `:latest` images require a
# paid LOCALSTACK_AUTH_TOKEN. Self-hosters can override via the LOCALSTACK_IMAGE env.
localstack:
image: ${LOCALSTACK_IMAGE:-localstack/localstack:4.14.0}
ports:
- "4566:4566"
- "4571:4571"
environment:
- LOCALSTACK_AUTH_TOKEN=${LOCALSTACK_AUTH_TOKEN:-}
- SERVICES=s3,lambda
- DEBUG=1
- PERSISTENCE=1
- LAMBDA_EXECUTOR=docker
- DOCKER_HOST=unix:///var/run/docker.sock
volumes:
- "./localstack-init:/etc/localstack/init/ready.d"
- "/var/run/docker.sock:/var/run/docker.sock"
- localstack-data:/var/lib/localstack
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:4566/_localstack/health"]
interval: 10s
timeout: 3s
retries: 5
start_period: 10s
networks:
- butterbase
control-api:
build:
context: .
dockerfile: services/control-api/Dockerfile
ports:
- "4000:4000"
env_file:
- path: .env
required: false
environment:
# Override the Dockerfile's NODE_ENV=production so the prod-only env checks
# (BUILD_RUNNER_SHARED_SECRET, BUILD_RUNNER_URL, AUTH_ENCRYPTION_KEY...) skip.
NODE_ENV: development
CONTROL_DB_URL: "postgresql://butterbase:butterbase_dev@control-plane-db:5432/butterbase_control"
DATA_PLANE_DB_HOST: data-plane-db
DATA_PLANE_DB_PORT: "5432"
DATA_PLANE_DB_USER: butterbase
DATA_PLANE_DB_PASSWORD: butterbase_dev
PGBOUNCER_HOST: pgbouncer
PGBOUNCER_PORT: "6432"
CONTROL_API_PORT: "4000"
AUTH_ENABLED: "false"
AUTH_ENCRYPTION_KEY: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
BUTTERBASE_REGIONS: us-east-1
BUTTERBASE_REGION: us-east-1
BUTTERBASE_PLATFORM_REGION: us-east-1
BUTTERBASE_INTERNAL_SECRET: dev-internal-secret-change-me
BUTTERBASE_LEASE_SIZE_USD: "1.00"
BUTTERBASE_LEASE_REFILL_THRESHOLD_USD: "0.20"
BUTTERBASE_LEASE_TTL_SECONDS: "300"
NEON_RUNTIME_PROJECT_ID_US_EAST_1: "postgresql://butterbase:butterbase_dev@runtime-plane-db:5432/butterbase_runtime_us"
NEON_DATA_PROJECT_ID_US_EAST_1: local-dev-data-project
NEON_DATA_PROJECT_ID: local-dev-data-project
NEON_PLATFORM_PRIMARY_URL: "postgresql://butterbase:butterbase_dev@control-plane-db:5432/butterbase_control"
CONTROL_PLANE_URL_PLATFORM_REGION: "http://control-api:4000"
DEV_OWNER_ID: "11111111-1111-1111-1111-111111111111"
DEV_ADMIN_USER_ID: "22222222-2222-2222-2222-222222222222"
NODE_OPTIONS: "--dns-result-order=ipv4first"
S3_BUCKET_NAME: butterbase-app-storage
AWS_REGION: us-east-1
S3_ENDPOINT: http://localstack:4566
S3_PUBLIC_ENDPOINT: http://localhost:4566
S3_FORCE_PATH_STYLE: "true"
AWS_ACCESS_KEY_ID: test
AWS_SECRET_ACCESS_KEY: test
REDIS_URL: redis://redis:6379
# Per-region KV Redis (keys match BUTTERBASE_REGIONS long-form names)
KV_REDIS_URL_US_EAST_1: redis://redis:6379
REALTIME_MAX_LISTEN_CONNECTIONS: "100"
depends_on:
control-plane-db:
condition: service_healthy
data-plane-db:
condition: service_healthy
runtime-plane-db:
condition: service_healthy
redis:
condition: service_healthy
localstack:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:4000/health/ready"]
interval: 10s
timeout: 3s
retries: 3
start_period: 10s
networks:
- butterbase
docs:
build:
context: .
dockerfile: services/docs/Dockerfile
ports:
- "4321:80"
networks:
- butterbase
traefik:
image: traefik:v3.4
ports:
- "80:80"
- "8080:8080"
volumes:
- ./infra/traefik/traefik.yml:/etc/traefik/traefik.yml:ro
- ./infra/traefik/dynamic.yml:/etc/traefik/dynamic.yml:ro
networks:
- butterbase
deno-runtime:
image: denoland/deno:alpine-2.0.6
working_dir: /app
depends_on:
pgbouncer:
condition: service_started
control-plane-db:
condition: service_healthy
runtime-plane-db:
condition: service_healthy
redis:
condition: service_healthy
ports:
- "7133:7133"
environment:
- PORT=7133
- DENO_DIR=/deno-dir
- PGBOUNCER_HOST=pgbouncer
- PGBOUNCER_PORT=6432
- PGBOUNCER_USER=butterbase
- PGBOUNCER_PASSWORD=butterbase_dev
- BUTTERBASE_REGION=us-east-1
- NEON_RUNTIME_PROJECT_ID_US_EAST_1=postgresql://butterbase:butterbase_dev@runtime-plane-db:5432/butterbase_runtime_us
- CONTROL_PLANE_URL=postgresql://butterbase:butterbase_dev@control-plane-db:5432/butterbase_control
- AUTH_ENCRYPTION_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
- WORKER_TIMEOUT_MS=30000
- MAX_CONCURRENT_WORKERS=100
- REDIS_URL=redis://redis:6379
- DO_INVOKER_URL=http://do-invoker:8787
- DO_INVOKER_TOKEN=local-dev-do-invoker-token
volumes:
- ./services/deno-runtime:/app:ro
- deno_cache:/deno-dir
command:
- sh
- -c
- |
rm -rf /deno-dir/gen &&
deno cache server.ts &&
deno run \
--allow-net \
--allow-env \
--allow-read=/app,/deno-dir \
--unstable-worker-options \
server.ts
networks:
- butterbase
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:7133/health"]
interval: 10s
timeout: 3s
retries: 3
start_period: 10s
# Local do-invoker shim so function↔DO round-trips work end-to-end.
# Note: wrangler dev's local mode does not simulate WfP dispatch namespaces,
# so the shim will 500 when attempting to dispatch. Full E2E requires
# deploying do-invoker + a DO to a scratch CF account.
do-invoker:
image: node:20-alpine
working_dir: /app
volumes:
- ./services/do-invoker:/app:ro
ports:
- "8787:8787"
environment:
- DO_INVOKER_TOKEN=local-dev-do-invoker-token
command: sh -c "npm install --no-audit --no-fund && npx wrangler dev --local --ip 0.0.0.0 --port 8787"
networks:
- butterbase
volumes:
control-plane-data:
data-plane-data:
runtime_plane_db_data:
deno_cache:
localstack-data:
redis-data:
networks:
butterbase:
driver: bridge