Skip to content

Commit dbd89b1

Browse files
authored
ci(spack): refresh the GHCR dependency buildcache from GitHub Actions (#342)
This workflow intentionally populates dependency binaries, but still builds `simphony` itself without autopush to keep the mirror focused on reusable dependencies. - add a scheduled/manual workflow to refresh the Spack dependency buildcache in GHCR - add a lightweight `spack-base` Docker target used only to bootstrap the workflow runtime - publish dependency binaries with Spack autopush, then verify the refreshed mirror from a clean container - limit `push` triggers to the files that actually affect buildcache production This job publishes binaries to GHCR, so it needs workflow-scoped credentials and clear publishing semantics. While Docker/BuildKit can pass secrets into `docker build`, putting `spack install` and registry writes inside a Dockerfile would couple a stateful publish step to image layer creation. Keeping the Spack commands in the workflow makes: - GHCR auth explicit - partial autopush progress survive a later failure - post-publish verification easy to run in a fresh container The Dockerfile stays responsible for building the runtime environment; the workflow stays responsible for mutating the external buildcache.
1 parent 1ed6074 commit dbd89b1

2 files changed

Lines changed: 168 additions & 3 deletions

File tree

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
name: Build Push Spack Buildcache
2+
3+
on:
4+
workflow_dispatch:
5+
schedule:
6+
- cron: '0 6 * * 1'
7+
push:
8+
branches:
9+
- main
10+
paths:
11+
- Dockerfile
12+
- .github/workflows/build-push-spack-buildcache.yaml
13+
14+
concurrency:
15+
group: ${{ github.workflow }}-${{ github.ref_name || github.event_name }}
16+
cancel-in-progress: true
17+
18+
permissions:
19+
contents: read
20+
packages: write
21+
22+
jobs:
23+
refresh-buildcache:
24+
runs-on: ubuntu-latest
25+
env:
26+
SPACK_BASE_IMAGE: simphony-spack-base:buildcache-${{ github.run_id }}
27+
SPACK_BASE_CACHE_SCOPE: spack-base-defaults
28+
29+
steps:
30+
- name: Checkout code
31+
uses: actions/checkout@v4
32+
33+
- name: Set up Docker Buildx
34+
uses: docker/setup-buildx-action@v3
35+
36+
- name: Build Spack base image
37+
uses: docker/build-push-action@v6
38+
with:
39+
context: .
40+
pull: true
41+
load: true
42+
target: spack-base
43+
tags: ${{ env.SPACK_BASE_IMAGE }}
44+
cache-from: type=gha,scope=${{ env.SPACK_BASE_CACHE_SCOPE }}
45+
cache-to: type=gha,mode=max,scope=${{ env.SPACK_BASE_CACHE_SCOPE }}
46+
47+
# Keep the Spack install/publish phase in the workflow instead of a Dockerfile
48+
# RUN step. BuildKit secrets could pass GHCR credentials into `docker build`,
49+
# but registry writes are easier to reason about as explicit workflow side
50+
# effects, and this keeps partial autopush progress plus cache verification
51+
# separate from image layer creation.
52+
- name: Populate dependency buildcache
53+
run: |
54+
docker run --rm \
55+
-e REGISTRY_USER='${{ github.actor }}' \
56+
-e REGISTRY_TOKEN='${{ secrets.GITHUB_TOKEN }}' \
57+
'${{ env.SPACK_BASE_IMAGE }}' \
58+
bash -lc '
59+
set -euo pipefail
60+
61+
# Spack 1.x keeps the builtin package repo in the separate spack-packages git
62+
# repository, so we can keep the Spack tool pinned while still floating package
63+
# metadata to the latest builtin develop branch on each run.
64+
spack repo update -b develop builtin
65+
# Fetch the latest simphony package metadata from the external repo as well.
66+
spack repo add https://github.com/BNLNPPS/spack-packages
67+
# Use a dedicated GHCR package for the Spack OCI mirror so Docker cache cleanup
68+
# jobs cannot prune buildcache artifacts behind the Spack mirror.
69+
spack mirror add --autopush --unsigned --oci-username-variable REGISTRY_USER --oci-password-variable REGISTRY_TOKEN simphony-spack-buildcache "${SPACK_BUILDCACHE_MIRROR}"
70+
spack external find --not-buildable --path /usr/local/cuda cuda
71+
72+
# Autopush dependencies as soon as source builds complete, so partial progress
73+
# survives a failed long-running buildcache refresh.
74+
spack install --only=dependencies --reuse --use-buildcache auto simphony ^geant4@${GEANT4_VERSION} ^optix-dev@${OPTIX_VERSION}
75+
76+
# Update the index after dependency autopush so partial progress is immediately discoverable.
77+
spack buildcache update-index simphony-spack-buildcache
78+
79+
# Keep the cache focused on dependencies; the PR workflow still builds simphony itself.
80+
spack mirror set --no-autopush simphony-spack-buildcache
81+
spack install --reuse --use-buildcache package:never,dependencies:auto simphony ^geant4@${GEANT4_VERSION} ^optix-dev@${OPTIX_VERSION}
82+
83+
# Ensure the index is current after the full run as well.
84+
spack buildcache update-index simphony-spack-buildcache
85+
'
86+
87+
- name: Verify dependency buildcache
88+
run: |
89+
docker run --rm \
90+
'${{ env.SPACK_BASE_IMAGE }}' \
91+
bash -lc '
92+
set -euo pipefail
93+
94+
# Match the publish step by floating the builtin spack-packages repo while keeping
95+
# the Spack tool itself pinned in spack-base.
96+
spack repo update -b develop builtin
97+
# Fetch the latest simphony package metadata from the external repo as well.
98+
spack repo add https://github.com/BNLNPPS/spack-packages
99+
spack mirror add --unsigned simphony-spack-buildcache "${SPACK_BUILDCACHE_MIRROR}"
100+
spack external find --not-buildable --path /usr/local/cuda cuda
101+
spack install --only=dependencies --use-buildcache only simphony ^geant4@${GEANT4_VERSION} ^optix-dev@${OPTIX_VERSION}
102+
'
103+
104+
- name: Cleanup local base image
105+
if: ${{ always() }}
106+
run: |
107+
docker image rm -f '${{ env.SPACK_BASE_IMAGE }}' || true
108+
109+
cleanup-buildcache-registry:
110+
if: ${{ always() && needs.refresh-buildcache.result != 'skipped' }}
111+
needs: refresh-buildcache
112+
runs-on: ubuntu-latest
113+
permissions:
114+
contents: read
115+
packages: write
116+
117+
steps:
118+
- name: Define cleanup targets
119+
run: |
120+
PACKAGE_NAME=$(echo "${{ github.event.repository.name }}-spack-buildcache" | tr '[:upper:]' '[:lower:]')
121+
echo "PACKAGE_NAME=${PACKAGE_NAME}" >> "$GITHUB_ENV"
122+
123+
- name: Cleanup stale untagged GHCR versions
124+
uses: dataaxiom/ghcr-cleanup-action@v1
125+
with:
126+
packages: ${{ env.PACKAGE_NAME }}
127+
# Keep a small buffer so the cleanup pass does not race just-published manifests.
128+
delete-untagged: true
129+
older-than: 1 day

Dockerfile

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@
22

33
ARG OS=ubuntu24.04
44
ARG CUDA_VERSION=13.0.2
5-
6-
FROM nvidia/cuda:${CUDA_VERSION}-devel-${OS} AS base
7-
85
ARG OPTIX_VERSION=9.0.0
96
ARG GEANT4_VERSION=11.4.1
107
ARG CMAKE_VERSION=4.2.1
8+
ARG SPACK_BUILDCACHE_MIRROR=oci://ghcr.io/bnlnpps/simphony-spack-buildcache
9+
10+
FROM nvidia/cuda:${CUDA_VERSION}-devel-${OS} AS base
11+
12+
ARG OPTIX_VERSION
13+
ARG GEANT4_VERSION
14+
ARG CMAKE_VERSION
1115
ARG CMAKE_BUILD_JOBS
1216

1317
ENV DEBIAN_FRONTEND=noninteractive
@@ -100,3 +104,35 @@ COPY . $OPTICKS_HOME
100104

101105
RUN cmake -S $OPTICKS_HOME -B $OPTICKS_BUILD -DCMAKE_INSTALL_PREFIX=$OPTICKS_PREFIX -DCMAKE_BUILD_TYPE=Debug \
102106
&& cmake --build $OPTICKS_BUILD --parallel "${CMAKE_BUILD_JOBS:-$(nproc)}" --target install
107+
108+
109+
FROM nvidia/cuda:${CUDA_VERSION}-devel-${OS} AS spack-base
110+
111+
ARG OPTIX_VERSION
112+
ARG GEANT4_VERSION
113+
ARG SPACK_BUILDCACHE_MIRROR
114+
ARG SPACK_VERSION=1.1.1
115+
116+
ENV DEBIAN_FRONTEND=noninteractive
117+
118+
# Install Spack package manager
119+
RUN apt update \
120+
&& apt install -y build-essential ca-certificates coreutils curl gfortran git gpg lsb-release unzip zip python3 \
121+
&& apt clean \
122+
&& rm -rf /var/lib/apt/lists/*
123+
124+
RUN mkdir -p /opt/spack && curl -fsSL https://github.com/spack/spack/archive/v${SPACK_VERSION}.tar.gz | tar -xz --strip-components 1 -C /opt/spack
125+
RUN echo "source /opt/spack/share/spack/setup-env.sh" > /etc/profile.d/z09_source_spack_setup.sh
126+
RUN echo "source /etc/profile.d/z09_source_spack_setup.sh" >> /etc/bash.bashrc
127+
128+
ENV BASH_ENV=/etc/profile.d/z09_source_spack_setup.sh
129+
ENV OPTICKS_HOME=/workspaces/simphony
130+
ENV OPTIX_VERSION=${OPTIX_VERSION}
131+
ENV GEANT4_VERSION=${GEANT4_VERSION}
132+
ENV SPACK_BUILDCACHE_MIRROR=${SPACK_BUILDCACHE_MIRROR}
133+
ENV PATH=/opt/spack/bin:${PATH}
134+
ENV NVIDIA_DRIVER_CAPABILITIES=graphics,compute,utility
135+
136+
WORKDIR ${OPTICKS_HOME}
137+
138+
SHELL ["/bin/bash", "-l", "-c"]

0 commit comments

Comments
 (0)