Files
bcs-website/.gitea/workflows/ci.yml
T
bmr_bluecap c19b2b2af4
CI / ci (push) Successful in 2m37s
ci: install docker + kustomize as static binaries, not distro packages
CI has been failing silently since 2026-08-03. The run for 9f1cbca did
execute (Gitea action_run #6, status=failure, 13m) but died before pushing an
image, so no package version exists for that commit and ArgoCD has been
serving the 2026-07-20 build ever since.

Cause: the "Ensure docker + kustomize are available" step ran
`apt-get install -y docker.io`. The runner's job image was node:18-bullseye
and Debian 11 went EOL, so debian-security stopped serving those package
versions. `apt-get update` still succeeds, so the failure surfaces only at
install time as 404s on docker.io, containerd, systemd and libcap2.

Fetch both tools as pinned static binaries instead. These have no distro
archive dependency, so the same rot cannot recur when bookworm ages out.
Verified in the real job environment: the static client installs and reaches
the host daemon through the mounted socket.

The runner job image has separately been moved to node:22-bookworm, which
also resolves the immediate breakage, but the static-binary approach is kept
as the durable fix.

Also refresh the prerequisites header: items 3 and 4 still described the
pre-ADR-0008 registry design (k3s now pulls over public HTTPS, and the
private package's pull auth comes from External Secrets).
2026-09-22 15:45:57 -04:00

121 lines
5.9 KiB
YAML

# BlueCap Strategies CI — Gitea Actions (ADR-0007)
#
# Pipeline: install → build (typecheck) → seo:lint → e2e → build & push image to Gitea Packages
# → bump the image tag in k8s/ and commit back to main. ArgoCD then reconciles k3s.
#
# PREREQUISITES (homelab, verify before the first run — see docs/gitops-deployment-strategy.md):
# 1. Docker must be usable from the job container. The runner mounts /var/run/docker.sock; if
# jobs can't see it, enable socket passthrough in act_runner config or switch this to kaniko.
# 2. The RUNNER HOST's dockerd must treat 10.66.15.22:3000 as an insecure (HTTP) registry
# ("insecure-registries": ["10.66.15.22:3000"] in /etc/docker/daemon.json).
# 3. K3S does NOT need registries.yaml — it pulls the same package over public HTTPS
# (git.7tl-homelab.com, valid cert). See ADR-0008. No node config, no cluster restart.
# 4. The Gitea package is PRIVATE; k3s pull auth comes from External Secrets ->
# k8s/externalsecret-registry.yaml -> `gitea-registry` imagePullSecret. See ADR-0008.
# 5. secrets.GITEA_TOKEN (auto-injected per run) needs write access to this repo (tag-bump commit)
# and the package registry.
name: CI
on:
push:
branches: [main]
# Don't re-trigger on the CI tag-bump commit (touches k8s/) or docs-only changes.
paths-ignore:
- 'k8s/**'
- 'docs/**'
- 'planning/**'
- '**/*.md'
env:
# Push over the internal HTTP endpoint (fast, no edge; host dockerd trusts it as insecure).
PUSH_IMAGE: 10.66.15.22:3000/bmr_bluecap/bcs-website
# k3s pulls over the public HTTPS endpoint (valid TLS -> no registries.yaml / node config / restart).
# Same Gitea package as PUSH_IMAGE, just a different access path.
DEPLOY_IMAGE: git.7tl-homelab.com/bmr_bluecap/bcs-website
jobs:
ci:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Node 22
uses: actions/setup-node@v4
with:
node-version: 22
- name: Install dependencies
run: npm ci
- name: Build (typecheck + astro build)
run: npm run build
- name: SEO lint
run: npm run seo:lint
# Playwright e2e (headless Chrome) is intentionally NOT run in CI — it's the heaviest step and
# adds little for a static site over `astro build` + seo:lint. Run it locally: `npm run test:e2e`.
- name: Compute image tag
id: tag
run: echo "sha=$(echo ${{ github.sha }} | cut -c1-12)" >> "$GITHUB_OUTPUT"
# Both tools are fetched as STATIC BINARIES, never from distro packages.
# History: this step used `apt-get install -y docker.io`, which broke CI on 2026-08-03 when
# Debian 11 (bullseye — the runner's job image is node:18-bullseye) went EOL and the
# debian-security pool stopped serving those package versions. `apt-get update` still
# succeeds, so the failure surfaces only at install time as a wall of 404s. Static binaries
# have no distro-archive dependency and pin an exact version, so this cannot rot the same way.
- name: Ensure docker + kustomize are available
env:
DOCKER_CLI_VERSION: '28.3.2'
KUSTOMIZE_VERSION: 'v5.4.3'
run: |
set -euo pipefail
if ! command -v docker >/dev/null 2>&1; then
curl -sSL --retry 3 --retry-delay 5 \
"https://download.docker.com/linux/static/stable/x86_64/docker-${DOCKER_CLI_VERSION}.tgz" -o /tmp/docker.tgz
# We only need the client; the daemon is the runner host's, via the mounted socket.
tar xzf /tmp/docker.tgz -C /tmp --strip-components=1 docker/docker
install -m 0755 /tmp/docker /usr/local/bin/docker
fi
if ! command -v kustomize >/dev/null 2>&1; then
curl -sSL --retry 3 --retry-delay 5 \
"https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2F${KUSTOMIZE_VERSION}/kustomize_${KUSTOMIZE_VERSION}_linux_amd64.tar.gz" \
| tar xz -C /usr/local/bin
fi
docker version --format 'docker client={{.Client.Version}} server={{.Server.Version}}'
kustomize version
# CI_TOKEN: a Gitea Personal Access Token (scopes: write:package, write:repository) owned by
# the repo owner, stored as a repo Actions secret. The auto GITEA_TOKEN lacks reliable package
# scope on Gitea, hence a dedicated PAT for both the registry push and the tag-bump commit.
- name: Build & push image to Gitea Packages
run: |
echo "${{ secrets.CI_TOKEN }}" | docker login 10.66.15.22:3000 -u "${{ github.repository_owner }}" --password-stdin
docker build -t "$PUSH_IMAGE:${{ steps.tag.outputs.sha }}" -t "$PUSH_IMAGE:latest" .
# Registry pushes can time out on a slow blob; docker push is resumable, so retry.
push_retry() {
for i in 1 2 3 4 5; do
docker push "$1" && return 0
echo "push of $1 failed (attempt $i), retrying in 10s..."
sleep 10
done
return 1
}
push_retry "$PUSH_IMAGE:${{ steps.tag.outputs.sha }}"
push_retry "$PUSH_IMAGE:latest"
- name: Bump k8s image tag and commit back
run: |
git config user.name "gitea-actions[bot]"
git config user.email "gitea-actions@bmr_bluecap"
# Deployment references the public HTTPS image (what k3s pulls); bump its tag.
(cd k8s && kustomize edit set image "$DEPLOY_IMAGE=$DEPLOY_IMAGE:${{ steps.tag.outputs.sha }}")
git add k8s/kustomization.yaml
git diff --cached --quiet && { echo "no image change"; exit 0; }
git commit -m "ci: deploy ${{ steps.tag.outputs.sha }} [skip ci]"
git remote set-url origin "http://${{ github.repository_owner }}:${{ secrets.CI_TOKEN }}@10.66.15.22:3000/bmr_bluecap/bcs-website.git"
git push origin HEAD:main