Docker on GitHub Actions

Docker images are useful for reproducibility and ease of setup and for software binary distribution on platforms not natively available on GitHub Actions runner images. While one can setup a custom Docker image, it’s often possible to simply use an existing official image from Docker Hub.

Example: Ubuntu 20.04

This example GitHub Actions workflow uses the Ubuntu 20.04 image to build a C++ binary with the GNU C++ compiler. For APT operations, the “-y” option is necessary. Environment variable DEBIAN_FRONTEND is set to “noninteractive” to avoid interactive prompts for certain operations despite “-y”. Don’t use “sudo” as the container user is root and the “sudo” package is not installed.

A special feature of this example is using Kitware’s CMake APT repo to install the latest version of CMake on an EOL Ubuntu distro.

name: ubuntu-20.04

on: [push]

# avoid wasted runs
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  ubuntu-20.04:
    runs-on: ubuntu-latest
    container:
      image: ubuntu:20.04
      env:
        DEBIAN_FRONTEND: noninteractive

    strategy:
      fail-fast: false
      matrix:
        gcc-version: [7, 8]

    env:
      CC: gcc-${{ matrix.gcc-version }}
      CXX: g++-${{ matrix.gcc-version }}
      FC: gfortran-${{ matrix.gcc-version }}

    steps:

    - name: install compilers
      run: |
        apt update -y
        apt install -y --no-install-recommends ca-certificates gpg curl ninja-build ${{ env.CC }} ${{ env.CXX }} ${{ env.FC }}

    - name: install CMake
      run: |
        curl -s https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null
        echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ focal main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null
        apt-get update
        test -f /usr/share/doc/kitware-archive-keyring/copyright || rm /usr/share/keyrings/kitware-archive-keyring.gpg
        apt-get install --no-install-recommends -y kitware-archive-keyring
        apt-get install --no-install-recommends -y cmake

    - uses: actions/checkout@v4

    - name: CMake configure
      run: cmake -B build

    - name: CMake build
      run: cmake --build build

    - name: CMake test
      run: ctest --test-dir build

Example: Alpine Linux

This example GitHub Actions workflow uses the Alpine Linux image with the MUSL C library to build a statically-linked binary.

name: alpine-musl

on: [push]

jobs:
  musl:
    runs-on: ubuntu-latest
    container:
      image: alpine

    steps:
    - uses: actions/checkout@v4

    - name: install build tools
      run: apk add --no-cache ninja-build cmake make gfortran openmpi-dev

    - name: print MUSL version
      continue-on-error: true
      run: ldd --version

    - name: CMake configure
      run: cmake -B build

    - name: CMake build
      run: cmake --build build

# Good idea to ensure self-tests pass before packaging
    - name: CMake test
      run: ctest --test-dir build

(Optional) If a CPack archive is desired add step:

    - name: CMake package
      if: success()
      run: cpack --config build/CPackConfig.cmake

The binary artifact or CPack archive can be uploaded by step upload-artifact:

    - name: .exe for release
      uses: actions/upload-artifact@v4
      if: success()
      with:
        name: my.exe
        path: build/my.exe