Skip to main content

Day-2 Docker Operations

Once an environment is running, you operate it with docker compose from its directory (/app/staging or /app/production). Every command shares the same anatomy, and two details trip people up if you skip them.

The command shape

VERSION=staging-latest docker compose -p staging --env-file .env -f deploy/docker-compose.prod.yml <cmd>

Two required pieces:

  • -p staging / -p production — the project flag. It gives each environment its own Docker network, which is what keeps two environments on one host from cross-connecting (without it they'd share a deploy_default network and one API could reach the other's Postgres). Always pass it.
  • VERSION=... prefix — compose needs it to resolve ${VERSION} in the image tags. Even for ps or logs, where the version is irrelevant, compose warns without it. Use VERSION=staging-latest (staging) or VERSION=v0.17.0 (production).

Everyday operations

  • See services: ... ps
  • Logs: ... logs api --tail 50 (add -f to stream)
  • Restart one service: ... restart api
  • Apply an .env change: ... stop api then ... up -d apinot restart. A plain restart reuses the existing container and won't pick up new env values.
  • Shell into a container: ... exec api sh
  • Connect to Postgres: ... exec postgres psql -U postgres -d circus — Postgres publishes no host port (it's reachable only over the Docker network), so exec is the way in, not psql -h localhost.
  • Resource usage: docker stats --no-stream
  • Pull + restart everything: export VERSION=... && ... pull && ... up -d

The nuclear option

... down -v stops everything and removes volumes — destroying the database. Reserve it for a deliberate clean slate (see Rollback & Environment Recovery); the next CI deploy rebuilds from the schema.