Posted on

Motivation

I have a multi-docker [repo] that stores a few containers for different tasks/projects. I want to be able to push an updated container to the [github container registry (ghcr.io)] every time I have a new commit to the repository.

Requirements:

  • Docker images are organized in sub-folders [repo]
  • Docker-build is run with a single github action definition yaml file (as opposed to [one yaml per image])
  • Not recreating all containers if I am only making changes changes to only one image

Github action yaml file

TLDR; the action yaml is at [here]

Setup workflow

For github actions, we need to define when the action is run. For this wokflow, I want to trigger it for all pull requests and pushes.

And we can also setup some environment variables as well to define the container registry and image name.

name: Push and publish to Docker Hub
on: [push, pull_request]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME_BASE: ${{ github.repository }}

Setup action

And then we can setup variables for the action itself. The highlight is that I'm using matrix.docker to define which subfolder in the repo I am going to build docker containers from (each of these subfolder should have a Dockerfile file).

jobs:
  build:
    timeout-minutes: 20
    runs-on: ubuntu-latest
    strategy:
      matrix:
        docker: ["single_cell", "graph_genome", "biotools", "hla", "assemble"]
    permissions:
      contents: read
      packages: write

Steps

standard steps

Some standard github action steps to includes are:

  • actions/checkout@v3: checking out the repo
  • docker/login-action: to login to the ghcr.io container registry, some more info can be found [here]
    steps:
      - name: Checkout repository
        uses: actions/checkout@v3

      - name: Log in to the Container registry
        uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

identifying the new changes

  • the tj-actions/changed-files helps identifying what files are changed. And we can couple this with the ${{ matrix.docker }}/Dockerfile variable to determine if there are any changes being made to each docker file.
      - name: Get changed files in the ${{ matrix.docker }} folder
        id: changed-files-specific
        uses: tj-actions/changed-files@v34
        with:
          files: |
            ${{ matrix.docker }}/Dockerfile

Building the docker container

  • we can use the standard docker/build-push-action, but adding a if: steps.changed-files-specific.outputs.any_changed == 'true' to use the above step to identify whether the build step is required for this container:

      - name: Build ${{ matrix.docker }}
        uses: docker/build-push-action@v2
        if: steps.changed-files-specific.outputs.any_changed == 'true'
        with:
          context: ./${{ matrix.docker }}
          file: ./${{ matrix.docker }}/Dockerfile
          platforms: linux/amd64
          push: true
          tags: |
            ghcr.io/${{ env.IMAGE_NAME_BASE }}/${{ matrix.docker }}:${{ github.sha }}
            ghcr.io/${{ env.IMAGE_NAME_BASE }}/${{ matrix.docker }}:latest