A Docker Compose setup demonstrating a multi-service architecture with health-based service dependencies, persistent storage, and secure logging configuration.
- Postgres: backing database for Keycloak, with data persisted outside Docker's default volume location via a bind mount.
- Keycloak: Identity and Access Management (IAM) service, connected to Postgres for persistent storage of realms, users, and clients.
- curl-service: a lightweight utility container that stays alive and only starts
once both Postgres and Keycloak report a
healthystatus.
- Bind mount instead of named volume: Postgres data is stored in
./db-datarather than Docker's default volume path, for easier inspection and backup. - Health-based startup order:
depends_onusescondition: service_healthyto ensure Keycloak only starts after Postgres is truly ready, andcurl-serviceonly starts after both services are healthy — not just "running". - Non-JSON logging: the default
json-filelogging driver was replaced withlocal, which is more space-efficient and avoids storing logs as JSON. - Log rotation limits:
max-file: 20caps the number of retained log files. Note: Docker's built-in logging drivers rotate by file count/size, not by calendar day — for true daily rotation, an external tool likelogrotatewould be required on the host. - Minimal exposed surface: only Keycloak's port (8080) is exposed to the host. Postgres and the curl service are reachable only within the internal Docker network.
- Copy the example environment file and fill in your own values:
cp .env.example .env- Start the stack:
docker compose up -d- Check service health:
docker compose ps- Access the Keycloak login page:
http://localhost:8080
This project was built as a hands-on exercise to practice Docker Compose service orchestration, health checks, and secure defaults — concepts directly relevant to DevOps/DevSecOps workflows.