KAHIBARO
Discord Login Register

24.9. Container Registries

Understanding Container Registries

A container registry is a service where you store and share container images. It plays a similar role to Git hosting platforms for source code, but for built images.

When you build Docker images in CI, the registry is usually the bridge between your CI pipeline and your deployment environment.

What Is a Container Registry?

A container registry is a centralized storage for container images, typically supporting:

You interact with a registry using docker or compatible tools.

Example:

bash
# Login to registry
docker login registry.example.com
# Build image
docker build -t registry.example.com/my-app:1.0.0 .
# Push image
docker push registry.example.com/my-app:1.0.0
# Later, on a server
docker pull registry.example.com/my-app:1.0.0
docker run -d --name my-app registry.example.com/my-app:1.0.0

A container registry is not the same as Docker Hub.
Docker Hub is one implementation of a registry. You can use many different registries or even run your own.

Image Names and Tags

Every image in a registry has a name and a tag. The full image reference usually looks like this:

text
[registry-host]/[namespace]/[repository]:[tag]

Common patterns:

ExampleMeaning
python:3.12Docker Hub, library/python, tag 3.12
myuser/myapp:latestDocker Hub, namespace myuser, repo myapp, tag latest
ghcr.io/my-org/my-api:1.0.0GitHub Container Registry, org my-org, repo my-api
registry.example.com/myteam/app:2024-08-01Private registry at registry.example.com

Useful conventions:

Rule: Always tag images explicitly in CI, for example using $GIT_SHA or a release version.
Never deploy untagged or implicitly tagged latest images to production.

Example CI tags:

bash
IMAGE_TAG="$GITHUB_SHA"          # full commit SHA
IMAGE_TAG="1.0.0"               # release
IMAGE_TAG="1.0.0-$GITHUB_SHA"   # release + SHA

Types of Container Registries

There are several common types of registries you will encounter.

Public Registries

Public registries host images that are often accessible to everyone.

Examples:

RegistryExample imageNotes
Docker Hubnginx:1.27Most common public registry
GitHub Container Registryghcr.io/user/app:tagIntegrated with GitHub
GitLab Registryregistry.gitlab.com/group/appIntegrated with GitLab

Typical use cases:

Private Registries

Private registries are used for internal or proprietary images.

Options:

OptionDescription
Private repos on Docker HubPrivate images under your Docker account
GitHub Packages / GHCRPrivate images tied to GitHub repos
GitLab Container RegistryPrivate images tied to GitLab projects
Cloud provider registriesECR, GCR, ACR etc
Self-hosted registryYour own registry instance, often via Docker

Use a private registry when:

Popular Registry Providers

Many CI/CD setups use registries that are built into source hosting or cloud platforms.

Docker Hub

Example usage:

bash
# Logged-in as 'mydockeruser'
docker build -t mydockeruser/my-api:1.0.0 .
docker push mydockeruser/my-api:1.0.0

GitHub Container Registry (GHCR)

Example naming conventions:

PatternDescription
ghcr.io/OWNER/IMAGE_NAME:tagGeneral image
ghcr.io/OWNER/REPO/IMAGE_NAMESometimes used inside org repos

Minimal GitHub Actions example:

yaml
name: Build and push image
on:
  push:
    branches: [ main ]
jobs:
  build-and-push:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
    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: Build and push
        uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: ghcr.io/${{ github.repository }}/my-api:${{ github.sha }}

GitLab Container Registry

Example name:

text
registry.gitlab.com/my-group/my-project/backend:1.0.0

Minimal GitLab CI snippet:

yaml
image: docker:24
services:
  - docker:24-dind
variables:
  DOCKER_DRIVER: overlay2
build_and_push:
  stage: build
  script:
    - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
    - docker build -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA" .
    - docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA"

Cloud Provider Registries

Cloud platforms provide registries that integrate with their services:

ProviderRegistryExample image
AWSAmazon ECR123456789012.dkr.ecr.us-east-1.amazonaws.com/app:tag
GCPArtifact Registry / GCRus-docker.pkg.dev/project/repo/app:tag
AzureAzure Container Registry (ACR)myregistry.azurecr.io/app:tag

Common use case:

Authentication and Access Control

To push to most registries, you must authenticate. To pull, you may or may not need authentication, depending on whether the image is public.

Basic Docker Login

For many registries you can login with docker login:

bash
docker login registry.example.com
# Prompts for username and password or token

Then build and push:

bash
docker build -t registry.example.com/myteam/app:1.0.0 .
docker push registry.example.com/myteam/app:1.0.0

CI Authentication With Secrets

In CI you should never hardcode credentials in the pipeline file. Use secret variables.

Example with GitHub Actions and Docker Hub:

yaml
- name: Log in to Docker Hub
  uses: docker/login-action@v3
  with:
    username: ${{ secrets.DOCKERHUB_USERNAME }}
    password: ${{ secrets.DOCKERHUB_TOKEN }}

Example with GitHub Actions and a private registry:

yaml
- name: Docker login
  uses: docker/login-action@v3
  with:
    registry: registry.example.com
    username: ${{ secrets.REGISTRY_USER }}
    password: ${{ secrets.REGISTRY_PASSWORD }}

Example with environment variables in GitLab:

yaml
script:
  - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"

Rule: Store registry credentials in CI secrets, never in the repository.
Use tokens or service accounts instead of personal passwords when possible.

Using Registries in CI/CD Pipelines

In a typical CI/CD workflow, the registry connects the build and deploy stages:

  1. Build job in CI:
    • Checkout code.
    • Build Docker image.
    • Tag image with version or commit SHA.
    • Push image to registry.
  2. Deploy job in CI or CD:
    • Pull specific image tag from registry.
    • Update Kubernetes deployment, Docker Compose, or server to use that tag.

Example: Simple Build and Push Pipeline

GitHub Actions example:

yaml
name: Build and push image
on:
  push:
    branches: [ main ]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Log in to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      - name: Build and push
        uses: docker/build-push-action@v6
        with:
          context: .
          push: true
          tags: mydockeruser/my-api:${{ github.sha }}

A deploy job could then reference mydockeruser/my-api:${{ github.sha }}.

Example: Multiple Tags for the Same Image

You can apply several tags to the same image, for example commit SHA and branch name:

bash
IMAGE_NAME="registry.example.com/myteam/app"
COMMIT_SHA="$GITHUB_SHA"
BRANCH_NAME="${GITHUB_REF_NAME}"
docker build -t "$IMAGE_NAME:$COMMIT_SHA" .
docker tag "$IMAGE_NAME:$COMMIT_SHA" "$IMAGE_NAME:$BRANCH_NAME"
docker tag "$IMAGE_NAME:$COMMIT_SHA" "$IMAGE_NAME:latest"
docker push "$IMAGE_NAME:$COMMIT_SHA"
docker push "$IMAGE_NAME:$BRANCH_NAME"
docker push "$IMAGE_NAME:latest"

This way:

Self-Hosted Registries

Sometimes you want to run your own registry, for example inside a corporate network.

Basic Docker Registry

Docker provides a reference implementation you can run as a container:

bash
docker run -d \
  -p 5000:5000 \
  --name registry \
  registry:2

You can then push images to localhost:5000:

bash
docker build -t localhost:5000/my-app:1.0.0 .
docker push localhost:5000/my-app:1.0.0

This is useful for:

For production use, you typically add:

Using a Private Registry in CI

If your registry is at registry.internal:5000, your CI configuration might include:

yaml
- name: Docker login
  run: echo "$REGISTRY_PASSWORD" | docker login registry.internal:5000 -u "$REGISTRY_USER" --password-stdin
- name: Build
  run: docker build -t registry.internal:5000/my-app:${GITHUB_SHA} .
- name: Push
  run: docker push registry.internal:5000/my-app:${GITHUB_SHA}

Note that the CI runners must have network access to registry.internal:5000.

Security and Best Practices

When dealing with container registries in CI/CD you must think about:

Keep Images Private When Needed

Avoid Leaking Credentials

Example of a bad practice:

yaml
# BAD: Hardcoded password
- run: docker login -u user -p mysecretpassword

Example of a safer practice:

yaml
- run: echo "$REGISTRY_PASSWORD" | docker login -u "$REGISTRY_USER" --password-stdin

Image Scanning

Many registries support vulnerability scanning:

In CI you can:

Retention and Cleanup

Images can quickly consume storage. Good policies:

Example policy:

Tag typeExampleRetention
Commit tags:sha-1234abcdLast 30 days or 100 images
Branch tags:mainKeep latest only
Release tags:1.0.0Keep all or manual cleanup

Connecting Registries to Deployment Environments

Your deployment environment must be able to pull images from your registry.

Docker Compose

In a docker-compose.yml file:

yaml
services:
  api:
    image: registry.example.com/myteam/app:1.0.0
    ports:
      - "8000:8000"

Before docker-compose up, you might need:

bash
docker login registry.example.com

Kubernetes

For Kubernetes, you define the image in the Deployment manifest:

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-api
spec:
  replicas: 2
  selector:
    matchLabels:
      app: my-api
  template:
    metadata:
      labels:
        app: my-api
    spec:
      containers:
        - name: my-api
          image: registry.example.com/myteam/app:1.0.0
          ports:
            - containerPort: 8000

For private registries you typically configure:

By understanding container registries and how to integrate them into CI/CD pipelines, you can:

Views: 10

Comments

Please login to add a comment.

Don't have an account? Register now!