CI / ci (push) Successful in 2m37s
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).
121 lines
5.9 KiB
YAML
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
|