Creating a container image

You can use this workflow step to create a new container image, this mostly relies on the docker/build-push-action, but sets up the environment for easy mutli-arch builds with buildx and qemu. It also logs in to the GitHub container registry allowing you to upload an image right away. To use it, add a job to your GitHub workflow calling this workflow:

# ...

jobs:

  # ...

  docker:
    runs-on: ubuntu-latest
    steps:
      # ...

      - name: Build container image
        uses: tweedegolf/build-container-image@main
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          push: ${{ github.ref == 'refs/heads/main' }}
          platforms: "linux/amd64,linux/arm64"
          tags: ghcr.io/tweedegolf/example:latest

      # ...

  # ...

Workflow inputs

This workflow has several parameters that allow customizing the behavior:

OptionRequiredDefault
token yes
GitHub token for logging into the ghcr container registry
tags yes
List of image tags (newline separated) for the resulting container image
push no false
If true, the image will be pushed to the registry
platforms no ""
Comma separated list of platforms to build the image for, i.e. linux/amd64,linux/arm64. If left empty, will only build for the native platform.
context no .
Context directory for the container image build
build-args no ""
List of build arguments (newline separated) to be inserted in the container image build
file no Dockerfile
Name of the dockerfile to build
no-cache no true
Set to false to enable caching of docker layers
pull no true
Pull base images from the registry when not available locally

Example usage

Below, you will find a working example where we either just build (and not push) a container image on a pull request, and we fully build and push a container on the main branch, these two require separate permissions. We'll also add a build matrix to allow multiple images to be generated:

  • .github/workflows/docker.yml

    name: Docker
    
    on:
      workflow_call:
    
    jobs:
      docker:
        strategy:
          matrix:
            include:
              - version: trixie
                latest: false
                alt: testing
              - version: bookworm
                latest: true
                alt: stable
              - version: bullseye
                latest: false
                alt: oldstable
        steps:
          - uses: actions/checkout@v4
          - name: Build container image
            uses: tweedegolf/build-container-image@main
            with:
              token: ${{ secrets.GITHUB_TOKEN }}
              push: ${{ github.ref == 'refs/heads/main' }}
              platforms: "linux/amd64,linux/arm64"
              build-args: |
                DEBIAN_VERSION=${{matrix.version}}
              tags: |
                ghcr.io/tweedegolf/debian:${{matrix.version}}
                ghcr.io/tweedegolf/debian:${{matrix.alt}}
                ${{ matrix.latest && 'ghcr.io/tweedegolf/debian:latest' || '' }}

    This file will be re-used by the two workflows below. As such we only trigger it on workflow_call. Note how we use a matrix to build multiple images. Of course for this workflow to run we'll also need a Dockerfile to be built, but that has been omitted in this example.

  • .github/workflows/build-push.yml

    name: Build and push
    
    permissions:
      contents: read
      packages: write
    
    on:
      push:
        branches:
          - main
      schedule:
        - cron: '30 2 * * SUN'
    
    jobs:
      build-and-push:
        uses: ./.github/workflows/docker.yml

    This build and push workflow for the main branch also runs on a schedule every week to keep the image up to date. Note how we require package write permission in this workflow.

  • .github/workflows/check.yml

    name: Checks
    
    permissions:
      contents: read
    
    on:
      pull_request:
    
    jobs:
      build:
        uses: ./.github/workflows/docker.yml
        secrets: inherit

    The checks workflow will just need read permissions for the repository with no write permissions required. We only run it for a pull request.