Files
ResInsight/.github/workflows/build-rhel8-image.yml
T
Magne Sjaastad 4b4bf29dfc Store RHEL8 image layer cache in GHCR instead of the Actions cache
The nightly image build has failed since 2026-07-23 with "failed to
solve: not_found" while exporting the BuildKit layer cache, because the
repository's GitHub Actions cache is at the 10 GB limit and entries are
evicted as fast as they are written (0% cache hit rate on restore).

Use a registry cache (ci-rhel8:buildcache in GHCR) instead, which has no
size cap, and exclude the buildcache tag from the daily image cleanup.

Make the cache effective across nightly rebuilds: key the vcpkg stage on
its actual inputs (vcpkg.json, the vcpkg configuration and the vcpkg
tool) with a direct manifest install instead of copying the entire build
context, and exclude .git from the Docker build context since its
internals differ between checkouts of the same commit and invalidated
'COPY . /src' on every run. Nightly builds now reuse the compiled vcpkg
ports from the layer cache and only recompile the ResInsight warmup
stage.
2026-07-27 15:38:46 +02:00

113 lines
4.2 KiB
YAML

name: Build RHEL8 CI Image
# Builds the Docker image used by the RHEL8 unit test workflow. The image bakes
# in the toolchain (gcc-toolset-14, libstdc++exp, Qt) and a prebuilt vcpkg
# binary cache so CI runs do not have to reprovision them every time.
on:
schedule:
# Nightly at 00:00 UTC, before the RHEL8 unit tests run at 02:00 UTC.
- cron: "0 0 * * *"
push:
paths:
- ".github/docker/Dockerfile.rhel8"
- ".github/workflows/build-rhel8-image.yml"
- ".dockerignore"
- "vcpkg.json"
- "vcpkg-configuration-rhel8.json"
- ".gitmodules"
workflow_dispatch:
inputs:
force_rebuild:
description: "Rebuild and overwrite today's image even if it already exists in GHCR"
type: boolean
default: false
concurrency:
group: build-rhel8-image
cancel-in-progress: false
jobs:
build-image:
runs-on: ubuntu-latest
# Cold first build runs the full ResInsight compile in the build-warmup
# stage (~1.5-2 h). Incremental nightly rebuilds reuse the BuildKit cache
# mount and finish much faster.
timeout-minutes: 180
permissions:
contents: read
packages: write
steps:
- name: Checkout
uses: actions/checkout@v7
with:
submodules: recursive
- name: Compute image name and tag
id: meta
run: |
image="ghcr.io/${GITHUB_REPOSITORY,,}/ci-rhel8"
date="$(date -u +%Y-%m-%d)"
repo_name_lc="${GITHUB_REPOSITORY##*/}"
repo_name_lc="${repo_name_lc,,}"
web_url="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/pkgs/container/${repo_name_lc}%2Fci-rhel8"
{
echo "image=$image"
echo "date=$date"
echo "web_url=$web_url"
} >> "$GITHUB_OUTPUT"
echo "Image refs : $image:latest"
echo " $image:$date"
echo "GHCR page : $web_url"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Log in to GitHub Container Registry
uses: docker/login-action@v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# The image build is expensive (cold ~1.5-2 h). If an image tagged with
# today's UTC date is already in GHCR, treat the build as already done
# for this day and skip. To force a same-day rebuild, dispatch the
# workflow with force_rebuild=true (or delete the dated tag from GHCR
# and rerun).
- name: Check if today's image already exists in GHCR
id: check
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ inputs.force_rebuild }}" == "true" ]]; then
echo "force_rebuild=true -- skipping existence check."
echo "exists=false" >> "$GITHUB_OUTPUT"
exit 0
fi
target="${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.date }}"
if docker buildx imagetools inspect "$target" >/dev/null 2>&1; then
echo "Image $target already exists -- skipping build."
echo "See: ${{ steps.meta.outputs.web_url }}"
echo "exists=true" >> "$GITHUB_OUTPUT"
else
echo "Image $target not found -- proceeding with build."
echo "exists=false" >> "$GITHUB_OUTPUT"
fi
- name: Build and push image
if: steps.check.outputs.exists != 'true'
uses: docker/build-push-action@v7
with:
context: .
file: .github/docker/Dockerfile.rhel8
push: true
tags: |
${{ steps.meta.outputs.image }}:latest
${{ steps.meta.outputs.image }}:${{ steps.meta.outputs.date }}
# Layer cache lives in GHCR instead of the GitHub Actions cache: the
# Actions cache has a 10 GB per-repo limit shared with all other
# workflows, so the multi-GB mode=max export was evicted immediately
# (0% hit rate) and the export itself started failing with
# "not_found" once the repo hit the cap.
cache-from: type=registry,ref=${{ steps.meta.outputs.image }}:buildcache
cache-to: type=registry,ref=${{ steps.meta.outputs.image }}:buildcache,mode=max,image-manifest=true