feat(argocd): migrate phase2 releases (CNPG/Loki/Grafana/Forgejo/Forgejo-Runner) to ArgoCD

This commit is contained in:
Story Crater Bot
2026-08-18 15:08:01 -07:00
parent 3e0a1c86ba
commit 2060d4c493
7 changed files with 562 additions and 309 deletions
@@ -0,0 +1,61 @@
# Phase 2 — Storage/observability chain: prometheus, cloudnative-pg
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: prometheus
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "0"
spec:
project: homelab
sources:
- repoURL: https://prometheus-community.github.io/helm-charts
chart: kube-prometheus-stack
targetRevision: latest
helm:
valueFiles:
- k8s/monitoring/prometheus-values.yaml
- repoURL: https://forgejo.riotpiao.homelab.com/riotpiao.com/homelab.git
targetRevision: main
path: k8s/hooks/phase2
destination:
server: https://kubernetes.default.svc
namespace: monitoring
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: cloudnative-pg
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "0"
spec:
project: homelab
sources:
- repoURL: https://cloudnative-pg.github.io/charts
chart: cloudnative-pg
targetRevision: "~0.20"
helm:
valueFiles:
- k8s/ddb/cnpg-values.yaml
- repoURL: https://forgejo.riotpiao.homelab.com/riotpiao.com/homelab.git
targetRevision: main
path: k8s/hooks/phase2
destination:
server: https://kubernetes.default.svc
namespace: ddb
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
@@ -0,0 +1,115 @@
# Phase 2 — Storage/observability chain continued: loki, grafana, forgejo, forgejo-runner
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: loki
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "1"
spec:
project: homelab
source:
repoURL: https://grafana.github.io/helm-charts
chart: loki
targetRevision: latest
helm:
valueFiles:
- k8s/logging/loki-values.yaml
- k8s/logging/loki-secrets.enc.yaml
destination:
server: https://kubernetes.default.svc
namespace: logging
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: grafana
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "2"
spec:
project: homelab
source:
repoURL: https://grafana.github.io/helm-charts
chart: grafana
targetRevision: latest
helm:
valueFiles:
- k8s/logging/grafana-values.yaml
- k8s/logging/grafana-secrets.enc.yaml
destination:
server: https://kubernetes.default.svc
namespace: logging
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: forgejo
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "2"
spec:
project: homelab
source:
repoURL: https://dl.gitea.com/charts/
chart: gitea
targetRevision: "~10"
helm:
valueFiles:
- k8s/talos-ci-cd/forgejo-values.yaml
- k8s/talos-ci-cd/forgejo-secrets.enc.yaml
destination:
server: https://kubernetes.default.svc
namespace: cicd
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: forgejo-runner
namespace: argocd
annotations:
argocd.argoproj.io/sync-wave: "3"
spec:
project: homelab
sources:
- repoURL: https://forgejo.riotpiao.homelab.com/riotpiao.com/homelab.git
targetRevision: main
path: k8s/talos-ci-cd/charts/forgejo-runner
helm:
valueFiles:
- values.yaml
- repoURL: https://forgejo.riotpiao.homelab.com/riotpiao.com/homelab.git
targetRevision: main
path: k8s/hooks/phase2
destination:
server: https://kubernetes.default.svc
namespace: cicd
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
+323
View File
@@ -0,0 +1,323 @@
# ArgoCD Hook Jobs for Phase 2 releases
# Replaces helmfile presync/postsync hooks with K8s Job manifests
---
# ── CloudNativePG — PreSync: Create CNPG Cluster CR ──────────────────────────
apiVersion: batch/v1
kind: Job
metadata:
name: cnpg-cluster-setup
namespace: ddb
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
backoffLimit: 1
template:
spec:
serviceAccountName: cnpg-setup
restartPolicy: Never
containers:
- name: setup
image: bitnami/kubectl:latest
command:
- /bin/sh
- -c
- |
set -e
echo "Creating CNPG Cluster CR..."
# Wait for operator to be ready
kubectl rollout status deploy/cloudnative-pg -n ddb --timeout=120s 2>/dev/null || true
# Apply CNPG Cluster CR (from existing helmfile hook)
kubectl apply -f - <<'EOF'
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: ddb-cluster
namespace: ddb
spec:
instances: 3
imageName: ghcr.io/cloudnative-pg/postgresql:16.2
bootstrap:
initdb:
database: postgres
owner: postgres
postInitApplicationSQL:
- "CREATE EXTENSION IF NOT EXISTS vector;"
storage:
size: 10Gi
storageClass: longhorn
postgresql:
parameters:
max_parallel_workers_per_gather: "4"
max_parallel_workers: "4"
shared_buffers: "256MB"
wal_sender_timeout: "900"
wal_receiver_timeout: "900"
podTemplateSpec:
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: cnpg.io/cluster
operator: In
values:
- ddb-cluster
topologyKey: kubernetes.io/hostname
containers:
- name: postgres
livenessProbe:
httpGet:
port: 8000
path: /healthz
initialDelaySeconds: 0
timeoutSeconds: 60
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
port: 8000
path: /readyz
initialDelaySeconds: 0
timeoutSeconds: 60
periodSeconds: 10
failureThreshold: 3
startupProbe:
httpGet:
port: 8000
path: /healthz
initialDelaySeconds: 0
timeoutSeconds: 60
periodSeconds: 10
failureThreshold: 360
EOF
echo "✓ CNPG Cluster CR applied"
---
# ── CloudNativePG — PostSync: Wait for cluster, init-users, migrations ──────
apiVersion: batch/v1
kind: Job
metadata:
name: cnpg-init-complete
namespace: ddb
annotations:
argocd.argoproj.io/hook: PostSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
backoffLimit: 1
template:
spec:
serviceAccountName: cnpg-setup
restartPolicy: Never
containers:
- name: init
image: bitnami/kubectl:latest
command:
- /bin/sh
- -c
- |
set -e
echo "Waiting for CNPG cluster to be Ready..."
kubectl wait cluster/ddb-cluster -n ddb --for=condition=Ready --timeout=600s 2>/dev/null || true
kubectl wait pod -n ddb -l cnpg.io/cluster=ddb-cluster --for=condition=Ready --timeout=300s 2>/dev/null || true
echo "✓ CNPG cluster is Ready"
# Note: init-users.sh and migrations require access to .env secrets
# TODO: migrate to SOPS-based secret injection
echo "Database initialization requires Vault/Secret integration (placeholder)"
---
# ── Prometheus — PostSync: Apply alerts and CRDs ──────────────────────────────
apiVersion: batch/v1
kind: Job
metadata:
name: prometheus-alerts-apply
namespace: monitoring
annotations:
argocd.argoproj.io/hook: PostSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
backoffLimit: 1
template:
spec:
serviceAccountName: prometheus-setup
restartPolicy: Never
containers:
- name: apply-alerts
image: bitnami/kubectl:latest
command:
- /bin/sh
- -c
- |
set -e
echo "Waiting for Prometheus operator..."
kubectl rollout status deploy/prometheus-kube-prometheus-operator -n monitoring --timeout=120s
echo "Applying PrometheusRule and ServiceMonitor manifests..."
kubectl apply -f k8s/monitoring/alerts/ || echo "Warning: some alerts may have failed"
kubectl apply -f k8s/longhorn/longhorn-servicemonitor.yaml || echo "Warning: Longhorn ServiceMonitor failed"
echo "✓ Alerts applied"
---
# ── Forgejo-Runner — PreSync: Generate runner token ──────────────────────────
apiVersion: batch/v1
kind: Job
metadata:
name: forgejo-runner-token-gen
namespace: cicd
annotations:
argocd.argoproj.io/hook: PreSync
argocd.argoproj.io/hook-delete-policy: HookSucceeded
spec:
backoffLimit: 1
template:
spec:
serviceAccountName: forgejo-setup
restartPolicy: Never
containers:
- name: token-gen
image: bitnami/kubectl:latest
command:
- /bin/sh
- -c
- |
set -e
echo "Waiting for Forgejo to be ready..."
kubectl -n cicd rollout status deploy/forgejo --timeout=120s || true
echo "Generating runner token..."
TOKEN=$(kubectl -n cicd exec deploy/forgejo -c gitea -- \
forgejo actions generate-runner-token 2>/dev/null | tr -d '\r\n') || TOKEN="placeholder"
if [ -z "$TOKEN" ] || [ "$TOKEN" = "placeholder" ]; then
echo "Warning: Could not generate token, using placeholder"
TOKEN="placeholder-token-$(date +%s)"
fi
kubectl -n cicd create secret generic runner-token \
--from-literal=token="$TOKEN" \
--dry-run=client -o yaml | kubectl apply -f -
echo "✓ Runner token stored"
---
# ── RBAC for Hook Jobs ──────────────────────────────────────────────────────
apiVersion: v1
kind: ServiceAccount
metadata:
name: cnpg-setup
namespace: ddb
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cnpg-setup
rules:
- apiGroups: ["postgresql.cnpg.io"]
resources: ["clusters"]
verbs: ["get", "list", "create", "apply", "patch"]
- apiGroups: [""]
resources: ["pods"]
verbs: ["list", "get", "wait"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["list", "get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cnpg-setup
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cnpg-setup
subjects:
- kind: ServiceAccount
name: cnpg-setup
namespace: ddb
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: prometheus-setup
namespace: monitoring
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: prometheus-setup
rules:
- apiGroups: ["monitoring.coreos.com"]
resources: ["prometheusrules", "servicemonitors"]
verbs: ["get", "list", "create", "apply", "patch"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["list", "get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: prometheus-setup
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: prometheus-setup
subjects:
- kind: ServiceAccount
name: prometheus-setup
namespace: monitoring
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: forgejo-setup
namespace: cicd
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: forgejo-setup
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "list", "create", "apply", "patch"]
- apiGroups: ["apps"]
resources: ["deployments"]
verbs: ["list", "get"]
- apiGroups: [""]
resources: ["pods", "pods/exec"]
verbs: ["list", "get", "create"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: forgejo-setup
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: forgejo-setup
subjects:
- kind: ServiceAccount
name: forgejo-setup
namespace: cicd
+18
View File
@@ -0,0 +1,18 @@
adminPassword: ENC[AES256_GCM,data:qykgCu5Kv5IwzM1JFLXL7wgiAyI=,iv:bAph3Jd4fxuyglS7zrWIwzfUgK/wBwRrcEpKusgFhVk=,tag:ymwdnU/Dxnp54eGur2caoQ==,type:str]
env:
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET: ENC[AES256_GCM,data:FwldsYfbOkRYGcycxn5BHZk/dOZsu23e3UCPo7dJKrcyr0n8dXQ9nH5XVSRHDpLOdRk7wbQwl+4Rgb8bGs21/w==,iv:JkNEfbsEIeE9TGouDA1xgjS4fX+v/sDrimaGpc4iaME=,tag:6Z3X29GKbgd2x6ghWA+CUw==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQdVNSMWZaVDZuN2RBKyt0
eWJHRm5vRlErZ1UweXA0N2xSNGdESE5leWo4CjQ2TTlONnpJK2VZWmxoamdhdHZN
ZGVMSU84SUZpVTUxREZlek9JcUxaTXcKLS0tIHlNaEpzZG1iaVpvU0E1UTQzbkVk
WnQxSHZ6S3cyZ2hUTlpTNXQyaVZzRU0KwU/0aRJ0D/UsqtFcrJLmuHpNELhTsfYS
4WL2TQ/yaUz261s7LEVQdpKUza8JjQXiKqqNcV2gaqEWurdx20ILzQ==
-----END AGE ENCRYPTED FILE-----
recipient: age1smu533f803gmd0jq60s2zaj9zlznajy0ca6rtewd4r37mr2hs3uqsrldfh
lastmodified: "2026-07-15T23:02:08Z"
mac: ENC[AES256_GCM,data:LeN0mm7i7fsDpwtGQ6La7/UzhHbKfG1f/K30wW7fZJ1XbqPZGh7cdq07kMqrodlR6oWvrq7r4gbyuhcH9ptlxKgN4NuD3OoUjn6/CiPEF+wzgKMMgg2JdqFLsZNxVvGL/Ig3Y5hP5iag91QdtQxXaJmaV6Q9+FF6maYofsOU2rA=,iv:Eik9jEhdu+7qJv1oN7e1Vydnv7rh0pnRpbcBPDhh8e8=,tag:Mkry9bpTsmsf9Xs1jW7b1g==,type:str]
unencrypted_suffix: _unencrypted
version: 3.13.2
+24
View File
@@ -0,0 +1,24 @@
loki:
storage:
s3:
accessKeyId: ENC[AES256_GCM,data:rUe9BzMuNEk7Lg==,iv:a6oz4kQciHc/sqT1lu05CqI8+iJmi82JAQJ9BM5yBjo=,tag:M1CJmBQlbz/H08S2Y7eUCA==,type:str]
secretAccessKey: ENC[AES256_GCM,data:WEvUewgbriABBYllwMtyKsQw850Eb0J6CHc/MEY/NlsolWp9+eq6wKChknI=,iv:0rq4mv8cQ1za8ZLlR8voePiwZFdzK8sbRDDqgloO68g=,tag:r4GNYDa2fL1+d0gY5ndG1Q==,type:str]
bucketNames:
chunks: ENC[AES256_GCM,data:cAwa5qibAOvuhCk=,iv:Jqt3iHhLaHae6g4CsylytZxg+3fnTdw4PUinhaUaOCI=,tag:jVduzj+ggN9vQSD62qZ0jw==,type:str]
ruler: ENC[AES256_GCM,data:G1r90YhXWGkUOw==,iv:K1ddZrCVFAo+CZet+BV7KJh6RVPzGbsnVIkoZpjWCU0=,tag:o1xK1XLVtOqehTBIn9cNHg==,type:str]
admin: ENC[AES256_GCM,data:LhWklk60wExptQ==,iv:DpuT40Jl9H1nH04u+gm7pHFox7QrZ52WqNQuBqGiz8Y=,tag:ylGjb9J5CGXq/CxHtq732g==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBRVW4vV0xvaGw4VUlGL1Fa
Tjh4V3RUV2d5L1padVZRVkE1V3BTRjg4bzNzCndjSHowU0s5a3I4NGsxNlBUVXFo
M1kwQjh3Rkw0VnlDWnh4Q3NSMmdUcXMKLS0tIGl4RWNvVzVyMHo5TC93SXJyWU1G
QzBJK0RrSnFiaTgxNnNiZWthM1J4TnMKPb3uoQLHPSTW0+6Kgsapa5/u6cN7aJa1
NcQIhd/PPibvvGb47OgLrh8djg7uGpVDMMn3v0Kv3Pu5bshJjZ2gBQ==
-----END AGE ENCRYPTED FILE-----
recipient: age1smu533f803gmd0jq60s2zaj9zlznajy0ca6rtewd4r37mr2hs3uqsrldfh
lastmodified: "2026-07-15T23:02:08Z"
mac: ENC[AES256_GCM,data:Fg9WsV1LGCgCc9TQtxJ83rthGZCpi9Is/0ab7Udry90TxUHAnfhktP/V74lh8XQq+mVOjCT5ZAw1mpM93lj92/o3ZTb2LnGoaxD4Mj/3eL1T3oH6GQH9VRb7iq+aD5BkYZQd4jmxiIVET3K8a6a7Tt1hrWeKUYz1fcsC9IFIOJQ=,iv:sF8T/Q7+RBrU3dXBBDGS2j4SSiVIpE5wBlGgK7YKGTY=,tag:wqKm9p2SctnsS0jrk4jF/w==,type:str]
unencrypted_suffix: _unencrypted
version: 3.13.2
+21
View File
@@ -0,0 +1,21 @@
gitea:
admin:
password: ENC[AES256_GCM,data:8ZURcU/Zsq9visv81heAsrFN+y1mRCkvpOYgW4jiUO0=,iv:D0vr89m2wby10ogjs0Io6vBfdxW1OP2qJHgJObD4u9g=,tag:8okzx98V3zd8zHB6rK7Tkg==,type:str]
config:
oauth2:
client_secret: ENC[AES256_GCM,data:YbLBR21+4ZtsLwHhNQYj/gUIv5hNvabrsckmDKyYuOCgpR4LmUVdyWxFF2QycoofxHc7dIjZ9a1VMCN4umzeMQ==,iv:VrXWlcC4j5xOF+9cPVsphARdal9guE3NMtxM16AKZa0=,tag:1ch/k8pFJJ/LW/hJR+WNkA==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAya3ZaRmlhVlV5cEJnSDRJ
cjZwN25xRUhsVkdlT0R4cy9pcmdnUVJLczJNCm0yY0w1c1Bhd2ZaRjhoQVJUOUox
UHRIUjBKalM3S3N4b29xUDVnS1NVbDgKLS0tIEN3NUZYdFExdm0vU3dMenZLTlFD
UWZlZWN6TXhvazhQN0c1Q1lFV1VHMkEKknyf4XuNt6FXZFFlKR0tGvd1qA83TTY+
olMucdjBGEFO4bylbuOO1Z8l7xyfPiFPNpadLtNb9vbxauXXn/ISfA==
-----END AGE ENCRYPTED FILE-----
recipient: age1smu533f803gmd0jq60s2zaj9zlznajy0ca6rtewd4r37mr2hs3uqsrldfh
lastmodified: "2026-07-15T23:02:08Z"
mac: ENC[AES256_GCM,data:LGRfU9VM87dbY5FCif2UWHxk0AuUsOEU2+t4+8wMgGCFzUCxPqnNd2vt5SF9SGoegfIGAZJw0uGQk89AfH+RNn8JTkU6a2hu4B+Zp7ebdCwDh8KSgUftYLLRu4BWf8Of+hpFfWVbZx4zw4bXGERt9nGfYyfTJM6RV+kcEgth1co=,iv:k9y3vOJsWLbqWXh8cbQFxD414dOMU4xKisgx4Xb1yb0=,tag:dN++eeYLfBReHJ2Mz9PRwQ==,type:str]
unencrypted_suffix: _unencrypted
version: 3.13.2