Chapter 42Lesson 01~240 minutes

Production Capstone: Build, Secure, Publish, Operate, Observe, and Recover a Complete Dockerized Application: Requirements, Constraints, and Target Architecture

Define the final Docker capstone requirements, threat model, trust boundaries, recovery objectives, evidence contract, and executable production-like architecture before building anything.

CapstoneRequirementsThreat modelArchitectureEvidence

Learning objectives

  • Define a final capstone as an auditable delivery system rather than “a Compose file that starts.”
  • Freeze requirements, threat assumptions, trust boundaries, recovery objectives, version assumptions, and cleanup scope before implementation.
  • Design one synthetic application that exercises immutable builds, a local registry, multi-platform metadata, persistent data, secrets/configs, health, resources, logging, and recovery.
  • Create a requirements-to-evidence matrix that ties each production claim to an observable Docker/registry/application artifact.
  • Separate what this single-host Compose capstone proves from what still belongs to an external orchestrator, secret manager, HA data service, or enterprise control plane.

1. Capstone mission: prove the delivery system, not just the container

The final chapter integrates the course into one reviewable system. The target is a small HTTP application whose source is committed, whose base image is resolved to a digest, whose release is built once as a multi-platform image index, whose SBOM/provenance and signature are bound to the release digest, whose runtime is deployed by digest, whose state survives container replacement, and whose failure/restore behavior is measurable.

Success means another engineer can independently answer: what source produced these bytes, who/what built them, what software is inside, what identity is running, where state and secrets live, which ports and networks exist, how health/resource/log contracts are configured, what backup was restored, and which exact evidence proves each claim?

2. Constraints and excluded dependencies

Constraint Capstone decision Reason
No paid/cloud dependency All mandatory work runs on an authorized local Docker host Keeps the lab reproducible and reviewable
No real credentials Use a fake runtime token and local test signing key Avoids secret disclosure and external account dependence
No production daemon mutation Local registry binds only to 127.0.0.1; BuildKit HTTP registry trust is scoped to a disposable builder Avoids global insecure-registry or daemon changes
No privileged helper Dockerfile contains no target-platform RUN step; multi-platform build does not require installing QEMU in this lab Preserves least privilege
No mutable-only release Deployment uses registry digest; tags are aliases/evidence only Prevents promotion drift
No state in writable layer SQLite database lives on a named volume Makes replacement/backup semantics explicit
No broad cleanup Every object has ch42 names/labels and is removed explicitly Protects unrelated Docker resources
Single-host scope Compose is the production-like runtime; HA scheduling is documented as an external-orchestrator boundary Avoids pretending a laptop is a cluster

3. Synthetic application

The app is deliberately small: Python standard library HTTP + SQLite, with no pip packages. GET /health reports process/data readiness, GET / returns the greeting and current counter, and authenticated POST /increment mutates the SQLite counter using a fake token mounted as a runtime secret. A marker file in the state volume can intentionally make health fail for the incident drill.

The container runs as numeric UID/GID 10001, uses a read-only root filesystem, writes only to /data and /tmp, drops all Linux capabilities, enables no-new-privileges, publishes only to loopback, rotates local logs, and has explicit CPU/memory/PID limits. A companion observer can reach the app only over an operations network and records health without receiving the app secret.

4. Target architecture and trust flow

Source-to-runtime control and evidence flow
flowchart TD
  S[Git source SHA + pinned base digest] --> B[Disposable Buildx / BuildKit builder]
  B --> I[Multi-platform image index digest]
  B --> A[SBOM + SLSA provenance]
  I --> R[127.0.0.1 local registry]
  A --> R
  R --> V[Scan + signature verification]
  V --> P[Release alias points to same digest]
  P --> C[Compose deploys immutable digest]
  C --> N[frontend + ops networks]
  C --> D[named data volume]
  C --> Q[config + fake runtime secret]
  C --> O[health + bounded logs + resources]
  D --> BK[backup checksum]
  C --> F[failure drills]
  BK --> RR[restore volume + recovery verification]
  RR --> H[handoff evidence packet]
            

The important causal boundary is that the registry digest is the release subject. SBOM, provenance, signature, deployment, rollback, scan results, and incident notes all point back to that immutable subject. A tag can help humans find it, but a tag is never the final identity.

5. Threat model

Threat / mistake Control in capstone Residual limit
Build from drifting source/base Git SHA + base image index digest + recorded builder/tool versions Upstream package repositories are not used during build because the Dockerfile has no RUN step
Secret leaks into image/history Runtime file secret only; no secret ARG/ENV/COPY Local Compose secret source file still exists on the host and is not encrypted at rest
Root/container mutation UID 10001, read-only rootfs, cap_drop ALL, no-new-privileges Shared host kernel remains a trust boundary
Tag race / rebuild-on-promotion Deploy/sign/promote exact digest Local test registry itself is not HA
Data loss on container replace Named volume + backup + restore drill SQLite single-host model is not a replicated production database
Unbounded resource/log growth CPU/memory/PID limits + local driver rotation Host capacity planning/central observability remains external
Network overexposure Loopback host publish + separate ops network No external TLS/load balancer in mandatory lab
Evidence erased during incident Capture IDs/digests/logs/events before repair Long-term evidence storage is outside the lab

