From 8b70bfbba934f784ed92b620f925c8b487b3446b Mon Sep 17 00:00:00 2001 From: CarterPerez-dev Date: Sun, 10 May 2026 05:23:55 -0400 Subject: [PATCH] chore(canary): merge backend compose into project root MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../backend/compose.yml | 59 ---------- .../backend/dev.compose.yml | 45 -------- .../canary-token-generator/compose.yml | 101 +++++++++++++++++- .../canary-token-generator/dev.compose.yml | 100 ++++++++++++++++- 4 files changed, 196 insertions(+), 109 deletions(-) delete mode 100644 PROJECTS/beginner/canary-token-generator/backend/compose.yml delete mode 100644 PROJECTS/beginner/canary-token-generator/backend/dev.compose.yml diff --git a/PROJECTS/beginner/canary-token-generator/backend/compose.yml b/PROJECTS/beginner/canary-token-generator/backend/compose.yml deleted file mode 100644 index 66d66a22..00000000 --- a/PROJECTS/beginner/canary-token-generator/backend/compose.yml +++ /dev/null @@ -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: diff --git a/PROJECTS/beginner/canary-token-generator/backend/dev.compose.yml b/PROJECTS/beginner/canary-token-generator/backend/dev.compose.yml deleted file mode 100644 index 26bfa456..00000000 --- a/PROJECTS/beginner/canary-token-generator/backend/dev.compose.yml +++ /dev/null @@ -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: diff --git a/PROJECTS/beginner/canary-token-generator/compose.yml b/PROJECTS/beginner/canary-token-generator/compose.yml index 09ea14d8..1e0ccfc8 100644 --- a/PROJECTS/beginner/canary-token-generator/compose.yml +++ b/PROJECTS/beginner/canary-token-generator/compose.yml @@ -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: diff --git a/PROJECTS/beginner/canary-token-generator/dev.compose.yml b/PROJECTS/beginner/canary-token-generator/dev.compose.yml index 6238f4bc..e1fdf07b 100644 --- a/PROJECTS/beginner/canary-token-generator/dev.compose.yml +++ b/PROJECTS/beginner/canary-token-generator/dev.compose.yml @@ -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: