Hermes Agent 883e264c42
Some checks failed
build-and-deploy / test (push) Failing after 2m36s
build-and-deploy / build-deploy (push) Has been skipped
chore: seed gitea-repo-template cookie-cutter
Reusable repo template for homelab services on git.aridgwayweb.com.

Bakes in (all verified live on armistace/wedding-photos):
- Hard commit guard: shared pre-commit hook (git config core.hooksPath
  ~/dev/git-hooks) + master branch protection (push whitelist [armistace],
  merge whitelist [hermes, armistace]).
- Gitea Actions CI (.gitea/workflows/build_push.yml): test + build-deploy,
  persistent remote buildkit cache, registry push, idempotent deploy that
  preserves hand-provisioned Secrets, cluster injection from repo secrets/vars
  via scripts/reconcile-cluster-inject.sh.
- Persistent buildkit cache (ci/buildkit/): single-replica Longhorn backing.
- scripts/reconcile-cluster-inject.sh: reconcile live Secret/ConfigMap from
  Gitea secrets/vars without clobbering hand-provisioned values.
- RUNBOOK.md: handoff-complete ops doc.

Placeholders (<APP> <OWNER> <NS> <KEY_*>) are filled per-service on repo creation.
2026-09-24 11:45:57 +10:00

106 lines
4.6 KiB
YAML

# Gitea Actions workflow for a single-service homelab app.
#
# THIS IS A TEMPLATE. On repo creation from this template, Gitea copies this file
# verbatim. Fill in the placeholders below (<APP>, <OWNER>, <NS>) to match your
# service. See RUNBOOK.md §2 for the one-time per-repo setup (repo secrets/vars).
#
# Proven patterns baked in (all verified live on armistace/wedding-photos):
# - buildx driver: remote -> persistent buildkit daemon (NOT docker-container,
# which can't reach Docker Hub on this runner). endpoint MUST be top-level,
# not under driver-opts (that yields "no remote endpoint provided").
# - Kubeconfig from CI secret, kubectl installed in-job.
# - Deploy does NOT delete the namespace (preserves hand-provisioned Secrets).
# - reconcile-cluster-inject.sh keeps the live Secret/ConfigMap in sync with
# repo secrets/vars without clobbering hand-provisioned values.
# - linux/amd64 only (arm64 via qemu OOMs the buildkit pod on the NUCs).
# - Do NOT use ghcr.io images in COPY --from (buildkit can't reach it); use the
# ECR base and install uv via pip.
name: build-and-deploy
on:
push:
branches: [master]
workflow_dispatch:
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install uv
uses: astral-sh/setup-uv@v5
- name: Unit tests
working-directory: backend
run: |
uv python install 3.12
uv sync --all-groups --frozen
uv run python -m pytest -q
build-deploy:
needs: test
runs-on: ubuntu-latest
container: catthehacker/ubuntu:act-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Create Kubeconfig
run: |
mkdir -p $HOME/.kube
echo "${{ secrets.KUBEC_CONFIG_BUILDX_NEW_2 }}" > $HOME/.kube/config
- name: Set up Docker Buildx (remote -> persistent buildkit daemon)
uses: docker/setup-buildx-action@v3
with:
driver: remote
# endpoint must be TOP-LEVEL (the action passes it positionally to
# `buildx create --driver remote <endpoint>`). Under driver-opts it
# fails with "ERROR: no remote endpoint provided".
endpoint: tcp://buildkit.gitea-runner.svc:1234
- name: Login to Gitea registry
uses: docker/login-action@v3
with:
registry: git.aridgwayweb.com
username: <OWNER>
password: ${{ secrets.REG_PASSWORD }}
- name: Build & push image
uses: docker/build-push-action@v5
with:
context: ./backend
push: true
platforms: linux/amd64
tags: |
git.aridgwayweb.com/<OWNER>/<APP>:latest
git.aridgwayweb.com/<OWNER>/<APP>:${{ github.sha }}
- name: Deploy
run: |
echo "Installing Kubectl"
apt-get update
apt-get install -y apt-transport-https ca-certificates curl gnupg
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.33/deb/Release.key | gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
chmod 644 /etc/apt/keyrings/kubernetes-apt-keyring.gpg
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.33/deb/ /' | tee /etc/apt/sources.list.d/kubernetes.list
chmod 644 /etc/apt/sources.list.d/kubernetes.list
apt-get update
apt-get install -y kubectl
# Do NOT delete the namespace — that destroys the live Secret (DB creds,
# JWT, etc.) which is provisioned by hand (see RUNBOOK.md).
kubectl apply -f kube/<NS>_namespace.yaml
kubectl create secret docker-registry regcred --docker-server=git.aridgwayweb.com --docker-username=<OWNER> --docker-password='${{ secrets.REG_PASSWORD }}' --docker-email=<OWNER>@aridgwayweb.com --namespace=<NS> --dry-run=client -o yaml | kubectl apply -f -
# Apply everything EXCEPT the placeholder Secret (which would clobber the live one).
kubectl apply -f kube/<NS>_configmap.yaml
kubectl apply -f kube/<APP>-backend_deploy.yaml
kubectl apply -f kube/<APP>-backend_service.yaml
# Reconcile the live Secret + ConfigMap from Gitea repo secrets/vars so
# every env key the deployments reference exists (prevents
# CreateContainerConfigError). See scripts/reconcile-cluster-inject.sh.
export <KEY_1>="${{ secrets.<KEY_1> }}"
export <KEY_2>="${{ secrets.<KEY_2> }}"
bash scripts/reconcile-cluster-inject.sh <NS>-secret <NS>-config <NS>
kubectl rollout status deployment/<APP>-backend -n <NS> --timeout=180s