Skip to content
Latchkey

Ubuntu: Build and push ubuntu-toolbox images workflow (containers/toolbox)

The Ubuntu: Build and push ubuntu-toolbox images workflow from containers/toolbox, explained and optimized by Latchkey.

B

CI health: B - good

Point runs-on at Latchkey and get job timeouts, SHA-pinned actions, self-healing for flaky steps, and up to 58% lower cost, applied automatically.

Grade your own workflow free or run it on Latchkey →
Source: containers/toolbox.github/workflows/ubuntu-images.yamlLicense Apache-2.0View source

What it does

This is the Ubuntu: Build and push ubuntu-toolbox images workflow from the containers/toolbox repository, a real project running GitHub Actions. It is shown here with attribution under its Apache-2.0 license.

Below, Latchkey shows a faster, safer version produced by its optimization engine.

The workflow

workflow (.yml)
name: "Ubuntu: Build and push ubuntu-toolbox images"

permissions: read-all

on:
  pull_request:
    branches:
      - main
    paths:
      - images/ubuntu/**
      - .github/workflows/ubuntu-images.yaml
  push:
    branches:
      - main
    paths:
      - images/ubuntu/**
      - .github/workflows/ubuntu-images.yaml
  schedule:
    - cron: '0 0 * * MON'

env:
  distro: 'ubuntu'
  latest_release: '24.04'
  platforms: 'linux/amd64, linux/arm64'
  registry: 'quay.io/toolbx'
  username: 'toolbx+github'

# Prevent multiple workflow runs from racing to ensure that pushes are made
# sequentially for the main branch. Also cancel in progress workflow runs for
# pull requests only.
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
  build-push-images:
    strategy:
      matrix:
        release: ['18.04', '20.04', '22.04', '24.04', '25.04', '25.10', '26.04']
      fail-fast: false

    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up QEMU for multi-arch builds
        shell: bash
        run: |
          sudo apt update
          sudo apt install qemu-user-static

      - name: Build container image
        uses: redhat-actions/buildah-build@v2
        if: env.latest_release != matrix.release
        with:
          platforms: ${{ env.platforms }}
          context: images/${{ env.distro }}/${{ matrix.release }}
          image: ${{ env.distro }}-toolbox
          tags: ${{ matrix.release }}
          containerfiles: images/${{ env.distro }}/${{ matrix.release }}/Containerfile
          layers: false
          oci: true

      - name: Build container image (latest tag)
        uses: redhat-actions/buildah-build@v2
        if: env.latest_release == matrix.release
        with:
          platforms: ${{ env.platforms }}
          context: images/${{ env.distro }}/${{ matrix.release }}
          image: ${{ env.distro }}-toolbox
          tags: ${{ matrix.release }} latest
          containerfiles: images/${{ env.distro }}/${{ matrix.release }}/Containerfile
          layers: false
          oci: true

      - name: Push to Container Registry
        uses: redhat-actions/push-to-registry@v2
        id: push
        if: (github.event_name == 'push' || github.event_name == 'schedule') && github.ref == 'refs/heads/main' && env.latest_release != matrix.release
        with:
          username: ${{ env.username }}
          password: ${{ secrets.QUAY_ROBOT_TOKEN }}
          image: ${{ env.distro }}-toolbox
          registry: ${{ env.registry }}
          tags: ${{ matrix.release }}

      - name: Push to Container Registry (latest tag)
        uses: redhat-actions/push-to-registry@v2
        id: push-latest
        if: (github.event_name == 'push' || github.event_name == 'schedule') && github.ref == 'refs/heads/main' && env.latest_release == matrix.release
        with:
          username: ${{ env.username }}
          password: ${{ secrets.QUAY_ROBOT_TOKEN }}
          image: ${{ env.distro }}-toolbox
          registry: ${{ env.registry }}
          tags: ${{ matrix.release }} latest

The same workflow, on Latchkey

Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.

name: "Ubuntu: Build and push ubuntu-toolbox images"
 
permissions: read-all
 
on:
  pull_request:
    branches:
      - main
    paths:
      - images/ubuntu/**
      - .github/workflows/ubuntu-images.yaml
  push:
    branches:
      - main
    paths:
      - images/ubuntu/**
      - .github/workflows/ubuntu-images.yaml
  schedule:
    - cron: '0 0 * * MON'
 
env:
  distro: 'ubuntu'
  latest_release: '24.04'
  platforms: 'linux/amd64, linux/arm64'
  registry: 'quay.io/toolbx'
  username: 'toolbx+github'
 
# Prevent multiple workflow runs from racing to ensure that pushes are made
# sequentially for the main branch. Also cancel in progress workflow runs for
# pull requests only.
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: ${{ github.event_name == 'pull_request' }}
 
jobs:
  build-push-images:
    timeout-minutes: 30
    strategy:
      matrix:
        release: ['18.04', '20.04', '22.04', '24.04', '25.04', '25.10', '26.04']
      fail-fast: false
 
    runs-on: latchkey-small
    steps:
      - name: Checkout
        uses: actions/checkout@v4
 
      - name: Set up QEMU for multi-arch builds
        shell: bash
        run: |
          sudo apt update
          sudo apt install qemu-user-static
 
      - name: Build container image
        uses: redhat-actions/buildah-build@v2
        if: env.latest_release != matrix.release
        with:
          platforms: ${{ env.platforms }}
          context: images/${{ env.distro }}/${{ matrix.release }}
          image: ${{ env.distro }}-toolbox
          tags: ${{ matrix.release }}
          containerfiles: images/${{ env.distro }}/${{ matrix.release }}/Containerfile
          layers: false
          oci: true
 
      - name: Build container image (latest tag)
        uses: redhat-actions/buildah-build@v2
        if: env.latest_release == matrix.release
        with:
          platforms: ${{ env.platforms }}
          context: images/${{ env.distro }}/${{ matrix.release }}
          image: ${{ env.distro }}-toolbox
          tags: ${{ matrix.release }} latest
          containerfiles: images/${{ env.distro }}/${{ matrix.release }}/Containerfile
          layers: false
          oci: true
 
      - name: Push to Container Registry
        uses: redhat-actions/push-to-registry@v2
        id: push
        if: (github.event_name == 'push' || github.event_name == 'schedule') && github.ref == 'refs/heads/main' && env.latest_release != matrix.release
        with:
          username: ${{ env.username }}
          password: ${{ secrets.QUAY_ROBOT_TOKEN }}
          image: ${{ env.distro }}-toolbox
          registry: ${{ env.registry }}
          tags: ${{ matrix.release }}
 
      - name: Push to Container Registry (latest tag)
        uses: redhat-actions/push-to-registry@v2
        id: push-latest
        if: (github.event_name == 'push' || github.event_name == 'schedule') && github.ref == 'refs/heads/main' && env.latest_release == matrix.release
        with:
          username: ${{ env.username }}
          password: ${{ secrets.QUAY_ROBOT_TOKEN }}
          image: ${{ env.distro }}-toolbox
          registry: ${{ env.registry }}
          tags: ${{ matrix.release }} latest
 

What changed

2 third-party actions are referenced by a movable tag. Pin them to the commit SHA (Latchkey resolves and applies this automatically) so a repointed tag cannot change what runs.

What Latchkey heals here

This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:

This workflow runs 1 job (7 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.

Actions used in this workflow