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
|
||||
# =============================================================================
|
||||
# Production compose - Nginx serving built React app
|
||||
# For Cloudflare tunnel: docker compose -f compose.yml -f cloudflared.compose.yml up
|
||||
# Production compose: nginx → canary backend → postgres + redis
|
||||
# Cloudflare tunnel overlay:
|
||||
# docker compose -f compose.yml -f cloudflared.compose.yml up -d
|
||||
# =============================================================================
|
||||
|
||||
name: ${APP_NAME:-canary-token-generator}
|
||||
|
|
@ -16,11 +17,15 @@ services:
|
|||
args:
|
||||
- VITE_API_URL=${VITE_API_URL:-/api}
|
||||
- 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
|
||||
ports:
|
||||
- "${NGINX_HOST_PORT:-22784}:80"
|
||||
networks:
|
||||
- app
|
||||
depends_on:
|
||||
canary:
|
||||
condition: service_healthy
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
|
|
@ -31,6 +36,96 @@ services:
|
|||
memory: 64M
|
||||
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:
|
||||
app:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
pgdata:
|
||||
redisdata:
|
||||
geolite:
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
# =============================================================================
|
||||
# AngelaMos | 2026
|
||||
# ©AngelaMos | 2026
|
||||
# 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
|
||||
# =============================================================================
|
||||
|
||||
|
|
@ -20,6 +20,8 @@ services:
|
|||
depends_on:
|
||||
frontend:
|
||||
condition: service_started
|
||||
canary:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- app
|
||||
restart: unless-stopped
|
||||
|
|
@ -37,6 +39,96 @@ services:
|
|||
environment:
|
||||
- VITE_API_URL=${VITE_API_URL:-/api}
|
||||
- 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:
|
||||
- app
|
||||
restart: unless-stopped
|
||||
|
|
@ -47,3 +139,7 @@ networks:
|
|||
|
||||
volumes:
|
||||
frontend_modules:
|
||||
pgdata_dev:
|
||||
redisdata_dev:
|
||||
canary_gocache:
|
||||
canary_gomodcache:
|
||||
|
|
|
|||
Loading…
Reference in New Issue