services: # ========================================================================= # Ingress — routes gRPC traffic to Diode services # ========================================================================= ingress-nginx: image: nginx:1.27-alpine ports: - "8080:8080" volumes: - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro depends_on: diode-ingester: condition: service_started diode-reconciler: condition: service_started diode-auth: condition: service_started restart: unless-stopped # ========================================================================= # Diode Ingester — accepts gRPC, publishes to Redis streams # ========================================================================= diode-ingester: image: netboxlabs/diode-ingester:latest environment: DIODE_REDIS_HOST: redis DIODE_REDIS_PORT: "6379" DIODE_REDIS_PASSWORD: "${REDIS_PASSWORD}" DIODE_GRPC_PORT: "8081" DIODE_AUTH_GRPC_TARGET: diode-auth:8081 depends_on: redis: condition: service_healthy restart: unless-stopped # ========================================================================= # Diode Reconciler — consumes Redis streams, reconciles with NetBox # ========================================================================= diode-reconciler: image: netboxlabs/diode-reconciler:latest environment: DIODE_REDIS_HOST: redis DIODE_REDIS_PORT: "6379" DIODE_REDIS_PASSWORD: "${REDIS_PASSWORD}" DIODE_GRPC_PORT: "8081" DIODE_NETBOX_API_URL: "${NETBOX_API_URL}" DIODE_NETBOX_API_TOKEN: "${NETBOX_API_TOKEN}" DIODE_RECONCILER_CLIENT_ID: "${RECONCILER_CLIENT_ID}" DIODE_RECONCILER_CLIENT_SECRET: "${RECONCILER_CLIENT_SECRET}" DIODE_AUTH_GRPC_TARGET: diode-auth:8081 DIODE_TO_NETBOX_CLIENT_ID: "${NETBOX_TO_DIODE_CLIENT_ID}" DIODE_TO_NETBOX_CLIENT_SECRET: "${NETBOX_TO_DIODE_CLIENT_SECRET}" depends_on: redis: condition: service_healthy diode-auth-bootstrap: condition: service_completed_successfully restart: unless-stopped # ========================================================================= # Diode Auth — validates OAuth2 tokens via Hydra # ========================================================================= diode-auth: image: netboxlabs/diode-auth:latest environment: DIODE_GRPC_PORT: "8081" DIODE_HYDRA_ADMIN_URL: http://hydra:4445 DIODE_HYDRA_PUBLIC_URL: http://hydra:4444 depends_on: hydra: condition: service_started restart: unless-stopped # ========================================================================= # Diode Auth Bootstrap — registers OAuth2 clients in Hydra (one-shot) # ========================================================================= diode-auth-bootstrap: image: python:3.12-alpine command: /client-credentials/bootstrap-clients.sh environment: HYDRA_ADMIN_URL: http://hydra:4445 volumes: - ./oauth2/client:/client-credentials:ro depends_on: hydra: condition: service_started restart: "no" # ========================================================================= # Hydra — OAuth2 / OpenID Connect server # ========================================================================= hydra: image: oryd/hydra:v2.2 command: serve all --dev --config /etc/hydra/hydra.yml environment: DSN: "postgres://${HYDRA_DB_USER}:${HYDRA_DB_PASSWORD}@postgres:5432/${HYDRA_DB_NAME}?sslmode=disable" SECRETS_SYSTEM: "${HYDRA_SYSTEM_SECRET}" URLS_SELF_ISSUER: http://hydra:4444/ URLS_SELF_PUBLIC: http://hydra:4444/ depends_on: hydra-migrate: condition: service_completed_successfully restart: unless-stopped # ========================================================================= # Hydra Migrate — runs Hydra database migrations (one-shot) # ========================================================================= hydra-migrate: image: oryd/hydra:v2.2 command: migrate sql --yes "postgres://${HYDRA_DB_USER}:${HYDRA_DB_PASSWORD}@postgres:5432/${HYDRA_DB_NAME}?sslmode=disable" depends_on: postgres: condition: service_healthy restart: "no" # ========================================================================= # Redis — message streams for Diode ingester ↔ reconciler # ========================================================================= redis: image: redis/redis-stack-server:latest command: redis-server --requirepass "${REDIS_PASSWORD}" --appendonly yes ports: - "6378:6379" healthcheck: test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "ping"] start_period: 5s interval: 5s timeout: 3s retries: 5 volumes: - diode-redis-data:/data restart: unless-stopped # ========================================================================= # PostgreSQL — stores Diode + Hydra databases # ========================================================================= postgres: image: postgres:16-alpine environment: POSTGRES_USER: "${DIODE_DB_USER}" POSTGRES_PASSWORD: "${DIODE_DB_PASSWORD}" POSTGRES_DB: "${DIODE_DB_NAME}" healthcheck: test: ["CMD-SHELL", "pg_isready -U ${DIODE_DB_USER} -d ${DIODE_DB_NAME}"] start_period: 10s interval: 10s timeout: 5s retries: 5 volumes: - diode-postgres-data:/var/lib/postgresql/data - ./init-hydra-db.sh:/docker-entrypoint-initdb.d/init-hydra-db.sh:ro restart: unless-stopped # ========================================================================= # Orb Agent — network discovery (NMAP, SNMP, NAPALM) # ========================================================================= orb-agent: image: netboxlabs/orb-agent:latest network_mode: host volumes: - ./orb-agent/agent.yaml:/opt/orb/agent.yaml:ro depends_on: diode-ingester: condition: service_started diode-auth-bootstrap: condition: service_completed_successfully restart: unless-stopped volumes: diode-redis-data: driver: local diode-postgres-data: driver: local