From 88540b6ded5fcf7bd5667a370c9ec3b224079e1a Mon Sep 17 00:00:00 2001 From: Dan V Date: Wed, 8 Apr 2026 23:10:41 +0200 Subject: [PATCH] feat: deploy Forgejo self-hosted git server - Add ZFS NFS datasets: media-pool/git (50G) and media-pool/git-db (10G) - Add nfs-git and nfs-git-db NFS subdir provisioner Helm values - Deploy Forgejo 10 (StatefulSet) + PostgreSQL 16 (StatefulSet) in infrastructure namespace - StorageClasses: nfs-git (repos/LFS, 50Gi) and nfs-git-db (postgres, 10Gi) - Ingress: git.vandachevici.ro with TLS via cert-manager - SSH NodePort 30022 for git clone ssh://git@host:30022/user/repo.git - Authentik OIDC provider configured (client ID: ZdnrHgyfUncSIPPrOe1o7UAA42N7BMhUHXjQVw4Y) - Add 'git' subdomain to dns-updater configmap Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../helm/nfs-provisioners/values-git-db.yaml | 14 + .../helm/nfs-provisioners/values-git.yaml | 14 + deployment/infrastructure/dns-updater.yaml | 72 ++++ deployment/infrastructure/forgejo.yaml | 320 ++++++++++++++++++ 4 files changed, 420 insertions(+) create mode 100644 deployment/helm/nfs-provisioners/values-git-db.yaml create mode 100644 deployment/helm/nfs-provisioners/values-git.yaml create mode 100644 deployment/infrastructure/dns-updater.yaml create mode 100644 deployment/infrastructure/forgejo.yaml diff --git a/deployment/helm/nfs-provisioners/values-git-db.yaml b/deployment/helm/nfs-provisioners/values-git-db.yaml new file mode 100644 index 0000000..0e53c99 --- /dev/null +++ b/deployment/helm/nfs-provisioners/values-git-db.yaml @@ -0,0 +1,14 @@ +nfs: + mountOptions: + - soft + - timeo=30 + path: /media-pool/git-db + server: 192.168.2.193 +storageClass: + allowVolumeExpansion: true + archiveOnDelete: true + defaultClass: false + mountOptions: + - soft + - timeo=30 + name: nfs-git-db diff --git a/deployment/helm/nfs-provisioners/values-git.yaml b/deployment/helm/nfs-provisioners/values-git.yaml new file mode 100644 index 0000000..6d36c95 --- /dev/null +++ b/deployment/helm/nfs-provisioners/values-git.yaml @@ -0,0 +1,14 @@ +nfs: + mountOptions: + - soft + - timeo=30 + path: /media-pool/git + server: 192.168.2.193 +storageClass: + allowVolumeExpansion: true + archiveOnDelete: true + defaultClass: false + mountOptions: + - soft + - timeo=30 + name: nfs-git diff --git a/deployment/infrastructure/dns-updater.yaml b/deployment/infrastructure/dns-updater.yaml new file mode 100644 index 0000000..d129584 --- /dev/null +++ b/deployment/infrastructure/dns-updater.yaml @@ -0,0 +1,72 @@ +--- +apiVersion: v1 +kind: ConfigMap +metadata: + annotations: {} + name: dns-updater-config + namespace: infrastructure +data: + DOMAIN: vandachevici.ro + NAME: photos;backup;media;chat;openttd;excalidraw;prv;drive;grafana;paperclip;proxmox;parts;dns;games;git + REMOVE_DUPLICATES: 'true' + SLEEP_INTERVAL: '60' +--- +# NOTE: Secret 'dns-updater-secret' must be created manually: +# kubectl create secret generic dns-updater-secret \ +# --from-literal=digitalocean-token= \ +# -n infrastructure +--- +apiVersion: apps/v1 +kind: DaemonSet +metadata: + annotations: {} + labels: + app: dns-updater + name: dns-updater + namespace: infrastructure +spec: + selector: + matchLabels: + app: dns-updater + template: + metadata: + labels: + app: dns-updater + spec: + containers: + - env: + - name: DIGITALOCEAN_TOKEN + valueFrom: + secretKeyRef: + key: digitalocean-token + name: dns-updater-secret + - name: DOMAIN + valueFrom: + configMapKeyRef: + key: DOMAIN + name: dns-updater-config + - name: NAME + valueFrom: + configMapKeyRef: + key: NAME + name: dns-updater-config + - name: SLEEP_INTERVAL + valueFrom: + configMapKeyRef: + key: SLEEP_INTERVAL + name: dns-updater-config + - name: REMOVE_DUPLICATES + valueFrom: + configMapKeyRef: + key: REMOVE_DUPLICATES + name: dns-updater-config + image: tunix/digitalocean-dyndns:latest + name: dns-updater + resources: + limits: + cpu: 100m + memory: 128Mi + requests: + cpu: 50m + memory: 64Mi + restartPolicy: Always diff --git a/deployment/infrastructure/forgejo.yaml b/deployment/infrastructure/forgejo.yaml new file mode 100644 index 0000000..bdc6b7d --- /dev/null +++ b/deployment/infrastructure/forgejo.yaml @@ -0,0 +1,320 @@ +--- +# Forgejo git server + PostgreSQL database +# Domain: git.vandachevici.ro +# Auth: Authentik OIDC (configured post-deploy via admin UI) +# Storage: NFS on HP ProLiant (media-pool/git, media-pool/git-db) +# SSH: NodePort 30022 (clone with: git clone ssh://git@:30022//.git) +# +# Initial deploy steps after applying: +# 1. Create Authentik OIDC provider (see plan.md todo: authentik-oidc) +# 2. In Forgejo admin: Site Administration → Authentication Sources → Add OAuth2 Source +# - Provider: OpenID Connect +# - Name: authentik +# - Client ID/Secret: from Authentik +# - OpenID Discovery URL: https://auth.vandachevici.ro/application/o/forgejo/.well-known/openid-configuration + +--- +apiVersion: v1 +kind: Secret +metadata: + name: forgejo-db-secret + namespace: infrastructure +type: Opaque +stringData: + POSTGRES_DB: forgejo + POSTGRES_USER: forgejo + POSTGRES_PASSWORD: Hg9mKnRpQwXvTz2Ld8cJsY4bAeUfN6 + +--- +apiVersion: v1 +kind: Secret +metadata: + name: forgejo-secret + namespace: infrastructure +type: Opaque +stringData: + # Random secret key for Forgejo session/cookie signing + # Generate with: openssl rand -hex 32 + secret-key: 5f323a291b24ba0d83c5df56569eeeb44e5eda0bcfc9f3d9601d5ab46f5f3754 + +--- +# PostgreSQL for Forgejo +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: forgejo-db-pvc + namespace: infrastructure +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi + storageClassName: nfs-git-db + +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: forgejo-db + namespace: infrastructure +spec: + replicas: 1 + selector: + matchLabels: + app: forgejo-db + serviceName: forgejo-db + template: + metadata: + labels: + app: forgejo-db + spec: + containers: + - name: postgres + image: postgres:16-alpine + ports: + - containerPort: 5432 + name: postgres + env: + - name: POSTGRES_DB + valueFrom: + secretKeyRef: + name: forgejo-db-secret + key: POSTGRES_DB + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: forgejo-db-secret + key: POSTGRES_USER + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: forgejo-db-secret + key: POSTGRES_PASSWORD + - name: PGDATA + value: /var/lib/postgresql/data/pgdata + volumeMounts: + - name: db-data + mountPath: /var/lib/postgresql/data + livenessProbe: + exec: + command: + - pg_isready + - -U + - forgejo + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 5 + readinessProbe: + exec: + command: + - pg_isready + - -U + - forgejo + initialDelaySeconds: 10 + periodSeconds: 5 + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + cpu: 500m + memory: 512Mi + volumes: + - name: db-data + persistentVolumeClaim: + claimName: forgejo-db-pvc + +--- +apiVersion: v1 +kind: Service +metadata: + name: forgejo-db + namespace: infrastructure +spec: + selector: + app: forgejo-db + ports: + - name: postgres + port: 5432 + targetPort: 5432 + +--- +# Forgejo git server +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: forgejo-data-pvc + namespace: infrastructure +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Gi + storageClassName: nfs-git + +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: forgejo + namespace: infrastructure +spec: + replicas: 1 + selector: + matchLabels: + app: forgejo + serviceName: forgejo + template: + metadata: + labels: + app: forgejo + spec: + initContainers: + - name: wait-for-db + image: busybox:1.36 + command: + - sh + - -c + - | + until nc -z forgejo-db 5432; do + echo "Waiting for PostgreSQL..." + sleep 2 + done + echo "PostgreSQL is ready" + containers: + - name: forgejo + image: codeberg.org/forgejo/forgejo:10 + ports: + - containerPort: 3000 + name: http + - containerPort: 22 + name: ssh + env: + - name: FORGEJO__database__DB_TYPE + value: postgres + - name: FORGEJO__database__HOST + value: forgejo-db:5432 + - name: FORGEJO__database__NAME + valueFrom: + secretKeyRef: + name: forgejo-db-secret + key: POSTGRES_DB + - name: FORGEJO__database__USER + valueFrom: + secretKeyRef: + name: forgejo-db-secret + key: POSTGRES_USER + - name: FORGEJO__database__PASSWD + valueFrom: + secretKeyRef: + name: forgejo-db-secret + key: POSTGRES_PASSWORD + - name: FORGEJO__server__DOMAIN + value: git.vandachevici.ro + - name: FORGEJO__server__ROOT_URL + value: https://git.vandachevici.ro + - name: FORGEJO__server__SSH_DOMAIN + value: git.vandachevici.ro + - name: FORGEJO__server__SSH_PORT + value: "30022" + - name: FORGEJO__server__SSH_LISTEN_PORT + value: "22" + - name: FORGEJO__security__SECRET_KEY + valueFrom: + secretKeyRef: + name: forgejo-secret + key: secret-key + - name: FORGEJO__service__DISABLE_REGISTRATION + value: "false" + - name: FORGEJO__service__REQUIRE_SIGNIN_VIEW + value: "false" + volumeMounts: + - name: forgejo-data + mountPath: /data + livenessProbe: + httpGet: + path: / + port: 3000 + initialDelaySeconds: 60 + periodSeconds: 15 + failureThreshold: 5 + readinessProbe: + httpGet: + path: / + port: 3000 + initialDelaySeconds: 30 + periodSeconds: 10 + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: 1000m + memory: 512Mi + volumes: + - name: forgejo-data + persistentVolumeClaim: + claimName: forgejo-data-pvc + +--- +# ClusterIP for HTTP (used by ingress) +apiVersion: v1 +kind: Service +metadata: + name: forgejo + namespace: infrastructure +spec: + selector: + app: forgejo + ports: + - name: http + port: 3000 + targetPort: 3000 + +--- +# NodePort for SSH git access (git clone ssh://git@git.vandachevici.ro:30022/user/repo.git) +apiVersion: v1 +kind: Service +metadata: + name: forgejo-ssh + namespace: infrastructure +spec: + type: NodePort + selector: + app: forgejo + ports: + - name: ssh + port: 22 + targetPort: 22 + nodePort: 30022 + +--- +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: forgejo + namespace: infrastructure + annotations: + cert-manager.io/cluster-issuer: letsencrypt-prod + nginx.ingress.kubernetes.io/proxy-body-size: "0" + nginx.ingress.kubernetes.io/proxy-read-timeout: "600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "600" +spec: + ingressClassName: nginx + rules: + - host: git.vandachevici.ro + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: forgejo + port: + number: 3000 + tls: + - hosts: + - git.vandachevici.ro + secretName: forgejo-tls