Chapter 42Lesson 03~250 minutes

Production Capstone: Build, Secure, Publish, Operate, Observe, and Recover a Complete Dockerized Application: Security, Governance, and Reliability Validation

Review the capstone as a production system: runtime authority, secrets, supply-chain evidence, networking, storage, observability, rollback, recovery objectives, exceptions, and operational readiness.

Security reviewGovernanceReliabilityReadinessExceptions

Learning objectives

  • Review the capstone through security, governance, reliability, recovery, observability, and operational-readiness lenses.
  • Verify each control against observable configuration/runtime evidence rather than assuming that configuration text is effective.
  • Separate accepted lab limitations from safer production alternatives, with owner, reason, evidence, and remediation path.
  • Re-check version-sensitive BuildKit/Compose/Engine/scanner/signing behavior and remove evergreen “latest” assumptions.
  • Create a readiness checklist that a second engineer can execute without hidden local knowledge.

1. Review the architecture as trust boundaries

The build client can influence source, build arguments, registry output, attestations, and cache; the Docker daemon controls runtime containers/networks/volumes; the registry stores image and attestation objects; the runtime secret source is a host file; and the application owns the SQLite data contract. A review must not collapse these into one “Docker security” box.

2. Supply-chain validation

Question Evidence Pass condition
Source bound? source.txt + provenance.json Recorded SHA appears in build metadata/labels or is otherwise linked to same build record
Base immutable? external-images.txt + provenance materials Base image reference is digest-pinned and visible in provenance/materials
Release immutable? subject.txt All policy decisions reference REPO@sha256:…
Platforms explicit? imagetools.txt Expected linux/amd64 and linux/arm64 manifests exist
SBOM attached? sbom.json SPDX content resolves from same subject
Provenance attached? provenance.json SLSA statement describes BuildKit build and materials
Scanner identity fresh enough? trivy-version + scan JSON metadata Version/database timestamp recorded; results treated as time-bounded
Signature verifies? signature-verify.json + cosign.pub Verifier checks the exact subject digest
Promotion same bytes? promotion.txt Alias digest equals subject digest

3. Runtime least-privilege review

APP_REF="$SUBJECT" docker compose -p ch42cap config > evidence/review-compose.yaml
APP_ID="$(APP_REF="$SUBJECT" docker compose -p ch42cap ps -q app)"
docker inspect "$APP_ID" --format '{{json .Config.User}} {{json .HostConfig.CapDrop}} {{json .HostConfig.SecurityOpt}} {{.HostConfig.ReadonlyRootfs}}'
docker inspect "$APP_ID" --format '{{json .Mounts}}'
docker port "$APP_ID"
docker network inspect ch42cap_frontend > evidence/review-frontend.json
docker network inspect ch42cap_ops > evidence/review-ops.json
Control Expected evidence Reason
Runtime user 10001:10001 Avoid root as application identity
Capabilities ALL dropped App requires no Linux capability grant
Privilege escalation no-new-privileges:true Blocks gaining more privileges through exec transitions
Root filesystem read-only Runtime mutation limited to declared writable mounts
Writable paths state volume + tmpfs only Makes side effects auditable
Host exposure 127.0.0.1:18080 only No LAN-wide publish in lab
Secret Mounted file, absent from image config Narrower runtime exposure than ENV
Observer No secret and ops-only network Companion gets only required connectivity

4. Secret and configuration governance

Check three independent questions: is the value absent from Git and the image; is it absent from docker inspect environment/config output; and is access limited to the app service? Then state the limitation: local Compose reads the fake secret from the host filesystem. Production should use an external secret system or orchestrator-backed secret mechanism appropriate to the environment, with rotation/audit controls beyond this lab.

git ls-files | grep -E 'secret|token' && exit 1 || true
docker image inspect "$SUBJECT" --format '{{json .Config.Env}}' > evidence/image-env.json
docker inspect "$APP_ID" --format '{{json .Config.Env}}' > evidence/container-env.json
grep -R 'ch42-fake-runtime-token-v1' evidence Dockerfile app.py compose.yaml config 2>/dev/null && echo 'review any hit carefully' || true

5. Network and publication governance

The app joins two networks because they serve different purposes. frontend enables the loopback publish path; ops is internal and connects the observer. Review actual endpoints rather than trusting YAML. A production deployment would normally terminate TLS and authentication at a trusted ingress/load balancer or application endpoint, with firewall/network policy outside this single-host lab.

6. Persistent-data and backup design review

The named volume is the state boundary. The app container is disposable; the SQLite database is not. Backup must therefore identify the volume, backup timestamp, source subject/config, application consistency method, archive digest, and restore target. The mandatory lab uses a controlled app stop before tar backup so SQLite is closed cleanly; production databases should use database-native backup/replication semantics appropriate to their engine.

