Skip to content

Commit c7f34a0

Browse files
committed
feat: Phase 4 Lab 06 -- Production Deployment (restart policy, resource limits, workers)
1 parent 4afbdd0 commit c7f34a0

3 files changed

Lines changed: 544 additions & 7 deletions

File tree

.github/workflows/ci.yml

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,4 +272,60 @@ run: bash tests/labs/test-lab-15-01.sh
272272

273273
- name: Cleanup
274274
if: always()
275-
run: docker compose -f docker/docker-compose.integration.yml down -v
275+
run: docker compose -f docker/docker-compose.integration.yml down -v
276+
277+
lab-06-smoke:
278+
name: Lab 15-06 -- Taiga Production Deployment (restart policy, resource limits, Celery events worker)
279+
runs-on: ubuntu-latest
280+
needs: validate
281+
continue-on-error: true
282+
steps:
283+
- uses: actions/checkout@v4
284+
285+
- name: Install tools
286+
run: sudo apt-get install -y curl postgresql-client netcat-openbsd ldap-utils
287+
288+
- name: Validate production compose
289+
run: docker compose -f docker/docker-compose.production.yml config -q && echo "Production compose valid"
290+
291+
- name: Start production stack
292+
run: docker compose -f docker/docker-compose.production.yml up -d
293+
294+
- name: Wait for PostgreSQL
295+
run: |
296+
for i in $(seq 1 18); do
297+
docker exec taiga-p06-db pg_isready -U taiga -d taiga > /dev/null 2>&1 && echo "DB ready" && break
298+
echo "Waiting for DB... ($i/18)"; sleep 5
299+
done
300+
301+
- name: Wait for Keycloak
302+
run: |
303+
for i in $(seq 1 24); do
304+
curl -sf http://localhost:8560/realms/master | grep -q realm && echo "KC ready" && break
305+
echo "Waiting for KC... ($i/24)"; sleep 5
306+
done
307+
308+
- name: Wait for Mailhog
309+
run: |
310+
for i in $(seq 1 12); do
311+
curl -sf http://localhost:8750/api/v2/messages > /dev/null && echo "MH ready" && break
312+
echo "Waiting for MH... ($i/12)"; sleep 5
313+
done
314+
315+
- name: Wait for Taiga frontend
316+
run: |
317+
for i in $(seq 1 24); do
318+
curl -sf http://localhost:8460/ | grep -qi html && echo "Taiga ready" && break
319+
echo "Waiting for Taiga... ($i/24)"; sleep 5
320+
done
321+
322+
- name: Run Lab 15-06 test script
323+
run: bash tests/labs/test-lab-15-06.sh --no-cleanup
324+
325+
- name: Collect logs on failure
326+
if: failure()
327+
run: docker compose -f docker/docker-compose.production.yml logs
328+
329+
- name: Cleanup
330+
if: always()
331+
run: docker compose -f docker/docker-compose.production.yml down -v

docker/docker-compose.production.yml

