Docker
Project-specific containerization patterns for Dockerfile and Docker Compose.
Architecture Decisions
Image Building
- Minimal base images — Use slim/alpine variants; pin to digest for reproducibility.
- Multi-stage builds — Separate build dependencies from runtime.
- Layer optimization — Combine RUN commands; place frequently changed files last.
- COPY over ADD — ADD only for tar extraction or remote URLs.
Security
- Non-root users — Always use UID >10000; never run as root in production.
- No secrets in images — Use Docker secrets or runtime env injection.
- .dockerignore required — Exclude .git, .env, node_modules, build artifacts.
Runtime
- One process per container — Single responsibility principle.
- Healthchecks required — Define HEALTHCHECK in Dockerfile or Compose.
- Resource limits — Always set mem_limit and cpus in production.
Compose
- Network segmentation — Dedicated networks per service group.
- Named volumes — Never use anonymous volumes in production.
- depends_on with healthchecks — Use
condition: service_healthy. - Environment separation — Use override files for dev/staging/prod.
Gotchas
COPY . .beforeRUN npm installbusts the cache on EVERY code change. Copypackage*.jsonfirst, install, THEN copy source.- Alpine uses musl libc, not glibc. Python packages with C extensions (numpy, pandas, cryptography) may fail to install or need
apk addbuild dependencies. Consider-slimvariants if you hit this. ENTRYPOINT ["python", "app.py"](exec form) handles signals correctly.ENTRYPOINT python app.py(shell form) wraps in/bin/sh -cand PID 1 won't receive SIGTERM — containers take 10s to stop.- Docker layer cache is invalidated from the FIRST changed layer downward. A changed
COPYnear the top rebuilds everything below it. depends_onwithoutcondition: service_healthyonly waits for container START, not readiness. Your app will crash connecting to a database that's still initializing.host.docker.internalworks on Docker Desktop (Mac/Windows) but NOT on Linux. Use--network hostor explicit container networking on Linux.- Build args (
ARG) are NOT available afterFROMin multi-stage builds unless re-declared. Each stage starts fresh. docker compose upreuses existing containers. After changingDockerfile, you needdocker compose up --buildordocker compose buildfirst.- Volume mounts override the container's filesystem — if your
node_modulesare built inside the container but you mount.:/app, the host's (possibly empty)node_modulesshadows them. Use a named volume fornode_modules. EXPOSEis documentation only — it does NOT publish the port. You still need-p 8080:8080orports:in compose.- Docker's default bridge network does NOT provide DNS resolution between containers. Use a custom network or compose's default network.
References
| When you need... | Read |
|---|---|
| Dockerfile patterns, CMD vs ENTRYPOINT | dockerfile.md |
| Compose services, networks, volumes | compose.md |
| Security hardening | security.md |
| Production deployment | production.md |