Container Fundamentals Best Practices
This is a working list of container fundamentals that hold up in production, aimed at tech leads setting defaults for a team.
Search across all documentation pages
This is a working list of container fundamentals that hold up in production, aimed at tech leads setting defaults for a team.
The theme is simple: one concern per container, immutable artifacts, least privilege, and resources declared explicitly.
Treat these as defaults, not laws - adopt them wholesale, then document each deliberate exception in an ADR.
Group A covers process shape, B covers image hygiene, C covers security posture, D covers resources and health, and E covers the runtime boundary.
Wire the checkable items into CI (linting, scanning, policy) so they hold without relying on memory.
SIGTERM for graceful shutdown and use an init shim (--init or tini) when your app spawns children, so signals and zombies are handled correctly.image@sha256:... (or an immutable semantic tag) so builds are reproducible and cannot silently change under you.RUN steps so the cache survives code-only changes.amd64 and arm64 so the same tag runs on Graviton and x86 without exec format error.USER in the image and runAsNonRoot: true in the pod so a compromise does not start as root inside the container.drop: ["ALL"] and grant specific capabilities explicitly; almost no app needs the default set.readOnlyRootFilesystem: true and mount an emptyDir for the few writable paths, so tampering and drift are blocked.allowPrivilegeEscalation: false and use the RuntimeDefault seccomp profile to shrink the syscall attack surface.restricted so insecure pod specs are rejected at admission, not discovered later./proc often still reports host CPUs and memory.You should be able to point at CI gates for image scanning, signing, and non-root/restricted policy, not just documentation.
Every running container should have a single clear concern, explicit resources, probes, and an immutable, digest-pinned image.
Any deviation - a multi-process container, a missing limit, an elevated capability - should have a written, reviewed reason.
Is one process per container a hard rule? It is a strong default, not dogma; sidecars and rare supervised apps are fine when justified and documented with a real init.
Requests or limits - which matters more? Requests drive scheduling and are almost always worth setting; memory limits protect the node, while CPU limits should be used sparingly to avoid throttling.
Why non-root if the container is isolated? Isolation is not a hard boundary, so non-root plus dropped capabilities limits the damage if the process is compromised or escapes.
Do these apply to Docker Compose dev setups too? Many do (non-root, pinned bases, one concern), but the security and resource controls are enforced by Kubernetes in production, not Compose.
How do I enforce this without nagging? Push checks into CI and admission control - scanning, signing, and the restricted Pod Security Standard - so violations are blocked automatically.
Stack versions: This page was written for Kubernetes 1.36.2, Docker Engine 29.6.1 (BuildKit default), containerd (CRI runtime on nodes), Helm 3, Compose v2, Argo CD (latest - verify at build), and Gateway API (GA - verify controller support at build).
Reviewed by Chris St. John·Last updated Jul 16, 2026