# Container Image and Runtime Checklist

**Image / service:** _______________  **Date:** _______

## 1. Base image

- [ ] **Pinned by digest**, not by tag — a tag moves, a digest does not
- [ ] Minimal base chosen deliberately (distroless, slim, alpine) with the reason recorded
- [ ] Base image comes from a source you would name in an audit
- [ ] Base updated on a schedule, not when something breaks
- [ ] **Not `latest`** anywhere in the file

> An image built from `FROM node:latest` is a different image every week. The version running
> is not the version anyone approved.

## 2. Build

- [ ] **Multi-stage build** — build tools do not reach the final image
- [ ] Dependency install is its own layer, before the source copy, so the cache survives a code
      change
- [ ] `.dockerignore` present — `.git`, `node_modules`, secrets, test fixtures
- [ ] Build is reproducible: same inputs, same image
- [ ] No `apt-get upgrade` in the build — upgrade the base instead, or the image drifts
- [ ] Package lists cleaned in the same layer they were created

## 3. Secrets — what must never be in an image

- [ ] **No credentials in `ENV`, `ARG`, or any layer** — layers are readable by anyone with the
      image, including deleted files
- [ ] No `.env` file copied in
- [ ] No private keys, certificates or tokens
- [ ] No `.git` directory
- [ ] Build-time secrets use the build secret mount, not `ARG`
- [ ] Image scanned for secrets in the pipeline

> A secret added in one layer and deleted in the next is still in the image. Deletion adds a
> layer; it does not remove one.

## 4. Runtime identity and filesystem

- [ ] **Runs as a non-root user**, created in the image
- [ ] `USER` set — the default is root and the default is wrong
- [ ] **Read-only root filesystem**, with writable volumes only where needed
- [ ] No `--privileged`
- [ ] Capabilities dropped, then added back only if required
- [ ] `no-new-privileges` set

## 5. Size and layers

- [ ] Final image size recorded and justified
- [ ] Nothing installed that is not needed at runtime — no compilers, no shells you do not use
- [ ] Layers ordered least-changing to most-changing
- [ ] Image inspected once by hand — you know what is in it

## 6. Configuration

- [ ] Configuration from environment or a mounted file, never baked in
- [ ] The same image runs in every environment
- [ ] Sensible defaults, with required values failing loudly at startup rather than defaulting
      to something wrong

## 7. Process behaviour

- [ ] **One process concern per container**
- [ ] Process runs in the foreground, PID 1 handles signals, or an init is used
- [ ] **Responds to SIGTERM** and shuts down cleanly within the grace period
- [ ] In-flight work is finished or handed back on shutdown
- [ ] Logs to stdout and stderr, not to files inside the container

> A container that ignores SIGTERM is killed after the grace period. Every rolling update then
> drops whatever it was doing.

## 8. Health and resources

- [ ] **Readiness check** — can it serve right now?
- [ ] **Liveness check** — the process only, never a dependency
- [ ] Memory limit set, from measurement
- [ ] CPU request set, from measurement
- [ ] Behaviour under the memory limit understood — a runtime that does not see the limit will
      exceed it

## 9. Supply chain

- [ ] Image scanned for known vulnerabilities in the pipeline, and the result blocks
- [ ] Dependency manifest committed and reviewed
- [ ] Image signed, or its digest recorded in the deployment record
- [ ] Registry access controlled and audited
- [ ] Retention policy on old images — registries grow without limit

## 10. The traps

- [ ] Not treating the container as a small server — no SSH, no cron inside, no manual fixes
- [ ] **No state on the container filesystem** — it is gone on restart
- [ ] Not running as root because it was easier
- [ ] Not copying the whole build context because `.dockerignore` was skipped
- [ ] Not using the same image with an environment variable that changes behaviour dangerously

## Sign-off

| | Name | Date |
|---|---|---|
| Built by | | |
| Reviewed by | | |