Lines changed: 312 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,318 @@
1-
# Lab 06 — Production: taiga HA-ready with monitoring and external volumes
2-
---
1+
# =============================================================================
2+
# IT-Stack: Taiga — Lab 06: Production Deployment
3+
# Module 15 · Phase 4 · Lab 06
4+
# =============================================================================
5+
# Services: PostgreSQL · Redis · OpenLDAP · Keycloak · Mailhog
6+
# Taiga Back · Taiga Front · Events Worker
7+
# Ports: Front:8460 Back:8061 KC:8560 LDAP:3871 MH:8750
8+
# Credentials:
9+
# DB: taiga / TaigaProd06!
10+
# Keycloak: admin / Admin06!
11+
# LDAP: cn=admin,dc=lab,dc=local / LdapProd06!
12+
# Taiga: admin / AdminProd06!
13+
# Production features vs Lab 05:
14+
# + restart: unless-stopped on ALL services
15+
# + Resource limits AND reservations on every service
16+
# + Dedicated events-worker container (async event processing)
17+
# + Redis for async event queue + session cache
18+
# + IT_STACK_ENV: production IT_STACK_LAB: "06" labels
19+
# + Healthcheck start_period on long-boot services
20+
# =============================================================================
21+
22+
name: it-stack-taiga-lab06
23+
324
services:
4-
taiga:
25+
26+
# ── PostgreSQL ────────────────────────────────────────────────────────────
27+
taiga-p06-db:
28+
image: postgres:15-alpine
29+
container_name: taiga-p06-db
30+
restart: unless-stopped
31+
environment:
32+
POSTGRES_DB: taiga
33+
POSTGRES_USER: taiga
34+
POSTGRES_PASSWORD: TaigaProd06!
35+
volumes:
36+
- taiga-p06-db-data:/var/lib/postgresql/data
37+
healthcheck:
38+
test: ["CMD-SHELL", "pg_isready -U taiga || exit 1"]
39+
interval: 10s
40+
timeout: 5s
41+
retries: 5
42+
start_period: 20s
43+
networks:
44+
- taiga-p06-net
45+
deploy:
46+
resources:
47+
limits:
48+
cpus: "1.0"
49+
memory: 512M
50+
reservations:
51+
cpus: "0.25"
52+
memory: 128M
53+
54+
# ── Redis ───────────────────────────────────────────────────────────────────
55+
taiga-p06-redis:
56+
image: redis:7-alpine
57+
container_name: taiga-p06-redis
58+
restart: unless-stopped
59+
command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
60+
volumes:
61+
- taiga-p06-redis-data:/data
62+
healthcheck:
63+
test: ["CMD", "redis-cli", "ping"]
64+
interval: 10s
65+
timeout: 3s
66+
retries: 3
67+
networks:
68+
- taiga-p06-net
69+
deploy:
70+
resources:
71+
limits:
72+
cpus: "0.5"
73+
memory: 320M
74+
reservations:
75+
cpus: "0.1"
76+
memory: 64M
77+
78+
# ── OpenLDAP ───────────────────────────────────────────────────────────────
79+
taiga-p06-ldap:
80+
image: osixia/openldap:1.5.0
81+
container_name: taiga-p06-ldap
82+
restart: unless-stopped
83+
environment:
84+
LDAP_ORGANISATION: "IT-Stack Production"
85+
LDAP_DOMAIN: lab.local
86+
LDAP_ADMIN_PASSWORD: LdapProd06!
87+
LDAP_CONFIG_PASSWORD: ConfigProd06!
88+
LDAP_BASE_DN: dc=lab,dc=local
89+
LDAP_READONLY_USER: "true"
90+
LDAP_READONLY_USER_USERNAME: readonly
91+
LDAP_READONLY_USER_PASSWORD: ReadOnlyProd06!
92+
ports:
93+
- "3871:389"
94+
volumes:
95+
- taiga-p06-ldap-data:/var/lib/ldap
96+
- taiga-p06-ldap-config:/etc/ldap/slapd.d
97+
healthcheck:
98+
test: ["CMD-SHELL", "ldapsearch -x -H ldap://localhost -b dc=lab,dc=local -D cn=admin,dc=lab,dc=local -w LdapProd06! cn=admin > /dev/null 2>&1 && echo ok"]
99+
interval: 15s
100+
timeout: 5s
101+
retries: 5
102+
start_period: 20s
103+
networks:
104+
- taiga-p06-net
105+
deploy:
106+
resources:
107+
limits:
108+
cpus: "0.5"
109+
memory: 256M
110+
reservations:
111+
cpus: "0.1"
112+
memory: 64M
113+
114+
# ── Keycloak ───────────────────────────────────────────────────────────────
115+
taiga-p06-kc:
116+
image: quay.io/keycloak/keycloak:24.0.3
117+
container_name: taiga-p06-kc
118+
restart: unless-stopped
119+
command: start-dev
120+
environment:
121+
KEYCLOAK_ADMIN: admin
122+
KEYCLOAK_ADMIN_PASSWORD: Admin06!
123+
KC_HEALTH_ENABLED: "true"
124+
KC_DB: dev-file
125+
KC_HOSTNAME_STRICT: "false"
126+
KC_HOSTNAME_STRICT_HTTPS: "false"
127+
KC_HTTP_ENABLED: "true"
128+
ports:
129+
- "8560:8080"
130+
healthcheck:
131+
test: ["CMD-SHELL", "curl -sf http://localhost:8080/realms/master || exit 1"]
132+
interval: 15s
133+
timeout: 5s
134+
retries: 10
135+
start_period: 60s
136+
networks:
137+
- taiga-p06-net
138+
deploy:
139+
resources:
140+
limits:
141+
cpus: "1.0"
142+
memory: 768M
143+
reservations:
144+
cpus: "0.25"
145+
memory: 256M
146+
147+
# ── Mailhog ────────────────────────────────────────────────────────────────
148+
taiga-p06-mail:
149+
image: mailhog/mailhog:latest
150+
container_name: taiga-p06-mail
151+
restart: unless-stopped
152+
ports:
153+
- "8750:8025"
154+
healthcheck:
155+
test: ["CMD-SHELL", "wget -qO- http://localhost:8025/api/v2/messages || exit 1"]
156+
interval: 10s
157+
timeout: 5s
158+
retries: 3
159+
networks:
160+
- taiga-p06-net
161+
deploy:
162+
resources:
163+
limits:
164+
cpus: "0.25"
165+
memory: 128M
166+
reservations:
167+
cpus: "0.05"
168+
memory: 32M
169+
170+
# ── Taiga Back ────────────────────────────────────────────────────────────
171+
taiga-p06-back:
172+
image: taigaio/taiga-back:latest
173+
container_name: taiga-p06-back
174+
restart: unless-stopped
175+
depends_on:
176+
taiga-p06-db:
177+
condition: service_healthy
178+
taiga-p06-redis:
179+
condition: service_healthy
180+
taiga-p06-ldap:
181+
condition: service_healthy
182+
taiga-p06-kc:
183+
condition: service_healthy
184+
ports:
185+
- "8061:8000"
186+
environment:
187+
IT_STACK_ENV: production
188+
IT_STACK_MODULE: taiga
189+
IT_STACK_LAB: "06"
190+
DJANGO_SECRET_KEY: taiga-prod-secret-key-06-change-in-prod
191+
POSTGRES_DB: taiga
192+
POSTGRES_USER: taiga
193+
POSTGRES_PASSWORD: TaigaProd06!
194+
POSTGRES_HOST: taiga-p06-db
195+
REDIS_URL: redis://taiga-p06-redis:6379
196+
TAIGA_SECRET_KEY: taiga-prod-secret-key-06
197+
TAIGA_DEBUG: "False"
198+
TAIGA_SITES_DOMAIN: localhost
199+
TAIGA_SITES_SCHEME: http
200+
DEFAULT_FROM_EMAIL: taiga@lab.local
201+
EMAIL_BACKEND: django.core.mail.backends.smtp.EmailBackend
202+
EMAIL_HOST: taiga-p06-mail
203+
EMAIL_PORT: "1025"
204+
CELERY_BROKER_URL: redis://taiga-p06-redis:6379
205+
CELERY_RESULT_BACKEND: redis://taiga-p06-redis:6379
206+
KEYCLOAK_URL: http://taiga-p06-kc:8080
207+
KEYCLOAK_REALM: it-stack
208+
KEYCLOAK_CLIENT_ID: taiga
209+
LDAP_SERVER: ldap://taiga-p06-ldap
210+
LDAP_BASE_DN: dc=lab,dc=local
211+
LDAP_BIND_DN: cn=admin,dc=lab,dc=local
212+
LDAP_BIND_PASSWORD: LdapProd06!
213+
MATTERMOST_URL: http://mattermost.lab.local:8065
214+
MATTERMOST_CHANNEL: it-stack-projects
215+
MATTERMOST_WEBHOOK_TOKEN: prod-mm-token-06
216+
volumes:
217+
- taiga-p06-back-data:/taiga-back/media
218+
healthcheck:
219+
test: ["CMD-SHELL", "curl -sf http://localhost:8000/api/v1/ || exit 1"]
220+
interval: 30s
221+
timeout: 10s
222+
retries: 5
223+
start_period: 120s
224+
networks:
225+
- taiga-p06-net
226+
deploy:
227+
resources:
228+
limits:
229+
cpus: "1.5"
230+
memory: 1G
231+
reservations:
232+
cpus: "0.25"
233+
memory: 256M
234+
235+
# ── Taiga Front ───────────────────────────────────────────────────────────
236+
taiga-p06-front:
5237
image: taigaio/taiga-front:latest
6-
container_name: it-stack-taiga
7-
restart: always
238+
container_name: taiga-p06-front
239+
restart: unless-stopped
240+
depends_on:
241+
taiga-p06-back:
242+
condition: service_healthy
8243
ports:
9-
- "80:$firstPort"
244+
- "8460:80"
245+
environment:
246+
IT_STACK_ENV: production
247+
IT_STACK_MODULE: taiga
248+
IT_STACK_LAB: "06"
249+
TAIGA_URL: http://localhost:8460
250+
TAIGA_WEBSOCKETS_URL: ws://localhost:8061
251+
TAIGA_SUBPATH: ""
252+
healthcheck:
253+
test: ["CMD-SHELL", "curl -sf http://localhost:80/ || exit 1"]
254+
interval: 30s
255+
timeout: 10s
256+
retries: 5
257+
start_period: 30s
258+
networks:
259+
- taiga-p06-net
260+
deploy:
261+
resources:
262+
limits:
263+
cpus: "0.5"
264+
memory: 256M
265+
reservations:
266+
cpus: "0.1"
267+
memory: 64M
268+
269+
# ── Taiga Events Worker (Celery async task processor) ────────────────────
270+
taiga-p06-events:
271+
image: taigaio/taiga-back:latest
272+
container_name: taiga-p06-events
273+
restart: unless-stopped
274+
command: ["python", "-m", "celery", "-A", "taiga.celery", "worker", "--loglevel=info", "-c", "2"]
275+
depends_on:
276+
taiga-p06-back:
277+
condition: service_healthy
278+
environment:
279+
IT_STACK_ENV: production
280+
IT_STACK_MODULE: taiga
281+
IT_STACK_LAB: "06"
282+
DJANGO_SECRET_KEY: taiga-prod-secret-key-06-change-in-prod
283+
POSTGRES_DB: taiga
284+
POSTGRES_USER: taiga
285+
POSTGRES_PASSWORD: TaigaProd06!
286+
POSTGRES_HOST: taiga-p06-db
287+
REDIS_URL: redis://taiga-p06-redis:6379
288+
CELERY_BROKER_URL: redis://taiga-p06-redis:6379
289+
CELERY_RESULT_BACKEND: redis://taiga-p06-redis:6379
290+
volumes:
291+
- taiga-p06-back-data:/taiga-back/media
292+
networks:
293+
- taiga-p06-net
294+
deploy:
295+
resources:
296+
limits:
297+
cpus: "0.5"
298+
memory: 512M
299+
reservations:
300+
cpus: "0.1"
301+
memory: 128M
302+
303+
# ── Networks ───────────────────────────────────────────────────────────────────
304+
networks:
305+
taiga-p06-net:
306+
name: taiga-p06-net
307+
driver: bridge
308+
309+
# ── Volumes ────────────────────────────────────────────────────────────────────
310+
volumes:
311+
taiga-p06-db-data:
312+
taiga-p06-redis-data:
313+
taiga-p06-ldap-data:
314+
taiga-p06-ldap-config:
315+
taiga-p06-back-data:
10316
environment:
11317
- IT_STACK_ENV=production
12318
- KEYCLOAK_URL=

0 commit comments

Comments
 (0)