Skip to content

Docker Service Management

Caroline runs 37 containers organized across 5 compose stacks. Every container uses restart: unless-stopped. CPU and memory limits are enforced via docker-compose.pi.yml overrides on every container.

Compose fileContainersPurpose
docker-compose.yml + docker-compose.pi.ymlpostgres, n8n, caddy, authelia, redis, cloudflared, waha, mcp-auth-, mcp-proxy-Core foundation
docker-compose.dashboard.ymldashboard-api, dashboard-nginx, docker-socket-proxyWeb dashboard
grafana/docker-compose.grafana.ymlgrafana, loki, prometheus, tempo, alloy, node-exporter, cadvisor, postgres-exporter, unpoller, blackbox-exporter, otel-collector, docker-socket-proxy-grafanaObservability
pi/docker-compose.ha.ymlhomeassistant, wyoming-whisper, wyoming-piper, wyoming-openwakeword, esphomeHome automation and voice
docker-compose.discord.ymldiscord-botDiscord bot

The Pi compose file (docker-compose.pi.yml) is an overlay that adds memory and CPU limits for the ARM environment. It is always passed with the core stack: docker compose -f docker-compose.yml -f docker-compose.pi.yml.

The Makefile abstracts these compose file combinations. Use Make targets rather than raw compose commands to avoid applying the wrong file set.

All containers on Caroline have explicit limits. Representative examples:

ServiceMemory limitCPU limit
postgres6 GB2.0
n8n2560 MB1.0
homeassistant1536 MB2.0
mcp-proxy-memory1 GB0.5
grafana1 GB1.0
prometheus2 GB1.0
dashboard-api512 MB0.5
caddy512 MB0.5
redis256 MB0.25
blackbox-exporter64 MB0.1

Limits are not optional. Caroline has 16 GB RAM total. Without limits, a single runaway container can OOM the entire host.

Terminal window
make pi-status # All containers on Caroline
make status # Local Mac containers
Terminal window
make pi-logs # All containers (tail -f)
make logs # Local Mac
make logs-n8n # n8n only (local)
make logs-postgres # Postgres only (local)
make logs-caddy # Caddy only (local)
make logs-mcp # MCP proxy + auth + tunnel (local)

For a specific container on Caroline:

Terminal window
make pi-shell
docker logs chris-os-n8n --tail 100 -f
Terminal window
make pi-restart # All services on Caroline
make ha-restart # Home Assistant only
make ha-up / ha-down # HA start/stop
make voice-up / voice-down # Voice pipeline
make dashboard-pi-up / dashboard-pi-down
make grafana-up / grafana-down

The dashboard is built from source, not pulled from a registry. Use the 5-step build:

Terminal window
make dashboard-pi-build

This: generates commit-cache.json from git log, rsyncs dashboard/ to Caroline, rsyncs ha-config/ to Caroline, runs docker build --no-cache, runs docker compose up -d, and verifies the version after deploy.

Terminal window
make pi-shell
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.RunningFor}}"

A container in Up X minutes (healthy) is passing its healthcheck. Up X minutes (unhealthy) means the healthcheck is failing. Check logs immediately.

Terminal window
make caddy-reload # Reload Caddyfile without restart (local)
make pi-shell
docker exec chris-os-caddy caddy reload --config /etc/caddy/Caddyfile

Five isolated bridge networks separate service tiers:

NetworkWhat’s on it
net-datapostgres, redis, n8n, authelia, mcp-proxy-{postgres,memory}, grafana, dashboard-api
net-appn8n, authelia, waha, caddy, mcp-proxy-n8n, discord-bot
net-mcpcaddy, cloudflared, all mcp-proxy and mcp-auth containers
net-frontendcaddy, dashboard-{api,nginx}, grafana, prometheus
net-monitoringgrafana, loki, prometheus, tempo, alloy, all exporters

Home Assistant and ESPHome use network_mode: host for mDNS and Bluetooth. The voice containers (wyoming-*) use the pi_default bridge network with published ports to loopback, reachable by the host-networked HA via localhost.

Pinned versions on all images — no :latest tags except where arm64 compatibility requires it. When updating an image version:

  1. Update the version in the compose file.
  2. Test locally if possible.
  3. Push to main; the deploy pipeline pulls and recreates the container.

GitOps convergence also detects image drift for pulled-image services and auto-recreates containers running stale versions.

Pulled-image services (auto-recreated by GitOps on drift): postgres, redis, authelia, cloudflared, waha, n8n, caddy, grafana, loki, prometheus.

Build-from-source services (reported but not auto-recreated): mcp-auth-, mcp-proxy-, dashboard-api, dashboard-nginx.