diff --git a/skills/gitea-ci/SKILL.md b/skills/gitea-ci/SKILL.md index 08c7522..837ac16 100644 --- a/skills/gitea-ci/SKILL.md +++ b/skills/gitea-ci/SKILL.md @@ -1,6 +1,6 @@ --- name: gitea-ci -description: End-to-end Gitea CI/CD setup with self-hosted act_runner, quality gate pipeline, buildah image build, k3s deploy, and GitHub mirror. Covers act_runner-specific gotchas that are not documented anywhere. +description: End-to-end Gitea CI/CD setup with self-hosted act_runner, quality gate pipeline, buildctl image build, k3s deploy, and GitHub mirror. Covers act_runner-specific gotchas that are not documented anywhere. --- # Gitea CI/CD Pipeline Setup @@ -31,7 +31,7 @@ Before writing any YAML, collect the following. Use AskUserQuestion for anything | Container registry | Ask or check existing config | `localhost:5000` on koala, or external | | k3s namespace | k8s/ manifests or ask | Deploy target | | GitHub mirror repo | Ask | Target for the mirror job | -| Image name | Ask or derive from repo name | Used in buildah + k3s steps | +| Image name | Ask or derive from repo name | Used in buildctl + k3s steps | Check the project's `CLAUDE.md` for infra notes first — often this answers most questions without needing to ask. @@ -135,33 +135,49 @@ jobs: - name: Build and push to local registry run: | + set -e + # buildctl, NOT buildah (infra#241). The runner is a pod with + # `capabilities: drop [ALL]` and `allowPrivilegeEscalation: false`, + # so rootless buildah cannot remap UID/GID for a fresh base-image + # pull and the pod has no OCI runtime -- every `RUN` step fails. + # buildctl is a thin client: it hands the build to the host's + # buildkitd over a socket, so the privileged work happens on the + # host and the pod's securityContext is not in the picture. + # The failure is LATENT -- warm base-image layers mask it, so a + # buildah step can look fine for weeks and then fail on a cold pull. + BUILDKIT_HOST="unix:///run/buildkit/buildkitd.sock" REGISTRY="localhost:5000" REF="${REGISTRY}/${{ env.IMAGE }}:${{ steps.meta.outputs.sha-tag }}" - buildah build \ - --label "org.opencontainers.image.revision=${{ github.sha }}" \ - --label "org.opencontainers.image.source=${{ github.repositoryUrl }}" \ - -t ${REF} \ - -t ${REGISTRY}/${{ env.IMAGE }}:latest \ - . - buildah push --tls-verify=false ${REF} - buildah push --tls-verify=false ${REGISTRY}/${{ env.IMAGE }}:latest - [[ -n "${{ steps.meta.outputs.version-tag }}" ]] && \ - buildah push --tls-verify=false \ - ${REF} \ - ${REGISTRY}/${{ env.IMAGE }}:${{ steps.meta.outputs.version-tag }} || true + TAR_FILE="$(mktemp)" + trap 'rm -f "$TAR_FILE"' EXIT + + buildctl --addr "$BUILDKIT_HOST" build \ + --frontend dockerfile.v0 \ + --local context=. \ + --local dockerfile=. \ + --opt label:org.opencontainers.image.revision="${{ github.sha }}" \ + --opt label:org.opencontainers.image.source="${{ github.repositoryUrl }}" \ + --output type=oci,dest="$TAR_FILE" + + # buildctl has no registry-push equivalent to `buildah push`; skopeo + # copies the OCI archive up, once per tag. + skopeo copy --dest-tls-verify=false \ + oci-archive:"$TAR_FILE" docker://${REF} + skopeo copy --dest-tls-verify=false \ + oci-archive:"$TAR_FILE" docker://${REGISTRY}/${{ env.IMAGE }}:latest + if [ -n "${{ steps.meta.outputs.version-tag }}" ]; then + skopeo copy --dest-tls-verify=false \ + oci-archive:"$TAR_FILE" \ + docker://${REGISTRY}/${{ env.IMAGE }}:${{ steps.meta.outputs.version-tag }} + fi echo "✓ Image pushed to ${REF}" - - name: Smoke test - run: | - REGISTRY="localhost:5000" - REF="${REGISTRY}/${{ env.IMAGE }}:${{ steps.meta.outputs.sha-tag }}" - CNAME="smoke-${{ steps.meta.outputs.sha-tag }}" - sudo k3s ctr images pull --plain-http ${REF} - OUTPUT=$(timeout 5 sudo k3s ctr run --rm ${REF} ${CNAME} / 2>&1 || true) - sudo k3s ctr containers delete ${CNAME} 2>/dev/null || true - echo "$OUTPUT" | grep -q "" \ - && echo "✓ Smoke test passed" \ - || echo "⚠ Smoke test inconclusive: $OUTPUT" + # No smoke test step. The one this skill used to recommend ran + # `sudo k3s ctr run` against the host's containerd -- that worked when + # the runner was the Arch host, and is impossible now that it is a pod: + # no sudo, no ctr, no containerd socket (`sudo: command not found`). + # The deploy job's `Verify rollout` + `Confirm pod running new image` + # below assert the same property against the real workload. # ── 3. Deploy to k3s ──────────────────────────────────────────────────────── deploy: