Back to Blog
Lesson 44 of the CI/CD: Continuous Integration from Scratch course
DevOpsAugust 19, 20263 min read

Container Registry Integration: Pushing Images in CI/CD

Learn to authenticate with a container registry like Docker Hub or GHCR and automate pushing your Docker images using GitHub Actions for seamless deployments.

DevOpsDockerCI/CDGitHub ActionsContainersCloud
Group of white shipping containers set against a forest backdrop, illustrating transportation logistics.

Previously in this course, we covered Building Images in CI. Now that your pipeline can successfully construct a container image from your source code, the next logical step is moving those artifacts off the ephemeral build runner and into a permanent home where your production servers can find them: the container registry.

Why Registry Integration Matters

A container registry acts as a versioned storage system for your images. Without a registry, your build artifacts exist only for the duration of the CI job. By pushing your images to a registry like Docker Hub or GitHub Container Registry (GHCR), you create a "source of truth" that your deployment targets can pull from later.

Think of it as the difference between a local draft of a document and a published version on a shared drive; until it's in the registry, it isn't ready for the real world.

Authenticating with a Registry

To push images, your CI pipeline needs permission to write to your account. You should never hardcode credentials in your YAML files. Instead, use Managing Secrets to store your DOCKER_USERNAME and DOCKER_PASSWORD (or Personal Access Token).

When using GitHub Actions, the most common and robust way to authenticate is the docker/login-action. It handles the handshake with the registry securely.

Worked Example: Pushing to Docker Hub

Let’s update your existing pipeline to include an authentication step and a push step. We assume you have already built your image and tagged it appropriately.

YAML
jobs:
  build-and-push:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ secrets.DOCKER_USERNAME }}/my-app:latest

In this example, the docker/build-push-action performs the heavy lifting. By setting push: true, the action automatically pushes the resulting image to the repository specified in the tags parameter after the build completes.

Hands-on Exercise

  1. Log in to your Docker Hub account and create a new repository (e.g., my-awesome-app).
  2. Add your DOCKER_USERNAME and DOCKER_PASSWORD as repository secrets in your GitHub repository settings.
  3. Update your workflow YAML file to include the docker/login-action and docker/build-push-action steps shown above.
  4. Push your changes and observe the "Actions" tab in GitHub; verify that the image appears in your Docker Hub dashboard after the job succeeds.

Common Pitfalls

  • Permissions Errors: If your build fails with a 403 or "denied" error, ensure your secret contains a Personal Access Token (PAT) with "write" permissions, not just your account password.
  • Tagging Mismatches: Always ensure the tag you push matches the naming convention of your registry repository. If you push to my-user/my-app, ensure your tag follows that exact format.
  • Public vs. Private: By default, new Docker Hub repositories are public. Ensure you verify the visibility settings of your registry, especially if your application code or environment contains sensitive logic.

Frequently Asked Questions

Which registry should I choose? If you are already using GitHub, GHCR (GitHub Container Registry) is highly recommended as it integrates natively with GitHub permissions. Docker Hub is a great, industry-standard alternative for cross-platform projects.

Should I use 'latest' tags for production? Avoid using latest in production environments. It is better practice to use the Git commit SHA or a semantic version (e.g., v1.0.2) as a tag to ensure you know exactly what code is running.

Does this increase my build time? Yes, adding a push step adds network latency to your pipeline. However, as discussed in Advanced Pipeline Caching, you can mitigate this by utilizing build layers effectively.

Recap

We have moved from building local artifacts to automating the distribution of those artifacts. By integrating registry authentication and pushing images, you've established a reliable link between your code and your future deployment environments. You now have a persistent, versioned record of every successful build.

Up next: Pulling Images in Production, where we will configure your target server to pull these images and refresh your application.

Similar Posts