@@ -146,8 +146,12 @@ volumes:
146146secrets :
147147 db-password :
148148 file : ./secrets/db-password.txt
149- db-user :
150- file : ./secrets/db-user.txt
149+ api-db-password :
150+ file : ./secrets/api-db-password.txt
151+ keycloak-db-password :
152+ file : ./secrets/keycloak-db-password.txt
153+ keycloak-admin-password :
154+ file : ./secrets/keycloak-admin-password.txt
151155
152156# ============================================================================
153157# CONFIGURATION
@@ -266,7 +270,7 @@ services:
266270
267271 # Ports: DO NOT expose externally in production
268272 # ports:
269- # - "8080 :8080" # ❌ For debug only, remove in production
273+ # - "8081 :8080" # ❌ For debug only, remove in production
270274
271275 # Ports (not externally exposed, only through nginx)
272276 expose :
@@ -277,8 +281,7 @@ services:
277281 - .env
278282
279283 secrets :
280- - db-password
281- - db-user
284+ - api-db-password
282285
283286 # Volumes
284287 volumes :
@@ -288,6 +291,8 @@ services:
288291 depends_on :
289292 db :
290293 condition : service_healthy
294+ keycloak :
295+ condition : service_healthy
291296
292297 # Resource limits
293298 deploy :
@@ -368,11 +373,13 @@ services:
368373 # Secrets
369374 secrets :
370375 - db-password
371- - db-user
376+ - keycloak-db-password
377+ - api-db-password
372378
373379 # Persistent volumes
374380 volumes :
375381 - db-data:/var/lib/postgresql/data
382+ - ./postgres/init:/docker-entrypoint-initdb.d:ro # Initialization scripts
376383
377384 # Not required, docker uses .env by default
378385 env_file :
@@ -386,7 +393,7 @@ services:
386393
387394 # Healthcheck
388395 healthcheck :
389- test : [ "CMD-SHELL", "pg_isready -U $$(cat /run/secrets/db-user) - d ${POSTGRES_DB:-people }" ]
396+ test : [ "CMD-SHELL", "pg_isready -U ${POSTGRES_USER} - d ${POSTGRES_DB}" ]
390397 interval : 10s
391398 timeout : 5s
392399 retries : 5
@@ -418,6 +425,71 @@ services:
418425 # Shared memory size (important for PostgreSQL)
419426 shm_size : 256mb
420427
428+ # ==========================================================================
429+ # KEYCLOAK - Identity and Access Management
430+ # ==========================================================================
431+ keycloak :
432+ image : quay.io/keycloak/keycloak:26.4
433+ container_name : keycloak
434+
435+ cap_drop :
436+ - ALL
437+
438+ security_opt :
439+ - no-new-privileges:true
440+
441+ restart : unless-stopped
442+
443+ networks :
444+ - backend
445+
446+ expose :
447+ - " 8080"
448+
449+ # Ports: DO NOT expose externally in production
450+ # ports:
451+ # - "8080:8080" # ❌ For debug only, remove in production
452+
453+ secrets :
454+ - keycloak-db-password
455+ - keycloak-admin-password
456+
457+ env_file :
458+ - .env
459+
460+ command : start-dev
461+
462+ depends_on :
463+ db :
464+ condition : service_healthy
465+
466+ healthcheck :
467+ test : ["CMD-SHELL", "exec 3<>/dev/tcp/keycloak/9000 && echo -e 'GET /health/ready HTTP/1.1\r\nHost: keycloak\r\nConnection: close\r\n\r\n' >&3 && cat <&3 | grep -q '200 OK'"]
468+ interval : 30s
469+ timeout : 10s
470+ retries : 5
471+ start_period : 90s # Keycloak takes time to initialize
472+
473+ deploy :
474+ resources :
475+ limits :
476+ cpus : ' 0.5'
477+ memory : 512M
478+ reservations :
479+ cpus : ' 0.25'
480+ memory : 256M
481+
482+ logging :
483+ driver : " json-file"
484+ options :
485+ max-size : " 50m"
486+ max-file : " 3"
487+
488+ labels :
489+ service : " keycloak"
490+ tier : " backend"
491+ environment : " ${ENVIRONMENT:-production}"
492+
421493# ============================================================================
422494# INITIALIZATION
423495# ============================================================================
0 commit comments