100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
YAML

Container Registries and Tagging Strategies

Explore how CI/CD pipelines push images to container registries and the tagging conventions that keep deployments traceable, safe, and repeatable.

Containers in CI/CDIntermediate8 min readJul 8, 2026
Analogies

Container Registries and Tagging Strategies

A container registry is a storage and distribution service for Docker images, acting as the handoff point between the build stage of a pipeline and every downstream consumer — deployment jobs, other teams, orchestration platforms like Kubernetes. Popular registries include Docker Hub, GitHub Container Registry (GHCR), Amazon ECR, Google Artifact Registry, and self-hosted options like Harbor. Choosing a registry involves considerations of access control, geographic proximity to deployment targets, cost, vulnerability scanning integration, and how tightly it integrates with your CI platform's authentication model. But the registry itself is only half the story — how images are tagged determines whether a team can reliably answer 'which exact image is running in production right now, and how do I roll back to the previous one?'

🏏

Cricket analogy: A stadium's equipment store is the handoff point between the bat manufacturer and every team using it — choosing a supplier (SG, Kookaburra, or local) depends on price, quality checks, and proximity to the ground; but the label alone won't tell you which exact bat Kohli used in the World Cup final.

Why the 'latest' Tag Is Dangerous in Pipelines

The 'latest' tag is a mutable pointer, not a version — pushing a new image to the same tag overwrites what 'latest' refers to, meaning two different deployments referencing 'myapp:latest' at different times could run entirely different code with no record of what changed. This makes rollbacks unreliable, debugging painful, and reproducibility impossible, since you cannot pull the exact image that was running last Tuesday once 'latest' has moved on. Production pipelines should almost always deploy using immutable, uniquely identifying tags rather than 'latest', reserving 'latest' at most as a convenience alias for local development.

🏏

Cricket analogy: Calling a player 'the current opener' is a mutable label — today it might mean Rohit Sharma, next series someone else entirely after a reshuffle, so a scouting report written against 'the current opener' months ago is useless without knowing exactly who that was at the time.

Immutable Tagging Conventions

The most robust tagging strategy uses the git commit SHA (or a shortened form of it) as the primary tag, since a SHA uniquely and permanently identifies the exact source code that produced the image — there can never be ambiguity about what 'app:a3f9c21' contains. Many teams layer additional, more human-readable tags alongside the SHA: semantic version tags (v2.4.1) for released software, branch-based tags (main, staging) that do move but are understood to be mutable pointers used only for non-production environments, and date-based tags for audit trails. A common pattern pushes the same image under multiple tags simultaneously — the immutable SHA and one or more mutable convenience aliases — so different consumers can reference the level of stability they need.

🏏

Cricket analogy: A player's unique BCCI registration ID permanently and unambiguously identifies one specific player, no matter how many nicknames ('Hitman,' 'Captain') get layered on top — the ID never changes even as human-readable nicknames come and go with form and role.

yaml
name: push-with-tags
on:
  push:
    branches: [main]
    tags: ['v*']
jobs:
  push-image:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Log in to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata for tags
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ghcr.io/acme/api
          tags: |
            type=sha,prefix=,format=short
            type=ref,event=branch
            type=semver,pattern={{version}}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

Think of an immutable SHA tag like a VIN number on a car: it uniquely and permanently identifies one specific build. A branch tag like 'staging' is more like a parking space — useful as a label for 'whatever is here right now,' but the occupant changes constantly.

Deploying directly from a mutable tag such as 'main' or 'latest' means your deployment manifest never actually changes, which breaks GitOps-style workflows that rely on detecting a diff to trigger a rollout — orchestrators may not notice a new image exists at all unless the pod is manually restarted or an imagePullPolicy of Always forces a re-pull.

Registry Cleanup and Retention Policies

Because every pipeline run can push a new uniquely tagged image, registries accumulate storage costs and clutter quickly. Most registries support retention policies that automatically expire untagged or old images after a configurable period, while explicitly protecting tags matching patterns like v* or images referenced by an active deployment. Designing this policy is a balance: too aggressive and you lose the ability to roll back to an older known-good build; too lax and storage costs and image sprawl grow unchecked.

🏏

Cricket analogy: A cricket board can't keep every training kit from every net session forever — old, unused gear gets cleared out periodically, but the exact match-day kits from World Cup finals (protected 'tagged' items) are preserved indefinitely regardless of age.

  • A container registry stores and distributes images built by CI pipelines to downstream deployment consumers.
  • The 'latest' tag is mutable and unreliable for production deployments since it can silently point to different code over time.
  • Git commit SHA tags provide immutable, unambiguous traceability from image back to source.
  • Semantic version and branch tags are useful human-readable aliases layered alongside SHA tags.
  • Deploying from mutable tags breaks GitOps diff-detection workflows that expect manifest changes to trigger rollouts.
  • Retention policies balance rollback capability against unbounded registry storage growth.

Practice what you learned

Was this page helpful?

Topics covered

#YAML#CICDToolsPipelinesStudyNotes#DevOps#ContainerRegistriesAndTaggingStrategies#Container#Registries#Tagging#Strategies#Docker#StudyNotes#SkillVeris