ci: stop disk reclaim from deleting a smoke image mid-test
v1.12.2 run 740: build-variant's `docker system prune -af --volumes` untagged pi-devbox:smoke-studio 30 ms after smoke-studio loaded it, so every studio assertion failed and the -studio tags were not published. All jobs share the runner's Docker daemon, and a smoke image is unused between smoke-test.sh's one-shot `docker run`s. - scripts/ci-reclaim-docker.sh: the same reclaim, per object type, but never prunes an image labelled se.jordbo.pi-devbox.ci-smoke-image; labelled orphans are swept after 6h. `assert-protected IMG` is the smoke preflight; `lint WORKFLOW...` rejects raw system/image prunes. - smoke jobs: label their image, assert it, tag it per run (pi-devbox:smoke[-studio]-<run_id>), remove it in an always() step. - all five reclaim sites call the script; lint.yml runs the guard. - Job order unchanged: studio jobs still gate only the -studio tags. Verified on an isolated docker:29-dind (old prune deletes a labelled image; new reclaim keeps it, removes unlabelled + 1970-created labelled images, spares an in-use image, no errors); actionlint, shellcheck, lint-shell, check-workflow-shell, check-doc-drift all clean.
This commit is contained in:
@@ -90,6 +90,12 @@ env:
|
||||
IMAGE: ${{ vars.DOCKERHUB_USERNAME }}/pi-devbox
|
||||
RELEASE_TAG: ${{ github.ref_type == 'tag' && github.ref_name || inputs.release_tag }}
|
||||
PROMOTE_LATEST: ${{ github.ref_type == 'tag' && 'true' || inputs.promote_latest }}
|
||||
# Label that protects a smoke job's loaded image from the disk reclaim every
|
||||
# job runs on the shared runner daemon (scripts/ci-reclaim-docker.sh says
|
||||
# why: v1.12.2 run 740 lost pi-devbox:smoke-studio to build-variant's prune
|
||||
# 30 ms after loading it). Set once here; the smoke builds apply it, the
|
||||
# reclaim script honours it, the smoke preflight asserts it.
|
||||
SMOKE_IMAGE_LABEL: se.jordbo.pi-devbox.ci-smoke-image
|
||||
|
||||
jobs:
|
||||
# ── Phase 1: decide whether base needs rebuilding ──────────────────
|
||||
@@ -538,8 +544,7 @@ jobs:
|
||||
/usr/lib/jvm 2>/dev/null || true
|
||||
apt-get clean || true
|
||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* || true
|
||||
docker system prune -af --volumes || true
|
||||
docker builder prune -af || true
|
||||
bash scripts/ci-reclaim-docker.sh
|
||||
df -h / || true
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
@@ -597,6 +602,10 @@ jobs:
|
||||
needs.resolve-versions.result == 'success' &&
|
||||
(needs.build-base.result == 'success' || needs.build-base.result == 'skipped')
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
# Per run, so two runs on different refs cannot test or delete each
|
||||
# other's image on the shared daemon. run_id is stable across re-runs.
|
||||
SMOKE_IMAGE: pi-devbox:smoke-${{ github.run_id }}
|
||||
container:
|
||||
image: catthehacker/ubuntu:act-latest
|
||||
steps:
|
||||
@@ -610,8 +619,7 @@ jobs:
|
||||
/usr/local/lib/android /usr/local/share/powershell \
|
||||
/usr/local/share/chromium /usr/local/share/boost \
|
||||
/usr/lib/jvm 2>/dev/null || true
|
||||
docker system prune -af --volumes || true
|
||||
docker builder prune -af || true
|
||||
bash scripts/ci-reclaim-docker.sh
|
||||
- uses: docker/setup-buildx-action@v4
|
||||
with: {driver-opts: network=host}
|
||||
- uses: docker/login-action@v3
|
||||
@@ -626,7 +634,8 @@ jobs:
|
||||
platforms: linux/amd64
|
||||
push: false
|
||||
load: true
|
||||
tags: pi-devbox:smoke
|
||||
tags: ${{ env.SMOKE_IMAGE }}
|
||||
labels: ${{ env.SMOKE_IMAGE_LABEL }}=true
|
||||
build-args: |
|
||||
BASE_IMAGE=${{ env.IMAGE }}:${{ needs.base-decide.outputs.base_tag }}
|
||||
PI_VERSION=${{ needs.resolve-versions.outputs.pi_version }}
|
||||
@@ -648,7 +657,14 @@ jobs:
|
||||
# Asserting the BUILT image matches it also catches a stale cached layer.
|
||||
EXPECTED_NODE_MAJOR=$(sed -n 's/^ARG NODE_VERSION=\([0-9][0-9]*\).*/\1/p' Dockerfile.base)
|
||||
export EXPECTED_NODE_MAJOR
|
||||
bash scripts/smoke-test.sh pi-devbox:smoke
|
||||
bash scripts/ci-reclaim-docker.sh assert-protected "$SMOKE_IMAGE"
|
||||
bash scripts/smoke-test.sh "$SMOKE_IMAGE"
|
||||
# The label keeps this image from every job's reclaim, so it is removed
|
||||
# here instead. A job killed before this step leaves an orphan, which the
|
||||
# reclaim's age sweep deletes once it is older than SMOKE_IMAGE_MAX_AGE.
|
||||
- name: Remove smoke image
|
||||
if: always()
|
||||
run: docker image rm "$SMOKE_IMAGE" || true
|
||||
|
||||
# ── Phase 3b: amd64 smoke for the studio variant ────────────────────
|
||||
# Additive + independent of the core `smoke` job: gates ONLY
|
||||
@@ -662,6 +678,10 @@ jobs:
|
||||
needs.resolve-versions.result == 'success' &&
|
||||
(needs.build-base.result == 'success' || needs.build-base.result == 'skipped')
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
# Per run, so two runs on different refs cannot test or delete each
|
||||
# other's image on the shared daemon. run_id is stable across re-runs.
|
||||
SMOKE_IMAGE: pi-devbox:smoke-studio-${{ github.run_id }}
|
||||
container:
|
||||
image: catthehacker/ubuntu:act-latest
|
||||
steps:
|
||||
@@ -675,8 +695,7 @@ jobs:
|
||||
/usr/local/lib/android /usr/local/share/powershell \
|
||||
/usr/local/share/chromium /usr/local/share/boost \
|
||||
/usr/lib/jvm 2>/dev/null || true
|
||||
docker system prune -af --volumes || true
|
||||
docker builder prune -af || true
|
||||
bash scripts/ci-reclaim-docker.sh
|
||||
- uses: docker/setup-buildx-action@v4
|
||||
with: {driver-opts: network=host}
|
||||
- uses: docker/login-action@v3
|
||||
@@ -691,7 +710,8 @@ jobs:
|
||||
platforms: linux/amd64
|
||||
push: false
|
||||
load: true
|
||||
tags: pi-devbox:smoke-studio
|
||||
tags: ${{ env.SMOKE_IMAGE }}
|
||||
labels: ${{ env.SMOKE_IMAGE_LABEL }}=true
|
||||
build-args: |
|
||||
BASE_IMAGE=${{ env.IMAGE }}:${{ needs.base-decide.outputs.base_tag }}
|
||||
PI_VERSION=${{ needs.resolve-versions.outputs.pi_version }}
|
||||
@@ -716,7 +736,14 @@ jobs:
|
||||
# Asserting the BUILT image matches it also catches a stale cached layer.
|
||||
EXPECTED_NODE_MAJOR=$(sed -n 's/^ARG NODE_VERSION=\([0-9][0-9]*\).*/\1/p' Dockerfile.base)
|
||||
export EXPECTED_NODE_MAJOR
|
||||
bash scripts/smoke-test.sh pi-devbox:smoke-studio
|
||||
bash scripts/ci-reclaim-docker.sh assert-protected "$SMOKE_IMAGE"
|
||||
bash scripts/smoke-test.sh "$SMOKE_IMAGE"
|
||||
# The label keeps this image from every job's reclaim, so it is removed
|
||||
# here instead. A job killed before this step leaves an orphan, which the
|
||||
# reclaim's age sweep deletes once it is older than SMOKE_IMAGE_MAX_AGE.
|
||||
- name: Remove smoke image
|
||||
if: always()
|
||||
run: docker image rm "$SMOKE_IMAGE" || true
|
||||
|
||||
# ── Phase 4: multi-arch publish ─────────────────────────────────────
|
||||
build-variant:
|
||||
@@ -741,8 +768,7 @@ jobs:
|
||||
/usr/local/lib/android /usr/local/share/powershell \
|
||||
/usr/local/share/chromium /usr/local/share/boost \
|
||||
/usr/lib/jvm 2>/dev/null || true
|
||||
docker system prune -af --volumes || true
|
||||
docker builder prune -af || true
|
||||
bash scripts/ci-reclaim-docker.sh
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
with: {platforms: arm64}
|
||||
- uses: docker/setup-buildx-action@v4
|
||||
@@ -834,8 +860,7 @@ jobs:
|
||||
/usr/local/lib/android /usr/local/share/powershell \
|
||||
/usr/local/share/chromium /usr/local/share/boost \
|
||||
/usr/lib/jvm 2>/dev/null || true
|
||||
docker system prune -af --volumes || true
|
||||
docker builder prune -af || true
|
||||
bash scripts/ci-reclaim-docker.sh
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
with: {platforms: arm64}
|
||||
- uses: docker/setup-buildx-action@v4
|
||||
|
||||
Reference in New Issue
Block a user