GitHub Actions can build and push Docker images for you, but it’s not as straightforward as it looks. The trick is realizing that GitHub Actions runners are ephemeral and don’t have Docker installed by default, and then figuring out how to authenticate with your container registry securely.

name: Build and Push Docker Image

on:
  push:
    branches:
      - main

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

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2

      - name: Login to Docker Hub
        uses: docker/login-action@v2
        with:

          username: ${{ secrets.DOCKERHUB_USERNAME }}


          password: ${{ secrets.DOCKERHUB_TOKEN }}


      - name: Build and push Docker image
        uses: docker/build-push-action@v4
        with:
          context: .
          file: ./Dockerfile
          push: true
          tags: your-dockerhub-username/your-repo-name:latest

This workflow automates the process of building a Docker image from your Dockerfile and pushing it to a registry like Docker Hub.

How it Works:

  1. Checkout code: This step pulls your repository’s code into the GitHub Actions runner. This is essential so the Dockerfile and any build context are available.
  2. Set up Docker Buildx: GitHub Actions runners don’t come with Docker installed. docker/setup-buildx-action installs and configures the BuildKit builder, which is a more efficient and feature-rich Docker image builder. It enables advanced features like multi-platform builds and better caching.
  3. Login to Docker Hub: This step is crucial for pushing your image. It uses docker/login-action to authenticate with your container registry. You’ll need to store your Docker Hub username and an access token (not your password!) as GitHub secrets.
    • Why an access token? Using an access token is more secure than your actual password. You can generate these in your Docker Hub account settings under "Security" -> "Access Tokens." Grant it "Write" permissions.
    • How to set up secrets: Go to your GitHub repository’s "Settings" -> "Secrets and variables" -> "Actions." Click "New repository secret" and add DOCKERHUB_USERNAME with your Docker ID and DOCKERHUB_TOKEN with your generated access token.
  4. Build and push Docker image: The docker/build-push-action does the heavy lifting.
    • context: .: Specifies the build context, which is the current directory where the Dockerfile resides.
    • file: ./Dockerfile: Points to your Dockerfile.
    • push: true: Tells the action to push the built image to the registry.
    • tags: your-dockerhub-username/your-repo-name:latest: This defines the image name and tag. Replace your-dockerhub-username with your Docker Hub username and your-repo-name with the desired name for your image. :latest is a common tag, but you could use commit SHAs, branch names, or version numbers for more specific tracking.

The Mental Model:

Think of GitHub Actions as a temporary, clean Linux environment that can execute commands. When you use actions like docker/setup-buildx-action or docker/login-action, you’re not installing Docker on your machine; you’re instructing the GitHub runner to download and configure the necessary tools for that specific job run. The build-push-action then leverages these tools to build your image and push it using the credentials you provided.

The ephemeral nature of runners means that each workflow run starts with a blank slate. This is great for consistency but means you can’t rely on anything being pre-installed or pre-configured between runs. Actions abstract away the complexity of setting up these environments.

The Hidden Gem:

The docker/build-push-action can also build multi-platform images if you configure BuildKit correctly and specify multiple --platform arguments. This is incredibly useful if you need your Docker image to run on different architectures (like amd64 for most desktops and arm64 for M1/M2 Macs or Raspberry Pis) without manually managing separate builds. You’d typically add a platforms argument to the build-push-action step, like platforms: linux/amd64,linux/arm64.

The next step is often setting up automated testing of your Docker image after it’s pushed.

Want structured learning?

Take the full Github course →