diff --git a/.github/workflows/qemu-emulator-build.yaml b/.github/workflows/qemu-emulator-build.yaml index 0957d80f0d..08b4ab62cc 100644 --- a/.github/workflows/qemu-emulator-build.yaml +++ b/.github/workflows/qemu-emulator-build.yaml @@ -80,7 +80,13 @@ jobs: - name: Generate emulator env run: node docker/local-emulator/generate-env-development.mjs + # VM boot + service verification is amd64-only. Under same-arch TCG on + # the arm64 runner there's no KVM, and the Next.js backend can't come + # up within any reasonable window under software emulation — same + # reason the build-time smoke test is skipped on arm64. The arm64 + # image is built and uploaded blind; it runs on real arm64 hardware. - name: Start emulator and verify + if: matrix.arch == 'amd64' run: | chmod +x docker/local-emulator/qemu/run-emulator.sh EMULATOR_ARCH=${{ matrix.arch }} \ @@ -88,12 +94,13 @@ jobs: docker/local-emulator/qemu/run-emulator.sh start - name: Verify services are healthy + if: matrix.arch == 'amd64' run: | EMULATOR_ARCH=${{ matrix.arch }} \ docker/local-emulator/qemu/run-emulator.sh status - name: Stop emulator - if: always() + if: always() && matrix.arch == 'amd64' run: | EMULATOR_ARCH=${{ matrix.arch }} \ docker/local-emulator/qemu/run-emulator.sh stop diff --git a/docker/local-emulator/qemu/cloud-init/emulator/user-data b/docker/local-emulator/qemu/cloud-init/emulator/user-data index c1d0d0f9bf..69481da602 100644 --- a/docker/local-emulator/qemu/cloud-init/emulator/user-data +++ b/docker/local-emulator/qemu/cloud-init/emulator/user-data @@ -399,28 +399,21 @@ write_files: - stack-local-emulator:final log "Flatten done." - log "Saving final image to /var/tmp..." + log "Pruning intermediate images in place..." docker rm flatten - docker save stack-local-emulator:final -o /var/tmp/final-image.tar - mv /var/lib/docker/volumes /var/tmp/volumes-backup - log "Nuking Docker storage and reloading..." - systemctl stop docker containerd - rm -rf /var/lib/docker /var/lib/containerd - systemctl start docker containerd - until docker info >/dev/null 2>&1; do sleep 1; done - docker load -i /var/tmp/final-image.tar + docker rmi stack-local-emulator stack-local-emulator-slim || true docker tag stack-local-emulator:final stack-local-emulator docker rmi stack-local-emulator:final || true - rm -f /var/tmp/final-image.tar - systemctl stop docker - rm -rf /var/lib/docker/volumes - mv /var/tmp/volumes-backup /var/lib/docker/volumes - systemctl start docker - log "Docker storage rebuilt." - - log "Zeroing free space for qcow2 compression..." - dd if=/dev/zero of=/zero.fill bs=1M 2>/dev/null || true - rm -f /zero.fill + docker builder prune -af || true + # Must be `prune -f` (dangling only), NOT `prune -af`. With -a, docker + # deletes every image that isn't referenced by a running/stopped + # container — at this point stack.service is only systemctl enable'd, + # not yet started, so the freshly-tagged stack-local-emulator image + # has zero container refs and would be nuked, bricking the final qcow2. + docker image prune -f || true + log "Intermediate images pruned." + + log "Releasing free space for qcow2 compression (fstrim)..." sync fstrim -av 2>/dev/null || true log "slim-docker-image done."