chore(canary): merge backend compose into project root
Single project-root compose.yml + dev.compose.yml manage all services.
Production stack (compose.yml):
- nginx public ingress on \${NGINX_HOST_PORT:-22784}:80
- canary Go backend, NO host port (reachable only via nginx)
distroless/static:nonroot Dockerfile
healthcheck → /healthz, depends on postgres + redis
- postgres postgres:18-alpine, no host port, named volume pgdata
- redis redis:7-alpine, no host port, named volume redisdata
- (geolite vol) read-only mount /data for GeoLite2-City.mmdb
Dev stack (dev.compose.yml):
- nginx dev ingress on \${NGINX_HOST_PORT:-58495}:80
- frontend Vite HMR on \${FRONTEND_HOST_PORT:-15723}:5173
- canary Air hot-reload (canary.dev Dockerfile, bind-mounts ./backend)
OTel exports to jaeger:4317
- postgres host port \${POSTGRES_DEV_PORT:-5447}:5432 for psql access
- redis host port \${REDIS_DEV_PORT:-6022}:6379 for redis-cli access
- jaeger UI 16686, OTLP gRPC 4317, OTLP HTTP 4318
- volumes gocache + gomodcache speed up rebuilds
All randomized host ports preserved exactly:
22784 (prod nginx), 58495 (dev nginx), 15723 (vite), 5447 (pg dev),
6022 (redis dev), 16686/4317/4318 (jaeger).
Backend has no host port in production: nginx is the single entrypoint.
Cloudflare Tunnel sidecar terminates at nginx:80 via cloudflared.compose.yml.
backend/compose.yml + backend/dev.compose.yml deleted (merged here).
Validation:
- docker compose -f compose.yml config — OK
- docker compose -f dev.compose.yml config — OK
- docker compose -f compose.yml -f cloudflared.compose.yml config — OK
This commit is contained in:
parent
7fa2861e7a
commit
8b70bfbba9
|
|
@ -1,59 +0,0 @@
|
||||||
# AngelaMos | 2026
|
|
||||||
# compose.yml - Production compose
|
|
||||||
|
|
||||||
services:
|
|
||||||
api:
|
|
||||||
image: go-backend:latest
|
|
||||||
ports:
|
|
||||||
- "8085:8080"
|
|
||||||
environment:
|
|
||||||
- ENVIRONMENT=production
|
|
||||||
- DATABASE_URL=postgres://postgres:postgres@postgres:5432/app?sslmode=disable
|
|
||||||
- REDIS_URL=redis://redis:6379/0
|
|
||||||
- OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4317
|
|
||||||
depends_on:
|
|
||||||
postgres:
|
|
||||||
condition: service_healthy
|
|
||||||
redis:
|
|
||||||
condition: service_healthy
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "wget", "-qO-", "http://localhost:8080/healthz"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 3
|
|
||||||
start_period: 10s
|
|
||||||
deploy:
|
|
||||||
resources:
|
|
||||||
limits:
|
|
||||||
memory: 256M
|
|
||||||
reservations:
|
|
||||||
memory: 128M
|
|
||||||
|
|
||||||
postgres:
|
|
||||||
image: postgres:18-alpine
|
|
||||||
environment:
|
|
||||||
POSTGRES_USER: postgres
|
|
||||||
POSTGRES_PASSWORD: postgres
|
|
||||||
POSTGRES_DB: app
|
|
||||||
volumes:
|
|
||||||
- pgdata:/var/lib/postgresql/data
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
|
||||||
interval: 5s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
|
|
||||||
redis:
|
|
||||||
image: redis:7-alpine
|
|
||||||
command: redis-server --appendonly yes
|
|
||||||
volumes:
|
|
||||||
- redisdata:/data
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "redis-cli", "ping"]
|
|
||||||
interval: 5s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
pgdata:
|
|
||||||
redisdata:
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
# AngelaMos | 2026
|
|
||||||
# dev.compose.yml - Development compose
|
|
||||||
|
|
||||||
services:
|
|
||||||
postgres:
|
|
||||||
image: postgres:18-alpine
|
|
||||||
ports:
|
|
||||||
- "5447:5432"
|
|
||||||
environment:
|
|
||||||
POSTGRES_USER: postgres
|
|
||||||
POSTGRES_PASSWORD: postgres
|
|
||||||
POSTGRES_DB: app
|
|
||||||
volumes:
|
|
||||||
- pgdata_dev:/var/lib/postgresql/data
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
|
||||||
interval: 5s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
|
|
||||||
redis:
|
|
||||||
image: redis:7-alpine
|
|
||||||
ports:
|
|
||||||
- "6022:6379"
|
|
||||||
command: redis-server --appendonly yes
|
|
||||||
volumes:
|
|
||||||
- redisdata_dev:/data
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "redis-cli", "ping"]
|
|
||||||
interval: 5s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
|
|
||||||
jaeger:
|
|
||||||
image: jaegertracing/all-in-one:1.54
|
|
||||||
ports:
|
|
||||||
- "16686:16686"
|
|
||||||
- "4317:4317"
|
|
||||||
- "4318:4318"
|
|
||||||
environment:
|
|
||||||
COLLECTOR_OTLP_ENABLED: "true"
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
pgdata_dev:
|
|
||||||
redisdata_dev:
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# AngelaMos | 2026
|
# ©AngelaMos | 2026
|
||||||
# compose.yml
|
# compose.yml
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Production compose - Nginx serving built React app
|
# Production compose: nginx → canary backend → postgres + redis
|
||||||
# For Cloudflare tunnel: docker compose -f compose.yml -f cloudflared.compose.yml up
|
# Cloudflare tunnel overlay:
|
||||||
|
# docker compose -f compose.yml -f cloudflared.compose.yml up -d
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
name: ${APP_NAME:-canary-token-generator}
|
name: ${APP_NAME:-canary-token-generator}
|
||||||
|
|
@ -16,11 +17,15 @@ services:
|
||||||
args:
|
args:
|
||||||
- VITE_API_URL=${VITE_API_URL:-/api}
|
- VITE_API_URL=${VITE_API_URL:-/api}
|
||||||
- VITE_APP_TITLE=${VITE_APP_TITLE:-Canary Token Generator}
|
- VITE_APP_TITLE=${VITE_APP_TITLE:-Canary Token Generator}
|
||||||
|
- VITE_TURNSTILE_SITE_KEY=${VITE_TURNSTILE_SITE_KEY:-}
|
||||||
container_name: ${APP_NAME:-canary-token-generator}-nginx
|
container_name: ${APP_NAME:-canary-token-generator}-nginx
|
||||||
ports:
|
ports:
|
||||||
- "${NGINX_HOST_PORT:-22784}:80"
|
- "${NGINX_HOST_PORT:-22784}:80"
|
||||||
networks:
|
networks:
|
||||||
- app
|
- app
|
||||||
|
depends_on:
|
||||||
|
canary:
|
||||||
|
condition: service_healthy
|
||||||
deploy:
|
deploy:
|
||||||
resources:
|
resources:
|
||||||
limits:
|
limits:
|
||||||
|
|
@ -31,6 +36,96 @@ services:
|
||||||
memory: 64M
|
memory: 64M
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
|
canary:
|
||||||
|
build:
|
||||||
|
context: ./backend
|
||||||
|
dockerfile: ../infra/docker/canary.prod
|
||||||
|
container_name: ${APP_NAME:-canary-token-generator}-canary
|
||||||
|
environment:
|
||||||
|
- ENVIRONMENT=production
|
||||||
|
- DATABASE_URL=postgres://canary:${POSTGRES_PASSWORD}@postgres:5432/canary?sslmode=disable
|
||||||
|
- REDIS_URL=redis://redis:6379/0
|
||||||
|
- PUBLIC_BASE_URL=${PUBLIC_BASE_URL}
|
||||||
|
- TURNSTILE_SECRET=${TURNSTILE_SECRET}
|
||||||
|
- OPERATOR_TOKEN=${OPERATOR_TOKEN}
|
||||||
|
- GEOLITE_PATH=/data/GeoLite2-City.mmdb
|
||||||
|
- WEBHOOK_HMAC_SECRET=${WEBHOOK_HMAC_SECRET:-}
|
||||||
|
- MYSQL_FAKE_ENABLED=${MYSQL_FAKE_ENABLED:-false}
|
||||||
|
- LOG_LEVEL=${LOG_LEVEL:-info}
|
||||||
|
- LOG_FORMAT=${LOG_FORMAT:-json}
|
||||||
|
- OTEL_ENABLED=${OTEL_ENABLED:-false}
|
||||||
|
- OTEL_EXPORTER_OTLP_ENDPOINT=${OTEL_EXPORTER_OTLP_ENDPOINT:-}
|
||||||
|
volumes:
|
||||||
|
- geolite:/data:ro
|
||||||
|
networks:
|
||||||
|
- app
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "-qO-", "http://localhost:8080/healthz"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 3
|
||||||
|
start_period: 15s
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
cpus: '1.0'
|
||||||
|
memory: 256M
|
||||||
|
reservations:
|
||||||
|
cpus: '0.25'
|
||||||
|
memory: 64M
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: postgres:18-alpine
|
||||||
|
container_name: ${APP_NAME:-canary-token-generator}-postgres
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: canary
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
||||||
|
POSTGRES_DB: canary
|
||||||
|
volumes:
|
||||||
|
- pgdata:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- app
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U canary -d canary"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 512M
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
container_name: ${APP_NAME:-canary-token-generator}-redis
|
||||||
|
command: redis-server --appendonly yes
|
||||||
|
volumes:
|
||||||
|
- redisdata:/data
|
||||||
|
networks:
|
||||||
|
- app
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
deploy:
|
||||||
|
resources:
|
||||||
|
limits:
|
||||||
|
memory: 128M
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
app:
|
app:
|
||||||
driver: bridge
|
driver: bridge
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
pgdata:
|
||||||
|
redisdata:
|
||||||
|
geolite:
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# AngelaMos | 2026
|
# ©AngelaMos | 2026
|
||||||
# dev.compose.yml
|
# dev.compose.yml
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Development compose - Nginx + Vite dev server with HMR
|
# Development compose: nginx → vite (HMR) + canary (Air hot-reload) + Postgres + Redis + Jaeger
|
||||||
# Uses .env.development
|
# Uses .env.development
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|
||||||
|
|
@ -20,6 +20,8 @@ services:
|
||||||
depends_on:
|
depends_on:
|
||||||
frontend:
|
frontend:
|
||||||
condition: service_started
|
condition: service_started
|
||||||
|
canary:
|
||||||
|
condition: service_healthy
|
||||||
networks:
|
networks:
|
||||||
- app
|
- app
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
@ -37,6 +39,96 @@ services:
|
||||||
environment:
|
environment:
|
||||||
- VITE_API_URL=${VITE_API_URL:-/api}
|
- VITE_API_URL=${VITE_API_URL:-/api}
|
||||||
- VITE_APP_TITLE=${VITE_APP_TITLE:-Canary Token Generator}
|
- VITE_APP_TITLE=${VITE_APP_TITLE:-Canary Token Generator}
|
||||||
|
- VITE_TURNSTILE_SITE_KEY=${VITE_TURNSTILE_SITE_KEY:-}
|
||||||
|
networks:
|
||||||
|
- app
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
canary:
|
||||||
|
build:
|
||||||
|
context: ./backend
|
||||||
|
dockerfile: ../infra/docker/canary.dev
|
||||||
|
container_name: ${APP_NAME:-canary-token-generator}-canary-dev
|
||||||
|
volumes:
|
||||||
|
- ./backend:/app
|
||||||
|
- canary_gocache:/root/.cache/go-build
|
||||||
|
- canary_gomodcache:/go/pkg/mod
|
||||||
|
environment:
|
||||||
|
- ENVIRONMENT=development
|
||||||
|
- DATABASE_URL=postgres://canary:canary@postgres:5432/canary?sslmode=disable
|
||||||
|
- REDIS_URL=redis://redis:6379/0
|
||||||
|
- PUBLIC_BASE_URL=${PUBLIC_BASE_URL:-http://localhost:58495}
|
||||||
|
- TURNSTILE_SECRET=${TURNSTILE_SECRET:-}
|
||||||
|
- OPERATOR_TOKEN=${OPERATOR_TOKEN:-dev-operator-token}
|
||||||
|
- GEOLITE_PATH=${GEOLITE_PATH:-/app/testdata/GeoLite2-City.mmdb}
|
||||||
|
- WEBHOOK_HMAC_SECRET=${WEBHOOK_HMAC_SECRET:-}
|
||||||
|
- MYSQL_FAKE_ENABLED=${MYSQL_FAKE_ENABLED:-false}
|
||||||
|
- LOG_LEVEL=debug
|
||||||
|
- LOG_FORMAT=text
|
||||||
|
- OTEL_ENABLED=${OTEL_ENABLED:-true}
|
||||||
|
- OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4317
|
||||||
|
- OTEL_INSECURE=true
|
||||||
|
networks:
|
||||||
|
- app
|
||||||
|
depends_on:
|
||||||
|
postgres:
|
||||||
|
condition: service_healthy
|
||||||
|
redis:
|
||||||
|
condition: service_healthy
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "-qO-", "http://localhost:8080/healthz"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 30s
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
postgres:
|
||||||
|
image: postgres:18-alpine
|
||||||
|
container_name: ${APP_NAME:-canary-token-generator}-postgres-dev
|
||||||
|
ports:
|
||||||
|
- "${POSTGRES_DEV_PORT:-5447}:5432"
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: canary
|
||||||
|
POSTGRES_PASSWORD: canary
|
||||||
|
POSTGRES_DB: canary
|
||||||
|
volumes:
|
||||||
|
- pgdata_dev:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- app
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U canary -d canary"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:7-alpine
|
||||||
|
container_name: ${APP_NAME:-canary-token-generator}-redis-dev
|
||||||
|
ports:
|
||||||
|
- "${REDIS_DEV_PORT:-6022}:6379"
|
||||||
|
command: redis-server --appendonly yes
|
||||||
|
volumes:
|
||||||
|
- redisdata_dev:/data
|
||||||
|
networks:
|
||||||
|
- app
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "redis-cli", "ping"]
|
||||||
|
interval: 5s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
jaeger:
|
||||||
|
image: jaegertracing/all-in-one:1.54
|
||||||
|
container_name: ${APP_NAME:-canary-token-generator}-jaeger-dev
|
||||||
|
ports:
|
||||||
|
- "${JAEGER_UI_PORT:-16686}:16686"
|
||||||
|
- "${JAEGER_OTLP_GRPC_PORT:-4317}:4317"
|
||||||
|
- "${JAEGER_OTLP_HTTP_PORT:-4318}:4318"
|
||||||
|
environment:
|
||||||
|
COLLECTOR_OTLP_ENABLED: "true"
|
||||||
networks:
|
networks:
|
||||||
- app
|
- app
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
@ -47,3 +139,7 @@ networks:
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
frontend_modules:
|
frontend_modules:
|
||||||
|
pgdata_dev:
|
||||||
|
redisdata_dev:
|
||||||
|
canary_gocache:
|
||||||
|
canary_gomodcache:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue