# Container Production Review

> Fill this in for any image that will run in production. Most container incidents trace back to
> one of five things: running as root, secrets baked into layers, a base image nobody updates,
> no health check, or a process that ignores shutdown signals. This page is those five plus the
> detail around them.

**Image:** _______________
**Owner (person):** _______________
**Date:** _______  **Registry:** _______________

## 1. Base image

| | |
|---|---|
| Base image and tag | |
| **Pinned by digest** | yes / no |
| Why this base (not the default) | |
| Size | |
| Who rebuilds it when the base is patched | |
| Rebuild cadence | |

🔴 `:latest` in production means the image you deploy on Friday is not the one you tested on
Tuesday. Pin by digest, and own the update path deliberately — pinning without a rebuild schedule
trades unpredictability for permanent staleness.

## 2. Build

| | |
|---|---|
| Multi-stage build | yes / no |
| Build tools present in the final image | yes / no — which |
| Layer order optimised (dependencies before source) | yes / no |
| `.dockerignore` present | yes / no |
| Final image size | |
| Reproducible from a clean checkout | yes / no |

**Anything in the final image that is not needed to run the application:** _______________

Compilers, package managers and shells left in a runtime image are attack surface and download
time. Everything in the image is something you now maintain.

## 3. Secrets

- [ ] No secrets in the Dockerfile
- [ ] No secrets in build arguments
- [ ] No secrets in any layer, including deleted files
- [ ] No `.env`, `.git`, key material or cloud credentials copied in
- [ ] Secrets injected at runtime from _______________

🔴 A file added in one layer and deleted in the next is still in the image. `docker history` and
a layer inspection will find it, and so will anyone who pulls the image. If a secret was ever
built into a published image, rotate it — deleting the image is not sufficient.

## 4. Runtime user and permissions

| | |
|---|---|
| Runs as user | root / _____ (uid) |
| Filesystem read-only | yes / no |
| Writable paths required | |
| Capabilities dropped | |
| Privileged mode | yes / no — why |
| Host paths mounted | |
| Host network / PID namespace used | yes / no |

**Running as root is the default and almost never necessary.** Create a user in the Dockerfile,
give it ownership of only what it needs, and switch to it before the entrypoint.

## 5. Process behaviour

| | |
|---|---|
| PID 1 is the application, not a shell | yes / no |
| **SIGTERM handled — graceful shutdown** | yes / no |
| Shutdown grace period needed | |
| In-flight work finished or requeued on shutdown | |
| Restart policy | |

A container that ignores SIGTERM is killed after the grace period. Under a rolling deploy that
means dropped requests or half-finished jobs on every release — a defect that only appears in
production, and only under load.

## 6. Health and observability

| | |
|---|---|
| Liveness check | |
| Readiness check (distinct from liveness) | |
| **Readiness actually checks dependencies** | yes / no |
| Logs to stdout/stderr, not files | yes / no |
| Log format | |
| Metrics exposed | |

Liveness answers "should this be restarted"; readiness answers "should this receive traffic".
Wiring the same endpoint to both causes a restart loop the moment a dependency is briefly slow.

## 7. Resources

| | Request | Limit |
|---|---|---|
| CPU | | |
| Memory | | |

**Memory limit set from measurement, not a guess:** yes / no
**What the application does when it hits the limit:** _______________
(Usually: killed abruptly. If the runtime has its own heap setting, it must be told about the
container limit or it will size itself against the host.)

## 8. Vulnerabilities

| | |
|---|---|
| Image scanned on build | yes / no — tool |
| Scan result: critical ___ high ___ | |
| Accepted findings, with reasons | |
| Who reviews scan results, and when | |
| Base image rebuild triggers a rescan | yes / no |

Record the accepted risk explicitly. A scan whose output nobody reads is a build step, not a
control.

## 9. Sign-off

| | Name | Date |
|---|---|---|
| Built by | | |
| Security review | | |
| Approved for production | | |
