You now have enough vocabulary to review one coherent application package: which files reach the builder, what the image starts, where the service listens, which configuration is public, where durable data goes and how shutdown is observed. The capstone turns those relationships into an accumulating audit rather than a set of unrelated yes/no flags.
The free graded task accepts real Dockerfile text, a selected file mapping and runtime settings. It recognizes a deliberately narrow teaching profile. A passing result means that those inputs satisfy that profile; it does not build an image, execute source code, run a Docker daemon, establish isolation or prove production readiness. Arbitrary Dockerfile syntax and malicious programs require different analysis.
Inspect the supplied application
The repository's projects/containers-deploy-lab/ includes a standard-library HTTP service, a health probe, Dockerfile, ignore file, example runtime JSON and an offline audit driver. The service reports a greeting, serves a health endpoint and writes a greeting record under /data when asked. It uses an exec-form entrypoint, a numeric non-root user and environment-driven port configuration. The optional local instructions make real tooling and volume permissions explicit.
The graded file mapping can contain harmless additional files, but the COPY profile permits only the two executable source files. That keeps source selection reviewable. The context denylist catches particular sensitive filenames and paths; it is not a secret scanner. A credential embedded in an innocent source file would not be discovered by this policy, and grading intentionally never supplies actual credentials.
Cross-check values, not just fields
A correct publishing object is still wrong for this application if its destination does not match the resolved PORT. A correct-looking entrypoint fails if COPY places the source under /application/ instead of /app/. A persistent mount is ineffective if the service writes somewhere else. A non-root image does not become privileged merely by being numeric, and a privileged runtime request materially changes the intended plan.
port = int({"PORT":"8123"}.get("PORT", "8000"))
expose = "8000"
published_destination = 8000
issues = []
if expose != str(port):
issues.append("port")
if published_destination != port:
issues.append("publish")
print(sorted(issues))Make the result useful to a reviewer
Accumulate independent issue codes in a set and sort at the end. Fixing a context defect should not require another submission merely to discover a known port mismatch. Reject wrong top-level input types with ValueError, but report malformed or absent policy fields through their documented issue codes. Parse JSON arrays with the standard library, keep strict boolean checks, and avoid accidental mutation while examining nested runtime mappings. The profile also fixes instruction order so setup happens before dropping the user and the image begins with FROM.
Before building, take the valid sample and change two independent boundaries at once. Predict both codes. Then replace a required file, move a COPY destination to a similar text prefix, and choose a shell-form entrypoint. The tests verify those distinctions and reject an implementation that simply accepts the sample.
Continue with real evidence
After the graded capstone, optional local practice can build the image, verify an HTTP response, write and recover volume data across replacement, and observe graceful stop. Those steps may require downloading an image and running a local daemon; the grader performs none of them. Never give the exercise a Docker socket or privileged container access. Real deployment adds image provenance, updates, permissions, resource limits, exposure policy, backups and operational review beyond this free course's measured outcome.