diff --git a/k8s/argocd/apps/phase2-storage-observability-0.yaml b/k8s/argocd/apps/phase2-storage-observability-0.yaml index 2bf9bd7..ffbcd90 100644 --- a/k8s/argocd/apps/phase2-storage-observability-0.yaml +++ b/k8s/argocd/apps/phase2-storage-observability-0.yaml @@ -10,13 +10,16 @@ metadata: argocd.argoproj.io/sync-wave: "0" spec: project: homelab - source: - repoURL: https://prometheus-community.github.io/helm-charts - chart: kube-prometheus-stack - targetRevision: latest - helm: - valueFiles: - - k8s/monitoring/prometheus-values.yaml + 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 @@ -37,13 +40,16 @@ metadata: argocd.argoproj.io/sync-wave: "0" spec: project: homelab - source: - repoURL: https://cloudnative-pg.github.io/charts - chart: cloudnative-pg - targetRevision: "~0.20" - helm: - valueFiles: - - k8s/ddb/cnpg-values.yaml + 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 diff --git a/k8s/argocd/apps/phase2-storage-observability-1.yaml b/k8s/argocd/apps/phase2-storage-observability-1.yaml index 2726998..a32c260 100644 --- a/k8s/argocd/apps/phase2-storage-observability-1.yaml +++ b/k8s/argocd/apps/phase2-storage-observability-1.yaml @@ -94,13 +94,16 @@ metadata: argocd.argoproj.io/sync-wave: "3" spec: project: homelab - source: - repoURL: https://forgejo.riotpiao.homelab.com/riotpiao.com/homelab.git - targetRevision: main - path: k8s/talos-ci-cd/charts/forgejo-runner - helm: - valueFiles: - - values.yaml + 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 diff --git a/k8s/hooks/phase2/phase2-hooks.yaml b/k8s/hooks/phase2/phase2-hooks.yaml new file mode 100644 index 0000000..09db118 --- /dev/null +++ b/k8s/hooks/phase2/phase2-hooks.yaml @@ -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