feat(ci): validar imagen nueva en E2E antes del deploy a dev
El stage E2E corría contra A76_URL (versión viva en dev), así que detectaba regresiones un build tarde: el código roto ya estaba desplegado cuando el siguiente pipeline lo encontraba. Ahora E2E levanta un stack efímero con la imagen del backend recién pusheada a Harbor y una imagen del frontend buildeada localmente con VITE_API_URL=http://localhost:8000/api/ (la imagen de prod tiene la URL de dev bakeada en el bundle). Si E2E falla, el deploy no ocurre — el guardrail actúa sobre lo que se va a desplegar. Cambios: - docker-compose.e2e.yml (nuevo): postgres + minio + valkey + backend + frontend efímeros, sin volúmenes persistidos, image tags vía env vars. - Jenkinsfile: stage E2E reescrito. Build temp frontend en paralelo con startup DB+alembic; preparación Playwright en paralelo con health wait de backend/frontend. --cache-from de la imagen prod para reusar layer de pnpm install. Cleanup garantizado vía trap EXIT. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
157
docker-compose.e2e.yml
Normal file
157
docker-compose.e2e.yml
Normal file
@@ -0,0 +1,157 @@
|
||||
# Stack efímero para pruebas E2E (Playwright) en CI.
|
||||
# Levantado por Jenkinsfile (stage "E2E (Playwright)") ANTES del deploy a dev,
|
||||
# para validar la imagen recién buildeada contra una DB limpia y servicios aislados.
|
||||
#
|
||||
# Diferencias clave vs docker-compose.prod.yml:
|
||||
# - Sin volúmenes persistidos (todo se descarta en `down -v`).
|
||||
# - Sin `container_name` ni `restart` (efímero, COMPOSE_PROJECT_NAME aísla los nombres).
|
||||
# - Sin `celery_worker` / `celery_beat` (no se ejercitan en los specs actuales).
|
||||
# - Imágenes vía env vars: la del frontend se rebuildea localmente con
|
||||
# VITE_API_URL=http://localhost:8000/api/ (la prod tiene la URL de dev bakeada).
|
||||
# - Puertos fijos: frontend 5173 / backend 8000 (URIs ya registradas en Workspace).
|
||||
#
|
||||
# Variables requeridas en el entorno al invocar docker compose:
|
||||
# E2E_BACKEND_IMAGE — imagen del backend recién pusheada a Harbor
|
||||
# E2E_FRONTEND_IMAGE — imagen temporal del frontend con VITE_API_URL=localhost
|
||||
|
||||
services:
|
||||
postgres-a76:
|
||||
image: postgres:18-alpine
|
||||
environment:
|
||||
POSTGRES_DB: anexo76_core
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_INITDB_ARGS: "--encoding=UTF8"
|
||||
networks:
|
||||
- e2e-net
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -U postgres -d anexo76_core || exit 1"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 10
|
||||
start_period: 20s
|
||||
tmpfs:
|
||||
- /var/lib/postgresql/data
|
||||
|
||||
minio:
|
||||
image: minio/minio:RELEASE.2025-09-07T16-13-09Z
|
||||
command: server /data --console-address ":9001"
|
||||
environment:
|
||||
MINIO_ROOT_USER: minioadmin
|
||||
MINIO_ROOT_PASSWORD: minioadmin
|
||||
networks:
|
||||
- e2e-net
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://127.0.0.1:9000/minio/health/live || exit 1"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 15s
|
||||
tmpfs:
|
||||
- /data
|
||||
|
||||
valkey:
|
||||
image: valkey/valkey:7.2
|
||||
networks:
|
||||
- e2e-net
|
||||
|
||||
backend:
|
||||
image: ${E2E_BACKEND_IMAGE}
|
||||
environment:
|
||||
- DEBUG=False
|
||||
- ENVIRONMENT=e2e
|
||||
- PYTHONUNBUFFERED=1
|
||||
- PYTHONDONTWRITEBYTECODE=1
|
||||
- CORE_DB_HOST=postgres-a76
|
||||
- CORE_DB_PORT=5432
|
||||
- CORE_DB_NAME=anexo76_core
|
||||
- CORE_DB_USER=postgres
|
||||
- CORE_DB_PASSWORD=postgres
|
||||
# Keycloak — apunta a Workspace real; el cliente anexo76-frontend ya
|
||||
# tiene http://localhost:5173/auth/callback como redirect URI permitida.
|
||||
- KEYCLOAK_SERVER_URL=https://workspace.aduanasoft.com/kcauth
|
||||
- KEYCLOAK_REALM=master
|
||||
- KEYCLOAK_CLIENT_ID=anexo76-frontend
|
||||
- KEYCLOAK_CLIENT_SECRET=${KEYCLOAK_CLIENT_SECRET:-}
|
||||
- CORS_ORIGINS=http://localhost:5173
|
||||
- VALKEY_URL=redis://valkey:6379/0
|
||||
- HUB_URL=https://workspace.aduanasoft.com
|
||||
- APP_PUBLIC_URL=http://localhost:5173
|
||||
- CSV_IMPORT_STORAGE=minio
|
||||
- S3_ENDPOINT_URL=http://minio:9000
|
||||
- S3_ACCESS_KEY=minioadmin
|
||||
- S3_SECRET_KEY=minioadmin
|
||||
- S3_BUCKET=anexo76
|
||||
- S3_REGION=us-east-1
|
||||
- S3_USE_SSL=false
|
||||
- S3_FILE_STORAGE=true
|
||||
ports:
|
||||
- "8000:8000"
|
||||
depends_on:
|
||||
postgres-a76:
|
||||
condition: service_healthy
|
||||
minio:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- e2e-net
|
||||
# Replica el comando de prod (gunicorn) para que el test ejerza el mismo runtime
|
||||
# que se desplegará. El CMD del Dockerfile usa uvicorn --reload (modo dev).
|
||||
command:
|
||||
- gunicorn
|
||||
- main:app
|
||||
- -k
|
||||
- uvicorn.workers.UvicornWorker
|
||||
- -w
|
||||
- "1"
|
||||
- -b
|
||||
- 0.0.0.0:8000
|
||||
- --log-level
|
||||
- info
|
||||
- --forwarded-allow-ips
|
||||
- "*"
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "curl -f http://localhost:8000/api/health || exit 1"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 60s
|
||||
|
||||
frontend:
|
||||
image: ${E2E_FRONTEND_IMAGE}
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
# VITE_API_URL ya está bakeada en E2E_FRONTEND_IMAGE; este valor solo sirve
|
||||
# para fallback server-side en frontend/src/lib/server/api.ts.
|
||||
- VITE_API_URL=http://localhost:8000/api/
|
||||
- INTERNAL_API_URL=http://backend:8000/api/
|
||||
- INTERNAL_HUB_URL=https://workspace.aduanasoft.com
|
||||
- HUB_URL=https://workspace.aduanasoft.com
|
||||
- VITE_HUB_URL=https://workspace.aduanasoft.com
|
||||
- VITE_KEYCLOAK_URL=https://workspace.aduanasoft.com/kcauth
|
||||
- VITE_KEYCLOAK_REALM=master
|
||||
- VITE_KEYCLOAK_CLIENT_ID=anexo76-frontend
|
||||
- KEYCLOAK_URL=https://workspace.aduanasoft.com/kcauth
|
||||
- KEYCLOAK_REALM=master
|
||||
- KEYCLOAK_CLIENT_ID=anexo76-frontend
|
||||
- KEYCLOAK_CLIENT_SECRET=${KEYCLOAK_CLIENT_SECRET:-}
|
||||
# ORIGIN controla url.origin y el flag secure de cookies — debe coincidir con la URL
|
||||
# registrada en Workspace para que el callback de Keycloak resuelva correctamente.
|
||||
- ORIGIN=http://localhost:5173
|
||||
- SITE_URL=http://localhost:5173
|
||||
ports:
|
||||
- "5173:5173"
|
||||
depends_on:
|
||||
backend:
|
||||
condition: service_healthy
|
||||
networks:
|
||||
- e2e-net
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "wget --no-verbose --tries=1 --spider http://localhost:5173/ || exit 1"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 30s
|
||||
|
||||
networks:
|
||||
e2e-net:
|
||||
driver: bridge
|
||||
Reference in New Issue
Block a user