7. Health, restart, shutdown, and availability

Mechanism What it proves What it does not prove
Process running PID still exists Application dependency readiness
Docker healthcheck Local /health contract succeeds External client path or SLA
restart: unless-stopped Process exits may be restarted Generic unhealthy status causes restart
stop_grace_period + SIGTERM Time is provided for graceful stop Application always flushes external dependencies correctly
Observer logs Ops-network probe reaches /health Public ingress path is reachable

Review docker compose ps, health history, app logs, and stop/recreate evidence. Never equate “Up” with end-to-end availability.

8. Resource and logging governance

docker inspect "$APP_ID" \
  --format 'Memory={{.HostConfig.Memory}} NanoCPUs={{.HostConfig.NanoCpus}} PidsLimit={{.HostConfig.PidsLimit}} Log={{json .HostConfig.LogConfig}}' | tee evidence/review-resources.txt
docker stats --no-stream "$APP_ID" | tee evidence/review-stats.txt

The configured envelope is not automatically the correct production envelope. It is a bounded lab policy. A production value needs workload measurements, headroom, host capacity, and SLO context. Likewise, local log rotation limits host growth but does not replace centralized retention, search, alerting, or tamper-resistant audit storage.

9. Rollback design

Rollback means choosing an earlier verified digest, not rebuilding an older tag. Preserve the previous subject and its signature/SBOM/provenance/scan evidence. Change APP_REF to the prior digest, render normalized Compose config, recreate only intended services, and verify both runtime digest and application/data behavior. Database schema compatibility must be reviewed separately: artifact rollback cannot magically reverse incompatible state migrations.

10. Compose versus orchestrator boundary

Single-host Compose proves External platform still needed for
Declarative services/networks/volumes/configs/secrets Multi-node scheduling and HA control plane
Digest-based local runtime contract Cluster admission/policy and rollout across nodes
Health/restart/resource/log settings Autoscaling and fleet-level capacity
Named-volume persistence and tested restore Distributed/managed storage and HA databases
Loopback publication Production ingress/TLS/global traffic management
Local evidence packet Central audit, metrics, traces, log retention

11. Accepted limitations register

Limitation Owner Why accepted in lab Safer production alternative
Plain HTTP loopback registry Platform owner Local disposable only TLS-authenticated HA registry
Local signing key Release owner Fake lab identity KMS/HSM or approved keyless identity/policy
Host-file Compose secret Application/platform owner Fake value only External secret manager/orchestrator secret
SQLite single volume Data owner Portable state/recovery teaching Managed/replicated database + native backup
Single host Platform owner Docker/Compose operating contract focus Kubernetes/OpenShift/Swarm/other orchestrator as required
No external TLS Network owner Loopback-only client path Trusted ingress and certificate automation
Local logs/stats SRE owner Bounded evidence only Central logs/metrics/traces + alerts

12. Operational readiness checklist

[ ] Active Docker context/endpoint documented
[ ] Engine/API/Compose/Buildx/BuildKit/scanner/signer versions recorded
[ ] Git source SHA clean and immutable
[ ] Base image digest recorded
[ ] Image index digest and expected platforms verified
[ ] SBOM/provenance extracted from subject digest
[ ] Vulnerability scan timestamp/version recorded and triaged
[ ] Signature verifies against expected identity/key
[ ] Promotion alias digest equals release subject
[ ] Normalized Compose config archived
[ ] Runtime user/capabilities/read-only/security options verified
[ ] Secret absent from Git/image/env evidence
[ ] Network endpoints and host publication verified
[ ] Named volume identified and writable owner verified
[ ] Health, restart, shutdown and resource limits tested
[ ] Log rotation configured and logs retrievable
[ ] Backup archive checksum captured
[ ] Restore into a new volume tested
[ ] Rollback digest retained and procedure documented
[ ] Incident entry commands preserve first-failure evidence
[ ] Cleanup list contains only exact ch42 identities
[ ] Accepted limitations have owner + safer production alternative

13. Version-sensitive revalidation

Before using this capstone later, re-check Engine release notes, Buildx/BuildKit attestation behavior, Compose schema fields, scanner database/tool versions, and Cosign CLI behavior. The evidence packet should make version drift obvious. Avoid “latest” as an operational requirement; use human-readable release identity plus captured actual version/digest.

Knowledge check

Why is a verified signature not enough to approve a release?

Why is read_only rootfs not equivalent to statelessness?

What does a Docker healthcheck fail to prove?

Why can image rollback be unsafe even when the old digest is verified?

What is the main governance limitation of local Compose secrets in this lab?

Next lesson

Next: Production Capstone: Build, Secure, Publish, Operate, Observe, and Recover a Complete Dockerized Application: Failure Injection, Troubleshooting, and Recovery Drill

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.