CI, Deployment and Orchestration
Build one immutable image per commit, test it, promote the same digest through every environment, and run it as a stateless, disposable process with config injected at run time.
Key points
- 1
Tag CI images with the commit SHA (for example via docker/metadata-action) and deploy by that tag or, better, by digest; mutable tags like
latestdrift between deploys. - 2
Build once, test that image, and promote the same digest to staging and production; per-environment builds ship untested bytes and make rollbacks rebuilds.
- 3
Give Buildx a persistent cache in CI (
cache-from/cache-towithtype=ghaor a registry) because each hosted runner starts empty. - 4
Graceful shutdown: stop routing traffic, deliver SIGTERM to the real app process (exec-form CMD or an init), drain in-flight work, exit before the grace period (10 seconds by default) ends in SIGKILL.
- 5
Run database migrations once per release as a separate step or job, not in every replica's startup command.
- 6
Language specifics:
npm cifor reproducible Node installs (watch NODE_ENV omitting devDependencies),PYTHONUNBUFFERED=1for Python logs, static Go binaries withCGO_ENABLED=0for scratch images, and JVM heaps sized below the container limit. - 7
Managed platforms like Cloud Run expect the app to listen on
$PORT, keep no local state, and may throttle CPU outside requests.
Common traps
A HEALTHCHECK on standalone Docker only reports status; it doesn't restart containers or gate traffic.
The json-file logging driver doesn't rotate by default, so busy containers can fill the host disk.
Swarm rolling updates default to
stop-first, which leaves a single-replica service briefly with nothing running.
Read the source
Test yourself on CI, Deployment and Orchestration
Ten questions, with the answer and explanation after each one.