services: postgres: image: imresamu/postgis:16-3.4 # multi-arch (amd64 + arm64) ports: - "5432:5432" environment: POSTGRES_USER: trails POSTGRES_PASSWORD: trails POSTGRES_DB: trails command: ["postgres", "-c", "shared_preload_libraries=pg_stat_statements"] volumes: - pgdata:/var/lib/postgresql/data - ./infrastructure/postgres/init-grafana-user.sql:/docker-entrypoint-initdb.d/init-grafana-user.sql:ro healthcheck: test: ["CMD-SHELL", "pg_isready -U trails"] interval: 5s timeout: 5s retries: 5 brouter: build: docker/brouter ports: - "17777:17777" volumes: - brouter_segments:/data/segments healthcheck: test: ["CMD-SHELL", "curl -s http://localhost:17777/ > /dev/null 2>&1"] interval: 5s timeout: 5s retries: 30 start_period: 10s prometheus: image: prom/prometheus:latest profiles: [monitoring] ports: - "9090:9090" volumes: # Directory mount (not the file) to match prod — a single-file bind # mount pins the host inode, so a replaced config is never seen. - ./infrastructure/prometheus:/etc/prometheus:ro - prometheus_data:/prometheus grafana: image: grafana/grafana:latest profiles: [monitoring] ports: - "3002:3000" environment: GF_AUTH_ANONYMOUS_ENABLED: "true" GF_AUTH_ANONYMOUS_ORG_ROLE: Admin GF_AUTH_DISABLE_LOGIN_FORM: "true" volumes: - ./infrastructure/grafana/provisioning/datasources:/etc/grafana/provisioning/datasources:ro - ./infrastructure/grafana/provisioning/dashboards:/etc/grafana/provisioning/dashboards:ro - ./infrastructure/grafana/dashboards:/var/lib/grafana/dashboards:ro - grafana_data:/var/lib/grafana loki: image: grafana/loki:latest profiles: [monitoring] ports: - "3100:3100" volumes: # Directory mount (not the file) to match prod. - ./infrastructure/loki:/etc/loki:ro - loki_data:/loki command: ["-config.file=/etc/loki/loki-config.yml"] volumes: pgdata: brouter_segments: prometheus_data: grafana_data: loki_data: