From 777edf389535f33e2aaa1d53cc4ee025d4e578d5 Mon Sep 17 00:00:00 2001 From: Scooby Husky Date: Mon, 17 Aug 2026 22:05:24 -0500 Subject: [PATCH] Phase 2: deploy Gitea warm standby on the VPS Pull-mirrors home GitLab's Homelabv4 repo on Gitea's own built-in mirror scheduler (6h interval) - no custom sync job needed, per the original plan. SQLite instead of the chart's default HA Postgres + Valkey cluster (single-instance standby holding one small repo, not worth the extra moving parts). A PostSync Job creates the mirror once, idempotently; Gitea's scheduler handles all ongoing pulls after that. Also added a public Cloudflare CNAME for gitlab.kube.huskypup.net -> home.kube.huskypup.net: the VPS has no route to home's LAN via Netbird (none of the mesh peers advertise that subnet, confirmed live), so GitLab needs to be reachable the same way any other internet client reaches it - home's public IP already has port 443 forwarded to istio-ingressgateway from earlier this session. Admin and GitLab-mirror credentials are plain Secrets created directly on the VPS cluster (kubectl, not git) - same pattern as vault-unseal-key. Co-Authored-By: Claude Sonnet 5 --- argocd-apps/vps-standby/gitea.yaml | 33 ++++++ .../gitea/manifests/setup-mirror-job.yaml | 104 ++++++++++++++++++ infrastructure/vps-standby/gitea/values.yaml | 67 +++++++++++ 3 files changed, 204 insertions(+) create mode 100644 argocd-apps/vps-standby/gitea.yaml create mode 100644 infrastructure/vps-standby/gitea/manifests/setup-mirror-job.yaml create mode 100644 infrastructure/vps-standby/gitea/values.yaml diff --git a/argocd-apps/vps-standby/gitea.yaml b/argocd-apps/vps-standby/gitea.yaml new file mode 100644 index 0000000..a4cdf90 --- /dev/null +++ b/argocd-apps/vps-standby/gitea.yaml @@ -0,0 +1,33 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: vps-gitea + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "2" # same wave as vps-vault, both just need vps-minio + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + project: vps-standby + sources: + - repoURL: https://dl.gitea.com/charts/ + chart: gitea + targetRevision: 12.7.0 + helm: + valueFiles: + - $values/infrastructure/vps-standby/gitea/values.yaml + - repoURL: https://gitlab.kube.huskypup.net/Scooby/Homelabv4.git + targetRevision: main + ref: values + - repoURL: https://gitlab.kube.huskypup.net/Scooby/Homelabv4.git + targetRevision: main + path: infrastructure/vps-standby/gitea/manifests + destination: + name: vps-standby + namespace: gitea + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true diff --git a/infrastructure/vps-standby/gitea/manifests/setup-mirror-job.yaml b/infrastructure/vps-standby/gitea/manifests/setup-mirror-job.yaml new file mode 100644 index 0000000..17895bf --- /dev/null +++ b/infrastructure/vps-standby/gitea/manifests/setup-mirror-job.yaml @@ -0,0 +1,104 @@ +--- +# One-time setup of a pull-mirror repo in Gitea, pointing at the home +# GitLab GitOps repo. Gitea's own built-in mirror scheduler handles the +# ongoing periodic pulls after this (configured via gitea.config.mirror +# in values.yaml, DEFAULT_INTERVAL: 6h) - this job just creates the +# mirrored repo once, idempotently (skips if it already exists). +# +# GitLab credentials for the mirror source are a plain Secret created +# directly on this cluster (kubectl, not git): +# kubectl -n gitea create secret generic gitlab-mirror-credentials \ +# --from-literal=username= --from-literal=password= +apiVersion: batch/v1 +kind: Job +metadata: + name: gitea-setup-mirror + namespace: gitea + annotations: + argocd.argoproj.io/hook: PostSync + argocd.argoproj.io/hook-delete-policy: BeforeHookCreation +spec: + backoffLimit: 3 + template: + spec: + restartPolicy: Never + securityContext: + runAsNonRoot: true + runAsUser: 65534 + seccompProfile: + type: RuntimeDefault + containers: + - name: setup-mirror + image: curlimages/curl:8.10.1 + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: ["ALL"] + command: + - /bin/sh + - -c + - | + set -eu + + # Service name follows the Helm release name (vps-gitea). + GITEA_URL="http://vps-gitea-http.gitea.svc.cluster.local:3000" + REPO_OWNER="gitea_admin" + REPO_NAME="Homelabv4" + + echo "==> Waiting for Gitea API..." + for i in $(seq 1 30); do + if curl -sf "${GITEA_URL}/api/v1/version" >/dev/null 2>&1; then + break + fi + sleep 5 + done + + echo "==> Checking if mirror repo already exists..." + EXISTS=$(curl -s -o /dev/null -w '%{http_code}' \ + -u "${GITEA_ADMIN_USER}:${GITEA_ADMIN_PASS}" \ + "${GITEA_URL}/api/v1/repos/${REPO_OWNER}/${REPO_NAME}") + + if [ "$EXISTS" = "200" ]; then + echo "==> Mirror repo already exists, nothing to do." + exit 0 + fi + + echo "==> Creating pull-mirror repo from GitLab..." + curl -sf -X POST \ + -u "${GITEA_ADMIN_USER}:${GITEA_ADMIN_PASS}" \ + -H "Content-Type: application/json" \ + "${GITEA_URL}/api/v1/repos/migrate" \ + -d "{ + \"clone_addr\": \"https://gitlab.kube.huskypup.net/Scooby/Homelabv4.git\", + \"repo_name\": \"${REPO_NAME}\", + \"repo_owner\": \"${REPO_OWNER}\", + \"mirror\": true, + \"mirror_interval\": \"6h\", + \"private\": false, + \"auth_username\": \"${GITLAB_USER}\", + \"auth_password\": \"${GITLAB_TOKEN}\", + \"service\": \"gitlab\" + }" + + echo "==> Done." + env: + - name: GITEA_ADMIN_USER + valueFrom: + secretKeyRef: + name: gitea-admin-secret + key: username + - name: GITEA_ADMIN_PASS + valueFrom: + secretKeyRef: + name: gitea-admin-secret + key: password + - name: GITLAB_USER + valueFrom: + secretKeyRef: + name: gitlab-mirror-credentials + key: username + - name: GITLAB_TOKEN + valueFrom: + secretKeyRef: + name: gitlab-mirror-credentials + key: password diff --git a/infrastructure/vps-standby/gitea/values.yaml b/infrastructure/vps-standby/gitea/values.yaml new file mode 100644 index 0000000..3c179ab --- /dev/null +++ b/infrastructure/vps-standby/gitea/values.yaml @@ -0,0 +1,67 @@ +# Gitea warm standby on the VPS - Phase 2. Pull-mirrors the home GitLab +# repo on a schedule (Gitea's built-in mirror feature - see +# manifests/setup-mirror-job.yaml for the one-time mirror setup), rather +# than a custom sync job. +# +# SQLite instead of the chart's default postgresql-ha + valkey-cluster: +# this is a single-instance standby holding one small mirrored repo, not +# a production multi-user Gitea - a full HA Postgres cluster + Valkey +# cluster would be a lot of extra moving parts (and VPS resources) for no +# real benefit here. +postgresql-ha: + enabled: false +postgresql: + enabled: false +valkey-cluster: + enabled: false +valkey: + enabled: false + +persistence: + enabled: true + size: 10Gi + storageClass: local-path + +resources: + requests: + cpu: 50m + memory: 128Mi + limits: + memory: 512Mi + +gitea: + admin: + existingSecret: gitea-admin-secret + passwordMode: keepUpdated + + config: + database: + DB_TYPE: sqlite3 + cache: + ADAPTER: memory + session: + PROVIDER: memory + queue: + TYPE: level + server: + DOMAIN: gitea.kube.huskypup.net + ROOT_URL: "https://gitea.kube.huskypup.net/" + SSH_PORT: 22 + SSH_LISTEN_PORT: 2222 + mirror: + ENABLED: true + DEFAULT_INTERVAL: 6h + + metrics: + enabled: false + +# No ingress - reached over Netbird from home while it's up, or directly +# on the VPS during an actual promoted-standby incident (same pattern as +# the other vps-standby services). +service: + http: + type: ClusterIP + port: 3000 + ssh: + type: ClusterIP + port: 22