Repository navigation
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
205 lines (195 loc) · 8.05 KB
/
Copy pathdocker-compose.yml
File metadata and controls
205 lines (195 loc) · 8.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# QueueLab con Docker Compose: infraestructura (PostgreSQL, RabbitMQ y Redis) y aplicación (API, worker y dashboard).
# Los valores por defecto son SOLO para desarrollo local; sobrescríbalos con un
# fichero .env (ver .env.example). Los puertos solo se publican en 127.0.0.1.
# PostgreSQL usa el puerto 5434 del host para no chocar con otras instancias locales (5432/5433).
name: queuelab
services:
postgres:
image: postgres:18-alpine
environment:
POSTGRES_DB: ${POSTGRES_DB:-queuelab}
POSTGRES_USER: ${POSTGRES_USER:-queuelab}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-queuelab}
ports:
- "127.0.0.1:${POSTGRES_PORT:-5434}:5432"
volumes:
- postgres-data:/var/lib/postgresql
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 5s
timeout: 3s
retries: 10
restart: unless-stopped
rabbitmq:
image: rabbitmq:4-management-alpine
environment:
RABBITMQ_DEFAULT_USER: ${RABBITMQ_USER:-queuelab}
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD:-queuelab}
ports:
- "127.0.0.1:${RABBITMQ_PORT:-5672}:5672"
- "127.0.0.1:${RABBITMQ_MANAGEMENT_PORT:-15672}:15672"
volumes:
- rabbitmq-data:/var/lib/rabbitmq
healthcheck:
test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"]
interval: 10s
timeout: 5s
retries: 10
restart: unless-stopped
# Solo guarda los contadores del límite de envíos (claves con expiración): no hay nada que conservar, así que
# no persiste a disco y un reinicio solo reinicia las cuotas.
redis:
image: redis:7-alpine
command: ["redis-server", "--save", "", "--appendonly", "no"]
ports:
- "127.0.0.1:${REDIS_PORT:-6379}:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 10
restart: unless-stopped
# --- Aplicación: `docker compose up -d --wait` levanta todo el flujo (API, worker y dashboard) ---
# Las imágenes se construyen desde el código (la primera vez tarda unos minutos: Maven y npm). La configuración
# llega por variables de entorno; los servicios hablan entre sí por nombre dentro de la red `queuelab` (ver `networks` al final).
# Para desarrollar con la API/worker/dashboard en el host, levante solo la infraestructura:
# docker compose up -d --wait postgres rabbitmq redis
# Ver docs/compose-stack.md.
api:
build:
context: ./backend
dockerfile: api/Dockerfile
image: queuelab-api:${QUEUELAB_TAG:-latest}
environment:
QUEUELAB_DB_URL: jdbc:postgresql://postgres:5432/${POSTGRES_DB:-queuelab}
QUEUELAB_DB_USER: ${POSTGRES_USER:-queuelab}
QUEUELAB_DB_PASSWORD: ${POSTGRES_PASSWORD:-queuelab}
QUEUELAB_RABBITMQ_HOST: rabbitmq
QUEUELAB_RABBITMQ_USER: ${RABBITMQ_USER:-queuelab}
QUEUELAB_RABBITMQ_PASSWORD: ${RABBITMQ_PASSWORD:-queuelab}
QUEUELAB_REDIS_HOST: redis
# El navegador llama a la API desde el origen del dashboard (localhost o 127.0.0.1, según cómo se abra).
QUEUELAB_CORS_ALLOWED_ORIGINS: http://localhost:${DASHBOARD_PORT:-3000},http://127.0.0.1:${DASHBOARD_PORT:-3000}
ports:
- "127.0.0.1:${API_PORT:-8080}:8080"
volumes:
# API y worker deben compartir este volumen: la API guarda las entradas y sirve los resultados que escribe el worker.
- storage-data:/data/storage
depends_on:
postgres:
condition: service_healthy
rabbitmq:
condition: service_healthy
redis:
condition: service_healthy
# El healthcheck (GET /actuator/health) viene definido en la imagen.
restart: unless-stopped
# Réplicas: `docker compose up -d --scale worker=3` (sin container_name ni puertos publicados, no hay conflictos).
worker:
build:
context: ./backend
dockerfile: worker/Dockerfile
image: queuelab-worker:${QUEUELAB_TAG:-latest}
environment:
QUEUELAB_DB_URL: jdbc:postgresql://postgres:5432/${POSTGRES_DB:-queuelab}
QUEUELAB_DB_USER: ${POSTGRES_USER:-queuelab}
QUEUELAB_DB_PASSWORD: ${POSTGRES_PASSWORD:-queuelab}
QUEUELAB_RABBITMQ_HOST: rabbitmq
QUEUELAB_RABBITMQ_USER: ${RABBITMQ_USER:-queuelab}
QUEUELAB_RABBITMQ_PASSWORD: ${RABBITMQ_PASSWORD:-queuelab}
# /metrics sin autenticación: se abre a la red de Compose (para Prometheus), pero el puerto NO se publica en el host.
QUEUELAB_METRICS_ADDRESS: 0.0.0.0
volumes:
- storage-data:/data/storage
depends_on:
postgres:
condition: service_healthy
rabbitmq:
condition: service_healthy
# La API aplica las migraciones de Flyway al arrancar; el worker asume que el esquema ya existe.
api:
condition: service_healthy
# El worker no tiene puerto HTTP de negocio: se vigila con su endpoint /metrics (la imagen no trae HEALTHCHECK).
healthcheck:
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://127.0.0.1:8081/metrics"]
interval: 10s
timeout: 3s
retries: 6
start_period: 45s
restart: unless-stopped
dashboard:
build:
context: ./frontend
image: queuelab-dashboard:${QUEUELAB_TAG:-latest}
environment:
# URL de la API tal como la ve el NAVEGADOR (no un nombre interno de la red de Compose).
QUEUELAB_API_URL: http://localhost:${API_PORT:-8080}
ports:
- "127.0.0.1:${DASHBOARD_PORT:-3000}:3000"
depends_on:
api:
condition: service_healthy
# El healthcheck (GET /jobs) viene definido en la imagen.
restart: unless-stopped
# --- Observabilidad (opcional): `docker compose --profile observability up -d` ---
# Prometheus recoge las métricas de la API y del worker y Grafana muestra el dashboard provisionado. Por defecto
# apunta a la API y al worker del host; con el stack de arriba use PROMETHEUS_CONFIG=prometheus.compose.yml
# (ver docs/observability/dashboard.md). Grafana usa el 3300 para no chocar con el dashboard web (3000) ni con servidores de desarrollo habituales (3001).
prometheus:
profiles: ["observability"]
image: prom/prometheus:v3.5.0
command:
- --config.file=/etc/prometheus/prometheus.yml
- --storage.tsdb.retention.time=7d
ports:
- "127.0.0.1:${PROMETHEUS_PORT:-9090}:9090"
volumes:
- ${PROMETHEUS_CONFIG:-./observability/prometheus/prometheus.yml}:/etc/prometheus/prometheus.yml:ro
- prometheus-data:/prometheus
extra_hosts:
- "host.docker.internal:host-gateway"
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:9090/-/ready"]
interval: 5s
timeout: 3s
retries: 10
restart: unless-stopped
grafana:
profiles: ["observability"]
image: grafana/grafana:12.1.1
environment:
GF_SECURITY_ADMIN_USER: ${GRAFANA_USER:-admin}
GF_SECURITY_ADMIN_PASSWORD: ${GRAFANA_PASSWORD:-admin}
# Solo local (puerto en 127.0.0.1): el dashboard se abre sin iniciar sesión, en modo lectura.
GF_AUTH_ANONYMOUS_ENABLED: "true"
GF_AUTH_ANONYMOUS_ORG_ROLE: Viewer
GF_DASHBOARDS_DEFAULT_HOME_DASHBOARD_PATH: /etc/grafana/dashboards/queuelab.json
GF_ANALYTICS_REPORTING_ENABLED: "false"
GF_ANALYTICS_CHECK_FOR_UPDATES: "false"
ports:
- "127.0.0.1:${GRAFANA_PORT:-3300}:3000"
volumes:
- ./observability/grafana/provisioning:/etc/grafana/provisioning:ro
- ./observability/grafana/dashboards:/etc/grafana/dashboards:ro
- grafana-data:/var/lib/grafana
depends_on:
prometheus:
condition: service_healthy
healthcheck:
test: ["CMD-SHELL", "wget -q --spider http://localhost:3000/api/health || exit 1"]
interval: 5s
timeout: 3s
retries: 20
restart: unless-stopped
# Red única y con nombre fijo: todos los servicios (también Prometheus y Grafana) se resuelven por su nombre
# (`postgres`, `rabbitmq`, `redis`, `api`, `worker`). Solo se publican, en 127.0.0.1, los puertos que se listan arriba.
networks:
default:
name: queuelab
volumes:
postgres-data:
rabbitmq-data:
# Entradas y resultados de los trabajos CSV: compartido por la API y los worker.
storage-data:
prometheus-data:
grafana-data: