skip to content

questions

4

Why does a CI job push one container image under both a git-SHA tag and a `stable` tag?

level: juniorimportance: must knowfreq 72%

answer

  1. Two names, two different jobs
  2. One name must never change meaning
  3. The other is re-pointed every release
  4. Redeploy needs a name nobody moved
  5. docker tag then a second push

basics

~20 s

The git-SHA tag is a permanent name for one exact build, so it can be redeployed later and traced back to a commit. The stable tag only points at whichever build is current, so it answers what is live now, not what shipped when.

solid answer

~50 s

The two tags do different jobs, and one tag cannot do both. A tag derived from the commit, such as `indexer:7e1c94d`, is written once and never re-pointed: it is a permanent, human-readable name for one specific set of bytes, so months later you can still start that exact build and know which commit produced it. An alias such as `indexer:stable` is deliberately mutable — each release re-points it with `docker tag indexer:7e1c94d indexer:stable` followed by a second `docker push`, which uploads only a manifest because the layers are already in the repository. Deployments and rollbacks should name the immutable tag; the alias is a convenience for humans, local runs and "give me something that works" pulls. If the alias is the only tag you ever push, every past release loses its name the moment the next one ships.

code

bash · 7 lines
bash
# build once, name it after the commit, push that name first
docker build -t registry.internal:5000/indexer:7e1c94d .
docker push registry.internal:5000/indexer:7e1c94d

# then move the alias as a separate, deliberate step
docker tag registry.internal:5000/indexer:7e1c94d registry.internal:5000/indexer:stable
docker push registry.internal:5000/indexer:stable

go deeper

for a junior

Be ready to say plainly what each of the two tags is for and to write the two commands that add and push an alias. Knowing that both names can point at one image ID is the core of it.

for a middle

Explain the mechanics: docker tag adds a name with no copy, the second push writes only a manifest, and re-pointing an alias leaves the previous manifest intact but nameless unless its own build tag exists.

for a senior

Show the operational consequence. An interviewer expects you to connect the convention to rollback: deployments name the immutable tag, aliases move afterwards, and no production action ever depends on a name someone else can re-point.

for a principal

Own the rule rather than the commands. Decide which names in your registry are allowed to move, who may move them, and where the history of those moves is recorded, since the registry itself keeps none.

### Two jobs, two tags A container image reference like `registry.internal:5000/indexer:7e1c94d` is a name a registry resolves to a manifest. Names are cheap: the same image can carry as many of them as you like, in the same repository, and pushing a second name for an image already in the repository transfers almost nothing because the blobs are already there. That cheapness is what makes the two-tag convention work. A release pipeline is being asked for two different things at once, and they are in direct conflict: 1. **"Run exactly the build we tested."** This needs a name that will mean the same thing forever. If the name can be re-pointed, then "deploy `indexer:stable`" is not an instruction, it is a bet on what somebody else has done since. 2. **"Run whatever is current."** A developer pulling the service to run it locally, a smoke-test job, a `FROM` line in a downstream image — these want the newest good build without being told its identifier every time. That needs a name that *does* move. One tag cannot satisfy both. So the pipeline pushes two. ### What the build tag looks like The immutable tag is derived from something the build already knows and never reuses: the commit that was built (`7e1c94d`), the pipeline's build number (`4183`), a release version, or a combination such as `1.4.2-4183-7e1c94d`. The rule that matters is not which of those you pick — it is that **the pipeline writes that tag once and no later build ever writes it again**. It is the name you put in a deployment, quote in an incident channel, and roll back to. ### What the alias looks like `stable`, `prod`, `edge`, `nightly`, `main` — the exact word is convention. What defines an alias is that it is re-pointed on purpose. Mechanically that is two commands after the build has been pushed: ``` docker tag registry.internal:5000/indexer:7e1c94d registry.internal:5000/indexer:stable docker push registry.internal:5000/indexer:stable ``` Locally, `docker image ls` now shows two rows with the *same* IMAGE ID — `docker tag` did not copy anything, it added a name. In the registry, the second push finds every layer already present ("Layer already exists") and writes only the manifest under the new tag. The previous build that used to be behind `stable` has not been deleted or damaged; it simply is not called `stable` any more. It is still reachable by its own build tag — which is exactly why that build tag has to exist. ### The failure this convention prevents The interesting question is what happens when a team pushes only the alias. Every release overwrites the meaning of the one name that exists. There is then no way to say "run the build from before lunch", because that build has no name at all. Rolling back becomes rebuilding from an older commit and hoping the result is equivalent — a different base image, a moved dependency or a changed build argument means it may not be. Worse, a rollback done by re-pointing the alias backwards is invisible: nothing in the registry records that the name used to mean something else. With both tags present, a rollback is boring: redeploy `indexer:7e1c94d`, which is a name nobody has permission to move, and adjust the alias afterwards if you keep one. ### What each side of the pair is *not* The build tag is not a version. It usually is not ordered — you cannot look at two commit-SHA tags and say which is newer — and it does not tell anybody whether a build is fit for production. That is what the alias, or a separate promotion step, is for. The alias is not an audit trail. It has no history: it is one pointer, and looking at it today tells you nothing about what it pointed at last Tuesday. If knowing that matters — and during an incident it usually does — the record has to live somewhere that keeps history, such as the deployment log that says which immutable tag was rolled out and when. ### The habit to take away Build once, push the immutable tag first, then move any aliases as a separate, deliberate step. Deploy and roll back by the immutable tag. Treat every mutable name as a signpost for humans, never as the thing a production system is pointed at.

  • Does pushing the second tag upload the image again?
    No. `docker tag` only adds a name locally — both tags share one image ID and nothing is copied. The second `docker push` checks each layer against the repository first, finds them all present and reports "Layer already exists", so it uploads only a small manifest under the new tag. That is why re-pointing an alias is effectively free even for a large image.
  • What happens to the build that `stable` used to point at?
    Nothing happens to the image itself. The tag is just a name, and re-pointing it removes that name from the old manifest — the manifest, its layers and its own build tag are untouched, so the old build is still pullable by `indexer:7e1c94d`. It only becomes genuinely unreachable if it had no other tag, which is precisely the situation the immutable build tag exists to prevent.
  • Should the alias be moved before or after the deployment succeeds?
    After. The deployment itself should name the immutable tag, so the alias is a record of "this build is the one we are happy with", not the trigger. Moving it first means a failed rollout leaves the alias advertising a build that never worked, and anybody who pulls the alias in the meantime — a developer, a smoke test, a downstream build — gets the bad one.

A commit-SHA tag is like the permanent catalogue number printed on a book's spine; stable is like the "new arrivals" shelf. You can always find the book by its number, but the shelf tells you nothing about what stood there last month.

saying these in an interview costs you the question

  • Thinks docker tag copies or rebuilds the image
  • Believes re-pointing a tag deletes the old image
  • Pushes only a moving alias and no per-build tag
  • Treats an alias as a record of what shipped
  • Says a rollback means rebuilding from the old commit
  • Assumes two tags cost two uploads of the layers

context

open as a page

Rolling back by redeploying the image tag `indexer:stable` brings the same broken build back. Why?

level: seniorimportance: should knowfreq 58%

basics

~20 s

Because the release already re-pointed that alias at the broken build, so redeploying it fetches the same manifest. A rollback has to name a tag nobody moved — the previous build's own immutable tag — not the alias the release just updated.

open as a page

Your platform deploys whatever the image tag `prod` currently points at. How do you govern that pointer, and would you keep the design?

level: principalimportance: should knowfreq 41%

basics

~20 s

A single mutable pointer with no history is a release control plane with no audit trail and no rollback target. Keep the alias for humans, restrict who may push it, record every move externally, and move deployments onto immutable build tags.

open as a page

Why tag a container image with the short git commit SHA rather than an incrementing build number?

level: middleimportance: nice to knowfreq 34%

basics

~20 s

A commit SHA ties the image to the source that produced it, needs no shared counter, and stays unique across branches and parallel builds. Its weakness is that SHAs carry no order, so many teams combine a build number with the SHA.

open as a page