Docker in CI/CD
๐ Docker in CI/CD
pipelines1-6 already built and pushed a Docker image as part of a CI pipeline. This chapter reviews that material, goes deeper on registry mechanics, and formalizes a real tagging strategy โ while folding in everything this course has covered since: multi-stage builds (Ch.1), optimized caching (Ch.2), and vulnerability scanning (Ch.6).
Recap: pipelines1-6's Docker-in-CI Chapter
pipelines1-6 established the core shape: build an image tagged with the commit SHA, push it to a registry, and gate that job on the test suite already passing โ "no image without passing tests." This chapter builds on exactly that foundation.
Container Registries
A registry is where built images actually live โ Docker Hub is the public default, but production systems commonly use a private registry (a cloud provider's own, or a self-hosted one like Harbor). docker login authenticates; docker push/docker pull move images in and out.
Registry credentials are themselves secrets โ the exact same discipline Chapter 6 established for never baking a credential into an image applies just as much to the credentials used to push that image: read from CI secrets at runtime, never hardcoded into a pipeline config file.
Tagging Strategy
pipelines1-6's commit-SHA tagging is immutable and traceable โ that exact tag always points to that exact commit, forever. A complete tagging strategy layers a few tag types together:
| Tag Type | Purpose | Mutable? |
|---|---|---|
Commit SHA (e.g. a1b2c3d) | Exact traceability to one commit | No โ immutable |
Semantic version (e.g. v1.2.3) | Marks a real release | No โ should never be reused |
latest | Convenience pointer to "the newest build" | Yes โ and that's the problem |
latest vs. an Immutable SHA Tag
latest
Mutable and ambiguous โ any subsequent push to latest, from any branch, silently changes what that tag points to.
Commit SHA
Permanently tied to one exact commit โ pulling it a year from now returns exactly the same image, every time.
Putting It Together: A Full CI Build/Push Step
๐ป Coding Challenges
Challenge 1: Write a Multi-Tag Build Command
Write a docker build command that tags one build with a commit SHA (e5f6g7h) and a semantic version (v2.0.0), for a release build โ but deliberately without a latest tag.
Goal: Practice applying multiple tags to a single build in one command.
Challenge 2: Secure the Registry Login Step
A CI config hardcodes docker login -u admin -p Sup3rSecret directly in its pipeline file. Rewrite it to follow this chapter's credential-handling guidance.
Goal: Practice applying Chapter 6's never-hardcode-credentials discipline to registry authentication specifically.
Challenge 3: Diagnose a Production Incident
A production system is configured to always pull myapp:latest. After an unrelated build on a different branch pushed a broken image also tagged latest, production silently started running that broken build. Explain what went wrong and how this chapter's tagging strategy would have prevented it.
Goal: Practice connecting the latest-tag gotcha to a realistic, concrete incident.
The latest tag is just a mutable pointer โ it doesn't mean "the newest stable release," it means "whatever was pushed to latest most recently, from wherever." A production system configured to always pull latest has no guarantee it's running anything specific at all โ a stray build from an unrelated branch, a hotfix that was never meant to go live, or a broken in-progress push can silently become what production is running, with no deploy event, no record, and no easy way to know exactly what's live without inspecting the image directly. Production deployments should always reference an immutable, specific tag โ a commit SHA or a semantic version โ precisely because that guarantees pulling it always returns the exact same image, verifiably, every time.
๐ฏ What's Next
The next chapter is Orchestration Beyond Compose โ why Compose doesn't scale to multi-host production, and a conceptual orientation to Kubernetes/Swarm as the next step.