# Docker Compose Patterns — CLAUDE.md Parent: [../CLAUDE.md](../CLAUDE.md) ## Overview All services run via Docker Compose on Ubuntu 24. The base `docker-compose.yml` defines the core stack. Project-specific overrides go in `docker-compose.override.yml`. ## Core Services ### Ignition Gateway ```yaml ignition: image: inductiveautomation/ignition:8.3.X ports: - "8088:8088" # HTTP gateway - "8043:8043" # HTTPS gateway - "62541:62541" # OPC-UA volumes: - ignition-data:/usr/local/bin/ignition/data - ./config/ignition/gateway.xml:/usr/local/bin/ignition/data/gateway.xml - ../ignition/project:/usr/local/bin/ignition/data/projects/framework environment: ACCEPT_IGNITION_EULA: "Y" GATEWAY_ADMIN_PASSWORD: "${IGNITION_ADMIN_PASSWORD}" IGNITION_EDITION: standard restart: unless-stopped ``` ### PostgreSQL ```yaml postgres: image: postgres:16-alpine volumes: - postgres-data:/var/lib/postgresql/data - ./config/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql environment: POSTGRES_DB: ignition POSTGRES_USER: ignition POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}" restart: unless-stopped ``` ### Traefik (Reverse Proxy) ```yaml traefik: image: traefik:v3 ports: - "80:80" - "443:443" - "8080:8080" # Traefik dashboard volumes: - /var/run/docker.sock:/var/run/docker.sock:ro - ./config/traefik:/etc/traefik restart: unless-stopped ``` ### Modbus Simulator (Template) One container per simulated device or device group. Use `docker-compose.override.yml` to add project-specific simulators. ```yaml modbus-sim-pumps: image: oitc/modbus-server:latest ports: - "5020:5020" volumes: - ./config/modbus/pumps.json:/app/config.json restart: unless-stopped ``` ## Rules ### Volume Management - **Named volumes** (`ignition-data`, `postgres-data`) persist across restarts. - **Never run `docker compose down -v`** — this destroys named volumes. - **Never run `docker compose down`** without explicit user confirmation. - Use `docker compose stop` to halt services without removing containers. - Use `docker compose restart ` for individual service restarts. ### Networking - All services share the default compose network. - Ignition connects to Modbus sims via container name (e.g., `modbus-sim-pumps:5020`). - Ignition connects to PostgreSQL via `postgres:5432`. - External access to WebDev API goes through Traefik or direct port mapping. ### Configuration Files - Gateway backup/restore: mount `gateway.xml` for initial config only. - Modbus configs: JSON files in `config/modbus/`, one per simulator. - PostgreSQL init: `config/postgres/init.sql` runs on first start only. ### Adding a New Modbus Simulator 1. Create config file: `config/modbus/.json` 2. Add service to `docker-compose.override.yml` 3. Assign unique port (start at 5020, increment by 1) 4. Add OPC-UA connection in Ignition config 5. Verify: `curl -s localhost:` or test from Ignition ### Environment Variables Store secrets in `.env` (gitignored): ``` IGNITION_ADMIN_PASSWORD=changeme POSTGRES_PASSWORD=changeme ``` Never hardcode credentials in compose files or configs. ### Health Checks ```yaml ignition: healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8088/StatusPing"] interval: 30s timeout: 10s retries: 5 ``` ## File Structure ``` docker/ ├── CLAUDE.md ← you are here ├── docker-compose.yml ← base stack (do not modify per-project) ├── docker-compose.override.yml ← project-specific additions ├── .env ← secrets (gitignored) └── config/ ├── ignition/ │ └── gateway.xml ├── postgres/ │ └── init.sql ├── traefik/ │ ├── traefik.yml │ └── dynamic/ └── modbus/ └── (device-group configs) ```