services: # ========================================== # Core API Service # ========================================== api: image: ${TJWATER_SERVER_IMAGE:-tjwater-server:local} build: context: ../.. dockerfile: Dockerfile container_name: tjwater_api restart: always ports: - "${API_PORT}:8000" volumes: - ../../app:/app/app - ../../resources:/app/resources environment: - PYTHONPATH=/app # Add other DB connections here as needed by your app depends_on: - timescaledb - postgis # ========================================== # Infrastructure Services # ========================================== # --- Keycloak --- keycloakDB: image: postgis/postgis:14-3.6@sha256:92b924abbccde1d7ac07947bc6fc0b06d6b3a4806c9c0b7020ba820fecaa6de6 container_name: keycloakDB restart: always environment: POSTGRES_DB: ${KEYCLOAK_DB_NAME} POSTGRES_USER: ${KEYCLOAK_DB_USER} POSTGRES_PASSWORD: ${KEYCLOAK_DB_PASSWORD} command: postgres -c wal_level=logical ports: - "${KEYCLOAK_DB_PORT}:5432" volumes: - ./keycloak/db_data:/var/lib/postgresql/data keycloak: image: keycloak/keycloak:26.8.1@sha256:79c623a22abacf3fe6c00a5fb30f5b7843d717b234033b80995891c06116d244 container_name: keycloak restart: always environment: KC_HOSTNAME: localhost KC_HOSTNAME_STRICT_BACKCHANNEL: "true" KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN_USER} KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD} KC_HEALTH_ENABLED: "true" KC_LOG_LEVEL: info KC_DB: postgres KC_DB_URL: jdbc:postgresql://keycloakDB:5432/${KEYCLOAK_DB_NAME} KC_DB_USERNAME: ${KEYCLOAK_DB_USER} KC_DB_PASSWORD: ${KEYCLOAK_DB_PASSWORD} volumes: - ./keycloak/themes:/opt/keycloak/themes - ./keycloak/import:/opt/keycloak/data/import healthcheck: test: [ "CMD", "curl", "-f", "http://localhost:8080/health/ready" ] interval: 15s timeout: 2s retries: 15 command: [ "start-dev", "--import-realm" ] ports: - "${KEYCLOAK_PORT}:8080" depends_on: - keycloakDB # --- TimescaleDB --- timescaledb: image: timescale/timescaledb:latest-pg15 container_name: timescaledb restart: always environment: POSTGRES_DB: ${TIMESCALE_DB_NAME} POSTGRES_USER: ${TIMESCALE_USER} POSTGRES_PASSWORD: ${DB_PASSWORD_SHARED} ports: - "${TIMESCALE_PORT}:5432" volumes: - ./timescaledb/data:/var/lib/postgresql/data # --- MapService (PostGIS & GeoServer) --- postgis: image: postgis/postgis:14-3.6@sha256:92b924abbccde1d7ac07947bc6fc0b06d6b3a4806c9c0b7020ba820fecaa6de6 container_name: postgis restart: always environment: POSTGRES_DB: ${POSTGIS_DB_NAME} POSTGRES_USER: ${POSTGIS_USER} POSTGRES_PASSWORD: ${DB_PASSWORD_SHARED} command: - postgres - -c - wal_level=logical - -c - max_worker_processes=32 - -c - max_logical_replication_workers=24 - -c - max_replication_slots=24 - -c - max_wal_senders=24 ports: - "${POSTGIS_PORT}:5432" volumes: - ./mapservice/data:/var/lib/postgresql/data geoserver: image: docker.osgeo.org/geoserver:2.28.5@sha256:c6a3f3ef32c8b39e8a93ef54346cbe62f212ed27f1c49c3ff51cbae5a9b70e84 container_name: geoserver restart: always ports: - "${GEOSERVER_PORT}:8080" depends_on: - postgis environment: - GEOSERVER_ADMIN_USER=${GEOSERVER_ADMIN_USER} - GEOSERVER_ADMIN_PASSWORD=${GEOSERVER_ADMIN_PASSWORD} - INSTALL_EXTENSIONS=true - STABLE_EXTENSIONS=vectortiles - CORS_ENABLED=true - CORS_ALLOWED_ORIGINS=* volumes: - ./mapservice/geoserver_data:/opt/geoserver_data networks: default: driver: bridge