Uptodate Docker

If you have a matrix of Docker builds to do, or if you are already using uptodate to generate a matrix of builds, we have provided here a more streamlined way to generate a matrix of builds and then build from it.

1. Overview of Steps

For this short tutorial, we will be creating a GitHub action that builds an ubuntu container across a matrix of versions. You should read the uptodate docs for more complex examples. These steps include:

  1. Generating a Dockerfile with one or more build arguments, “args”
  2. Creating an uptodate.yaml file that maps out the specific versions in your matrix
  3. Adding the workflow with the action here!

And you can see the complete Example Workflow here along with the uptodate.yaml and Dockerfile that are used to populate the build matrix!

2. Create a Dockerfile

You’ll first want to create a Dockerfile. Typically this means something like the following:

ARG ubuntu_version=22.04
FROM ubuntu:${ubuntu_version}

RUN apt-get update && apt-get install -y cowsay
ENTRYPOINT ["cowsay"]

For the above, we have represented versions and anything we might want to treat as a variable as build arguments. As an example, the first build argument, ubuntu_version is how we will choose a base image. You can add other build arguments to further custom the logic of your Dockerfile.

3. uptodate.yaml

The uptodate.yaml is going to populate your build matrix. An example is provided below for our ubuntu container.

dockerbuild:

  build_args:
    ubuntu_version:
      key: ubuntu
      versions:
       - "18.04"
       - "20.04"
       - "22.04"

In the above, the build arg ubuntu_version will be populated with each of the listed versions. The key ubuntu will be used to populate the container name. You can then follow the example provided for your workflow. The name of the container will match to the relative path of where you run your build. For example:

# Root is here, in the action the inputs-> root variable below
docker/

   # This will be <registry>/<repo>/ubuntu:<tag>
   ubuntu/Dockerfile

And the tags are derived from the various variables in your matrix. E.g., for ubuntu:18.04 in this repository using the uptodate.yaml above and recipe below, you’d get ghcr.io/rse-ops/uptodate:ubuntu-18.04.

4. Create GitHub Action

Once you have your Dockerfile and uptodate.yaml, you can add your workflow! Notice that our root working directory is uptodate.

name: Container Build Matrices

on: 
  pull_request: []
  push:
    branches:
      - main
  workflow_dispatch:

jobs:
  generate:
    name: Generate Build Matrix
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.matrix.outputs.matrix }}
      is_empty: ${{ steps.matrix.outputs.is_empty }}
    steps:
    - uses: rse-ops/ci/uptodate/matrix@main
      id: matrix
      with:
        root: uptodate
        
  build:
    needs:
      - generate
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        result: ${{ fromJson(needs.generate.outputs.matrix) }}

    if: ${{ needs.generate.outputs.is_empty == 'false' }}
    name: "Build ${{ matrix.result.container_name }}"
    steps:
    - uses: rse-ops/ci/uptodate/build@main
      with:
        repo: rse-ops
        registry: ghcr.io
        deploy: "$"
        token: ${{ secrets.GITHUB_TOKEN }}
        container_name: ${{ matrix.result.container_name }}
        command_prefix: ${{ matrix.result.command_prefix }}
        dockerfile: ${{ matrix.result.filename }}

5. Full Example

For the full example, see the uptodate.yaml and matching Dockerfile in this directory, and the matching test-uptodate.yaml that uses it.