name: project-auth-local x-defaults: &defaults init: true restart: unless-stopped logging: driver: json-file options: max-size: "10m" max-file: "3" services: postgres: <<: *defaults image: postgres:16-alpine env_file: - ../../.env.local ports: - "${POSTGRES_HOST_PORT:-5432}:5432" environment: POSTGRES_USER: ${POSTGRES_SUPERUSER:-postgres} POSTGRES_PASSWORD: ${POSTGRES_SUPERUSER_PASSWORD:-postgres} POSTGRES_DB: ${POSTGRES_DEFAULT_DB:-postgres} AUTH_DB_NAME: ${AUTH_DB_NAME:-project_auth} AUTH_DB_USER: ${AUTH_DB_USER:-project_auth} AUTH_DB_PASSWORD: ${AUTH_DB_PASSWORD:-project_auth} KEYCLOAK_DB_NAME: ${KEYCLOAK_DB_NAME:-keycloak} KEYCLOAK_DB_USER: ${KEYCLOAK_DB_USER:-keycloak} KEYCLOAK_DB_PASSWORD: ${KEYCLOAK_DB_PASSWORD:-keycloak} volumes: - postgres_data:/var/lib/postgresql/data - ./resources/postgres/init:/docker-entrypoint-initdb.d:ro healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_SUPERUSER:-postgres} -d ${POSTGRES_DEFAULT_DB:-postgres}"] interval: 10s timeout: 5s retries: 10 networks: [auth_net] keycloak: <<: *defaults image: quay.io/keycloak/keycloak:26.5.5 env_file: - ../../.env.local command: - start-dev - --import-realm - --http-port=8080 - --http-management-port=9000 depends_on: postgres: condition: service_healthy ports: - "${KEYCLOAK_HOST_PORT:-8081}:8080" environment: KC_DB: postgres KC_DB_URL: jdbc:postgresql://postgres:5432/${KEYCLOAK_DB_NAME:-keycloak} KC_DB_USERNAME: ${KEYCLOAK_DB_USER:-keycloak} KC_DB_PASSWORD: ${KEYCLOAK_DB_PASSWORD:-keycloak} KC_HEALTH_ENABLED: "true" KC_BOOTSTRAP_ADMIN_USERNAME: ${KEYCLOAK_ADMIN:-admin} KC_BOOTSTRAP_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD:-admin} volumes: - keycloak_data:/opt/keycloak/data - ../../docs/development/keycloak/realm:/opt/keycloak/data/import:ro healthcheck: # Keycloak image ships no curl/wget; use bash /dev/tcp against the management port. test: - "CMD-SHELL" - | exec 3<>/dev/tcp/127.0.0.1/9000 && \ printf 'GET /health/ready HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n' >&3 && \ grep -q '200 OK' <&3 interval: 10s timeout: 5s retries: 30 start_period: 60s networks: [auth_net] vault: <<: *defaults image: hashicorp/vault:1.18 env_file: - ../../.env.local command: - vault - server - -dev - -dev-root-token-id=${VAULT_DEV_ROOT_TOKEN_ID:-project-auth-root-token} - -dev-listen-address=0.0.0.0:8200 ports: - "${VAULT_HOST_PORT:-8200}:8200" environment: # 127.0.0.1 here is correct: it scopes the in-container `vault` CLI used by the healthcheck. VAULT_ADDR: http://127.0.0.1:8200 VAULT_DEV_ROOT_TOKEN_ID: ${VAULT_DEV_ROOT_TOKEN_ID:-project-auth-root-token} VAULT_DEV_LISTEN_ADDRESS: 0.0.0.0:8200 healthcheck: test: ["CMD", "vault", "status", "-address=http://127.0.0.1:8200"] interval: 10s timeout: 5s retries: 10 networks: [auth_net] vault-init: image: hashicorp/vault:1.18 init: true restart: "no" logging: driver: json-file options: max-size: "10m" max-file: "3" env_file: - ../../.env.local depends_on: vault: condition: service_healthy environment: VAULT_ADDR: http://vault:8200 VAULT_TOKEN: ${VAULT_DEV_ROOT_TOKEN_ID:-project-auth-root-token} VAULT_TRANSIT_KEY_NAME: ${VAULT_TRANSIT_KEY_NAME:-project-auth-jwt} entrypoint: - /bin/sh - /vault-init/01-init-transit.sh volumes: - ./resources/vault/init:/vault-init:ro networks: [auth_net] volumes: postgres_data: keycloak_data: networks: auth_net: name: project-auth-local