6. Recovery objectives

Set explicit learning objectives rather than invented enterprise guarantees. The lab target is RPO = backup point: writes after the archive timestamp may be lost. The target RTO is measured, not promised: start a timer before restore-volume creation and stop it only after the recovered app returns the expected persisted counter from the same release digest. Record host and workload conditions so the timing is not presented as universal.

7. Requirements-to-evidence matrix

Requirement Primary evidence Independent verification
Exact source Git commit SHA + clean status git rev-parse HEAD; git status --porcelain
Pinned build input Python base image index digest imagetools inspect base; Dockerfile/metadata evidence
Reproducible builder identity Buildx/BuildKit version + builder inspect docker buildx version; docker buildx inspect --bootstrap
Multi-platform release Registry image-index digest + platform manifests docker buildx imagetools inspect SUBJECT
SBOM/provenance SPDX/SLSA JSON extracted from the release subject imagetools inspect --format .SBOM/.Provenance
Vulnerability status Trivy version, DB timestamp/output bound to subject trivy version + JSON result
Signature identity Cosign public key + verify output cosign verify --key ... SUBJECT
Promotion without rebuild build tag digest == release alias digest compare imagetools Digest lines
Normalized runtime contract docker compose config output review service/user/mount/network/resource/security fields
Runtime identity container ID, image digest, user/security/mount/network inspect docker inspect + compose ps
Persistent state named volume ID + counter value before/after replacement volume inspect + API response
Backup/restore archive SHA-256 + restored counter + recovery timing sha256sum + recovered endpoint
Observability health, logs, events, stats sample compose ps; logs; docker events; docker stats --no-stream
Cleanup boundary pre/post labeled-object inventory filters by exact names/labels; no prune

8. Version and platform freeze

Before implementation, capture actual local versions. The course reference baseline is Engine 29.8.1, BuildKit 0.33.0, Buildx 0.37.1, Compose 5.5.1, Trivy 0.74.0, and Cosign 3.1.3. Do not silently substitute these for what your machine runs.

mkdir -p evidence
{
  date -u +%Y-%m-%dT%H:%M:%SZ
  docker context show
  docker version
  docker info
  docker compose version
  docker buildx version
  trivy --version 2>/dev/null || true
  cosign version 2>/dev/null || true
} > evidence/toolchain.txt

9. Clean-room object namespace

All generated Docker state uses the ch42 prefix or Compose project ch42cap. The registry is 127.0.0.1:5000, the Buildx builder is ch42-builder, registry storage is ch42_registry_data, application state is ch42cap_state, and restore state is ch42_state_restore. This is not cosmetic: cleanup and incident commands can select exact identities.

10. Production boundaries not simulated away

This lab does not claim to provide HA scheduling, external TLS, managed KMS/HSM signing, centralized log/metric retention, multi-node databases, enterprise identity, admission control, or cross-region backups. The handoff must name those gaps and map them to Kubernetes/Helm/OpenShift, an external secret manager, a managed/HA registry, a real observability platform, and production backup infrastructure where appropriate.

11. Go/no-go gate before implementation

Safety boundary. Do not proceed if the current Docker context targets a shared/production daemon, if the local registry port is already owned by another service, or if the learner cannot distinguish the lab’s fake credentials from real credentials.
Gate Go condition
Context Named/inspected authorized local daemon
Port 5000 Available for loopback-only local registry
Disk Enough space for two platform manifests, registry data, scan DB, and backup archive
Tools Docker/Compose/Buildx available; Trivy/Cosign installed from reviewed upstream releases for full capstone
Platforms Builder reports linux/amd64 and linux/arm64 metadata build support; no privileged binfmt install is required by this Dockerfile
Cleanup All planned mutations map to exact ch42 identities

12. What Lesson 1 freezes

The architecture, evidence matrix, threat assumptions, RPO/RTO interpretation, object namespace, and excluded production dependencies now exist before any release is built. Lesson 2 implements this contract and captures evidence after every major transition rather than reconstructing history at the end.

Knowledge check

Why is the registry digest the primary release identity instead of release-1?

Why can local Compose secrets satisfy the learning goal but not prove encrypted-at-rest secret management?

Why does this capstone avoid RUN instructions in the Dockerfile?

What does RPO = backup point mean?

A container is healthy and the digest is correct. Is the production contract fully proven?

Next lesson

Next: Production Capstone: Build, Secure, Publish, Operate, Observe, and Recover a Complete Dockerized Application: Implementation and Automation Build-Out

Continue with the next lesson in the course sequence and carry forward the evidence-first Docker operating model.

Official references and version notes

Baseline checked:

2026-09-22. The capstone records the learner’s actual versions before execution. Reference baselines used for compatibility discussion are Docker Engine/CLI 29.8.1, BuildKit 0.33.0, Buildx 0.37.1, Docker Compose 5.5.1, Trivy 0.74.0, and Cosign 3.1.3. Packaged Docker Desktop/Engine installations may expose different bundled containerd/runc versions, so the evidence packet records what the active daemon actually reports.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.