Skip to main content
GitHub Actions
CHAPTER 11

Docker Integration with GitHub Actions

Updated: May 15, 2026
25 min read

# CHAPTER 11

Docker Integration with GitHub Actions

1. Introduction

Modern software is rarely deployed as raw source code. Instead, the industry standard is to package the code, its dependencies, and its runtime environment into a single, immutable artifact known as a Docker Container. This guarantees that if the application runs on the developer's laptop, it will run exactly the same way on the production server. In this chapter, we will evolve our CI/CD pipeline. Instead of just testing the code, the final output of our GitHub Action will be compiling a Docker Image and securely publishing it to a container registry like Docker Hub or the GitHub Container Registry (GHCR).

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Understand the role of Docker in a CI/CD pipeline.
  • Authenticate GitHub Actions with a remote Docker Registry.
  • Utilize official Docker Marketplace actions to build images.
  • Tag Docker images dynamically using GitHub commit SHAs.
  • Push the built container to a registry for deployment.

3. Beginner-Friendly Explanation

Imagine baking a cake for a bakery.
  • The Old Way (Source Code): You send the bakery a recipe (the code), a bag of flour, and some eggs. You hope they have the right oven temperature and the right pan size. Sometimes they mess it up, and the cake burns.
  • The Docker Way: You bake the perfect cake in your own kitchen. You put it in a sealed, indestructible, climate-controlled titanium box (The Docker Container). You mail the box to the bakery. They just open the box and serve it. It is mathematically impossible for the cake to be burned.

Our GitHub Action is the automated factory that bakes the cake, seals it in the titanium box, and places it on the delivery truck.

4. The Docker Build Workflow

To build a Docker image, your repository must contain a Dockerfile. The workflow logic follows a strict three-step sequence:
  1. 1. Login: Authenticate with the Registry (e.g., Docker Hub) so we have permission to upload.
  1. 2. Build: Execute docker build to read the Dockerfile and create the image.
  1. 3. Push: Execute docker push to upload the heavy image file to the cloud.

While you *could* run these commands manually using run: docker build..., Docker provides official Marketplace Actions that handle caching and tagging much more efficiently.

5. Mini Project: Build and Publish a Docker Image

Let's build a CD pipeline that creates a Docker image and pushes it to Docker Hub whenever code is merged to main.

Prerequisites: You must add your Docker Hub username (DOCKERHUBUSERNAME) and password/token (DOCKERHUBTOKEN) to your GitHub Repository Secrets!

Step-by-Step Pipeline Concept:

yaml
12345678910111213141516171819202122232425262728293031323334
name: Publish Docker Image
on:
  push:
    branches:
      - main

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

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

      # Step 2: Set up Docker Buildx (A fast build engine)
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      # Step 3: Build and Push the Image
      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: . # Looks for the Dockerfile in the root directory
          push: true
          # We tag the image with 'latest' AND the specific Git Commit SHA
          tags: |
            myusername/my-web-app:latest
            myusername/my-web-app:${{ github.sha }}

6. The Importance of Tagging (github.sha)

In the example above, we tagged the image using ${{ github.sha }}. This is a built-in GitHub variable representing the unique hash of the Git commit (e.g., a1b2c3d4...). Why is this critical? If you only tag your image as latest, every deployment overwrites the previous one. If you deploy a bug and the website crashes, you cannot roll back because the old image was deleted! By tagging every image with the specific Git commit hash, you create an immutable history. Rolling back is as easy as telling the server to run the previous hash.

7. Real-World Scenarios

A financial startup was building an application that processed massive amounts of data. Their pipeline ran npm install directly on the production server during deployment. One day, the NPM registry went down globally for an hour. During that hour, the startup attempted a deployment. The server deleted the old code, tried to download the new dependencies, failed, and the entire application went offline. Following the outage, they migrated to Docker. GitHub Actions built the complete Docker image in isolation. If NPM went down, the GitHub Action would fail, but the *production server was completely untouched and stayed online*. They achieved true "Immutable Deployments."

8. Best Practices

  • Use GHCR (GitHub Container Registry): Instead of paying for Docker Hub, GitHub provides its own registry natively. You can change the login action to authenticate with ghcr.io using the built-in ${{ secrets.GITHUB_TOKEN }}. This keeps your code and your Docker images perfectly synced in the same platform without needing external passwords.

9. Security Recommendations

  • Docker Image Scanning: Just because code is in a container doesn't mean it's secure. You should add a step *after* the build (but *before* the push) to scan the Docker image for vulnerabilities using a tool like Trivy (uses: aquasecurity/trivy-action). If Trivy detects a critical vulnerability in the base operating system of your container, it will fail the workflow and block the upload.

10. Troubleshooting Tips

  • Build Context Errors: If the build-push-action fails saying it cannot find files, ensure your context: is pointing to the correct directory. If your Dockerfile is inside a subfolder named backend/, you must set context: ./backend.

11. Exercises

  1. 1. What is the operational danger of tagging every Docker image build exclusively with the :latest tag?
  1. 2. Why is building a Docker container considered a safer deployment strategy than running dependency installation scripts directly on a live production server?

12. FAQs

Q: Does it take a long time to build a Docker image on GitHub runners? A: It can, but the docker/setup-buildx-action we included enables layer caching. If you don't change your package.json, Docker won't redownload your dependencies; it will just use the cached layer from the last build, reducing build times from 5 minutes to 30 seconds.

13. Interview Questions

  • Q: Describe a complete Continuous Delivery pipeline utilizing Docker. Detail the authentication mechanism with the registry and the strategy used for tagging images to ensure robust rollback capabilities.
  • Q: Explain the concept of an "Immutable Artifact." Why has the DevOps industry standardized on Docker containers rather than ZIP files for application delivery?

14. Summary

In Chapter 11, we embraced modern container orchestration. We transitioned our pipelines from deploying raw files to manufacturing immutable Docker artifacts. We utilized official marketplace actions to handle the complexities of authenticating with container registries and utilized the highly optimized Buildx engine. Finally, we learned the critical DevOps pattern of tagging images with Git Commit SHAs, ensuring that every artifact we produce is traceable, unique, and instantly reversible in the event of a production failure.

15. Next Chapter Recommendation

Our Docker image is sitting safely in a registry. Now, we must instruct a cloud provider to pull that image and run it. Proceed to Chapter 12: GitHub Actions for Kubernetes and Cloud.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·