Command Palette

Search for a command to run...

Hectal
PHASE 5Intermediate ~14 min· topic 3 of 4

Topic 5.3

Container Registries: ECR, GHCR, and Docker Hub

In one line

A container registry is an artifact repository specifically for Docker images — the exact same build-once-store-retrieve principle from Topic 5.1, applied to the images Docker's own course taught you to build.

0/4 · 0%

Key ideas

  1. 01

    A CONTAINER REGISTRY is genuinely just a specialized artifact repository (Topic 5.1's principle applies identically) storing container IMAGES specifically, addressable by a name and TAG (my-registry/my-app:1.5.0) — docker push and docker pull (Docker's own course) are the exact commands used to publish to and retrieve from one.

  2. 02

    DOCKER HUB is the original, most widely-known public registry — genuinely fine for public, open-source images, but real organizations building PRIVATE, proprietary images almost always use a different registry with better organizational access control and, often, tighter integration with their existing cloud or CI platform.

  3. 03

    AWS ECR (Elastic Container Registry) integrates directly with AWS's own IAM permission system (the DevOps roadmap this course draws from covers IAM in its own dedicated AWS course) — genuinely the natural choice for a team already deploying to AWS (ECS, EKS — Kubernetes' own course covered EKS as a managed Kubernetes offering), since authentication and access control flow directly from infrastructure the team already manages.

  4. 04

    GHCR (GitHub Container Registry) integrates directly with GitHub itself — genuinely convenient for a team already using GitHub Actions (Phase 2), since authentication can flow automatically from the same GITHUB_TOKEN a workflow already has access to, with zero separate registry credentials to manage at all.

  5. 05

    IMAGE TAGGING STRATEGY matters genuinely as much as the registry choice itself — tagging every build with a genuinely UNIQUE identifier (a commit SHA, or a real semantic version, Git's own course Phase 6.3) rather than always overwriting a generic latest tag is what actually makes 'roll back to the previous version' (Kubernetes' own course, Phase 6.3) a meaningful, reliable operation — latest by definition can't distinguish one specific previous version from another.

  6. 06

    A genuinely common, correct real pattern: build once, tag the resulting image with BOTH a specific, unique identifier (myapp:a1b2c3d or myapp:1.5.0) AND, separately, update a floating tag like myapp:latest to also point at that same image — giving both a precise, permanent reference for deployments/rollbacks and a convenient, human-friendly 'whatever's newest' reference for casual use.

Code & diagrams

container-registry-push.shmarkdown

Tagging with both a unique identifier and a floating 'latest' — the standard, correct pattern.

# Build once
docker build -t myapp:build .

# Tag with a genuinely unique, permanent identifier — never reused
docker tag myapp:build my-registry/myapp:$CI_COMMIT_SHA

# ALSO tag as latest, for convenience — this one DOES get overwritten each time
docker tag myapp:build my-registry/myapp:latest

# Push BOTH tags
docker push my-registry/myapp:$CI_COMMIT_SHA
docker push my-registry/myapp:latest

# A rollback references the SPECIFIC, permanent tag — never "latest",
# since "latest" by definition can't tell you which specific previous version it was
# kubectl set image deployment/myapp myapp=my-registry/myapp:a1b2c3d  (Kubernetes course, Phase 6.3)
ghcr-authentication.ymlmarkdown

GHCR's own convenience — zero separate credentials needed inside a GitHub Actions workflow.

jobs:
  build-and-push:
    runs-on: ubuntu-latest
    permissions:
      packages: write            # grants this job's own GITHUB_TOKEN registry access
    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 }}   # already exists — no separate secret needed

      - name: Build and push
        run: |
          docker build -t ghcr.io/my-org/myapp:${{ github.sha }} .
          docker push ghcr.io/my-org/myapp:${{ github.sha }}

Explain it without notes

01

Why is tagging every image build with a unique identifier like a commit SHA, in addition to latest, genuinely important for being able to roll back reliably?

02

Why might a team already deploying to AWS specifically choose ECR over Docker Hub for their private images?

Practice

01

Push an image to a registry you have access to (Docker Hub, GHCR, or ECR) with both a unique tag and a latest tag, and confirm both tags are visible in the registry pointing at the same image.

02

If you use GitHub Actions, set up image push authentication using GITHUB_TOKEN against GHCR, confirming you never needed to create or store a separate registry credential.

Trade-offs

  • ↔

    A registry tightly integrated with your existing platform (ECR with AWS, GHCR with GitHub) reduces credential management overhead significantly, but it does create a real degree of platform coupling — moving to a different cloud provider or Git host later means also migrating your container registry and updating every pipeline and deployment reference to it, a genuine, real cost worth being aware of even if it's rarely the deciding factor for most teams' initial choice.

Done when you can

  • I understand a container registry is just an artifact repository specialized for container images.

  • I can explain why tagging with a unique identifier (not just latest) matters for reliable rollbacks.

  • I can reason about when ECR, GHCR, or Docker Hub is the most natural choice for a given team's existing platform.