Template
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.
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user