diff --git a/README.md b/README.md index fcc3412..8058961 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,7 @@ Aquest clúster K3s gestiona els següents serveis: ``` . ├── README.md # Aquest fitxer +├── argocd-bootstrap.yaml # App-of-apps: llavor per a ArgoCD (aplicar 1 cop) ├── / # Cada aplicació té el seu directori │ ├── deployment.yaml # Definició del Deployment │ ├── service.yaml # Definició del Service @@ -32,8 +33,12 @@ Aquest clúster K3s gestiona els següents serveis: │ ├── namespace.yaml # Namespace dedicat (opcional) │ ├── configmap.yaml # ConfigMaps (opcional) │ └── pvc.yaml # PersistentVolumeClaims (opcional) +├── argocd/ # ArgoCD +│ ├── ingress.yaml # Ingress d'ArgoCD +│ ├── apps/ # Applications + AppProject declaratius +│ └── gen-apps.sh # Genera argocd/apps/* i argocd-bootstrap.yaml └── nas/ # Servei extern per al NAS - ├── nas.yaml # Service i Endpoints externs + ├── transport.yaml # ServersTransport de Traefik └── ingress.yaml # Ingress del NAS ``` @@ -62,6 +67,9 @@ kubectl apply -f /.yaml ### Desplegar Tot el Clúster +La forma recomanada és deixar que ArgoCD sincronitzi el repo (veure secció [ArgoCD (GitOps)](#-argocd-gitops)). +Per a un desplegament manual sense ArgoCD: + ```bash # Desplegar totes les aplicacions for dir in */; do @@ -122,6 +130,66 @@ spec: number: 80 ``` +## 🐙 ArgoCD (GitOps) + +Totes les aplicacions del repo es despleguen de forma declarativa amb ArgoCD. Hi ha un `Application` per cada directori d'aplicació, agrupades sota un `AppProject` anomenat `k3s-cluster`. + +### Estructura + +- [`argocd/apps/project.yaml`](argocd/apps/project.yaml) — `AppProject` `k3s-cluster` (sync-wave -1). +- [`argocd/apps/.yaml`](argocd/apps/) — un `Application` per aplicació (sync-wave 0), cadascun apunta al seu directori del repo. +- [`argocd-bootstrap.yaml`](argocd-bootstrap.yaml) — `Application` "app-of-apps" que sincronitza tot el directori `argocd/apps/`. És l'únic recurs que cal aplicar a mà. +- [`argocd/gen-apps.sh`](argocd/gen-apps.sh) — regenera tots els fitxers anteriors a partir d'una llista d'aplicacions. + +### Flux + +1. El `AppProject` i tots els `Application` estan versionats a `argocd/apps/`. +2. L'app `k3s-cluster-root` (a `argocd-bootstrap.yaml`) llegeix `argocd/apps/` i crea/actualitza el projecte i totes les applications. +3. Cada `Application` sincronitza el seu directori (ex: `pihole/`) cap al seu namespace, amb `prune` i `selfHeal` activats. + +### Bootstrap (una sola vegada) + +Prerequisits: + +1. ArgoCD instal·lat al clúster (namespace `argocd`). +2. `cert-manager` instal·lat (veure [`cert-manager/install.sh`](cert-manager/install.sh)) — el `ClusterIssuer` depèn dels seus CRDs. +3. El repo registrat a ArgoCD (`Settings → Repositories`). Si el repo és públic a GitHub, l'HTTPS funciona sense credencials. + +Llançar la llavor: + +```bash +kubectl apply -f argocd-bootstrap.yaml +``` + +A partir d'aquí ArgoCD crea el projecte `k3s-cluster`, totes les `Application` i les sincronitza automàticament. Qualsevol canvi al repo es propaga sol (self-heal). + +### Recrear el clúster des de zero + +```bash +# 1. Instal·lar K3s +# 2. Instal·lar ArgoCD +# 3. Instal·lar cert-manager +kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml +kubectl wait --for=condition=available --timeout=120s deployment/cert-manager -n cert-manager +# 4. Registrar el repo a ArgoCD (o deixar-lo públic) +# 5. Llançar la llavor +kubectl apply -f argocd-bootstrap.yaml +``` + +### Afegir o treure una aplicació + +1. Crea/esborra el directori de l'aplicació. +2. Afegeix/treu la línia corresponent a l'array `APPS` de [`argocd/gen-apps.sh`](argocd/gen-apps.sh) amb el format `name|namespace|path|recurse|validate`. +3. Executa `./argocd/gen-apps.sh` per regenerar els manifests. +4. Fes commit i push; ArgoCD ho sincronitza sol. + +### Notes + +- Els `Application`/`AppProject` pertanyen al namespace `argocd` (recursos propis d'ArgoCD). +- L'app `argocd` té `recurse: false` sobre el directori `argocd/` per gestionar només `ingress.yaml` i no els seus propis manifests sota `argocd/apps/`. +- L'app `phoenix` usa `Validate=false` per tolerar el CRD `ServiceMonitor` si el Prometheus Operator encara no és instal·lat. +- Els secrets que no estan al repo (ex: `gitea-registry` per a `gym-tracker`) s'han de crear manualment al seu namespace; Argo no els gestiona ni els esborra. + ## 💾 Persistència de Dades Les aplicacions que necessiten emmagatzematge persistent utilitzen: diff --git a/argocd-bootstrap.yaml b/argocd-bootstrap.yaml new file mode 100644 index 0000000..a005d07 --- /dev/null +++ b/argocd-bootstrap.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: k3s-cluster-root + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "-1" +spec: + project: default + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: argocd/apps + directory: + recurse: true + destination: + server: https://kubernetes.default.svc + namespace: argocd + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/argocd/apps/argocd.yaml b/argocd/apps/argocd.yaml new file mode 100644 index 0000000..4372df5 --- /dev/null +++ b/argocd/apps/argocd.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: argocd + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: k3s-cluster + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: argocd + directory: + recurse: false + destination: + server: https://kubernetes.default.svc + namespace: argocd + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/argocd/apps/cert-manager.yaml b/argocd/apps/cert-manager.yaml new file mode 100644 index 0000000..332be26 --- /dev/null +++ b/argocd/apps/cert-manager.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: cert-manager + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: k3s-cluster + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: cert-manager + directory: + recurse: true + destination: + server: https://kubernetes.default.svc + namespace: cert-manager + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/argocd/apps/fava.yaml b/argocd/apps/fava.yaml new file mode 100644 index 0000000..eb284a3 --- /dev/null +++ b/argocd/apps/fava.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: fava + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: k3s-cluster + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: fava + directory: + recurse: true + destination: + server: https://kubernetes.default.svc + namespace: fava + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/argocd/apps/gitea.yaml b/argocd/apps/gitea.yaml new file mode 100644 index 0000000..9adc747 --- /dev/null +++ b/argocd/apps/gitea.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: gitea + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: k3s-cluster + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: gitea + directory: + recurse: true + destination: + server: https://kubernetes.default.svc + namespace: gitea + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/argocd/apps/glance.yaml b/argocd/apps/glance.yaml new file mode 100644 index 0000000..4b586cb --- /dev/null +++ b/argocd/apps/glance.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: glance + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: k3s-cluster + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: glance + directory: + recurse: true + destination: + server: https://kubernetes.default.svc + namespace: glance + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/argocd/apps/gym-tracker.yaml b/argocd/apps/gym-tracker.yaml new file mode 100644 index 0000000..98486a1 --- /dev/null +++ b/argocd/apps/gym-tracker.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: gym-tracker + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: k3s-cluster + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: gym-tracker + directory: + recurse: true + destination: + server: https://kubernetes.default.svc + namespace: gym-tracker + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/argocd/apps/homeassistant.yaml b/argocd/apps/homeassistant.yaml new file mode 100644 index 0000000..7a297fd --- /dev/null +++ b/argocd/apps/homeassistant.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: homeassistant + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: k3s-cluster + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: homeassistant + directory: + recurse: true + destination: + server: https://kubernetes.default.svc + namespace: home-assistant + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/argocd/apps/jellyfin.yaml b/argocd/apps/jellyfin.yaml new file mode 100644 index 0000000..a5dda04 --- /dev/null +++ b/argocd/apps/jellyfin.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: jellyfin + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: k3s-cluster + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: jellyfin + directory: + recurse: true + destination: + server: https://kubernetes.default.svc + namespace: jellyfin + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/argocd/apps/litellm.yaml b/argocd/apps/litellm.yaml new file mode 100644 index 0000000..13aaca5 --- /dev/null +++ b/argocd/apps/litellm.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: litellm + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: k3s-cluster + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: litellm + directory: + recurse: true + destination: + server: https://kubernetes.default.svc + namespace: litellm + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/argocd/apps/minecraft-server.yaml b/argocd/apps/minecraft-server.yaml new file mode 100644 index 0000000..427d722 --- /dev/null +++ b/argocd/apps/minecraft-server.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: minecraft-server + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: k3s-cluster + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: minecraft-server + directory: + recurse: true + destination: + server: https://kubernetes.default.svc + namespace: minecraft + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/argocd/apps/monitoring.yaml b/argocd/apps/monitoring.yaml new file mode 100644 index 0000000..13ba82f --- /dev/null +++ b/argocd/apps/monitoring.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: monitoring + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: k3s-cluster + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: monitoring + directory: + recurse: true + destination: + server: https://kubernetes.default.svc + namespace: monitoring + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/argocd/apps/myorg-assistant.yaml b/argocd/apps/myorg-assistant.yaml new file mode 100644 index 0000000..3d4c5b9 --- /dev/null +++ b/argocd/apps/myorg-assistant.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: myorg-assistant + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: k3s-cluster + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: myorg-assistant + directory: + recurse: true + destination: + server: https://kubernetes.default.svc + namespace: myorg-assistant + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/argocd/apps/n8n.yaml b/argocd/apps/n8n.yaml new file mode 100644 index 0000000..5f63515 --- /dev/null +++ b/argocd/apps/n8n.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: n8n + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: k3s-cluster + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: n8n + directory: + recurse: true + destination: + server: https://kubernetes.default.svc + namespace: n8n + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/argocd/apps/nas.yaml b/argocd/apps/nas.yaml new file mode 100644 index 0000000..0f77b77 --- /dev/null +++ b/argocd/apps/nas.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: nas + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: k3s-cluster + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: nas + directory: + recurse: true + destination: + server: https://kubernetes.default.svc + namespace: nas-proxy + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/argocd/apps/openwebui.yaml b/argocd/apps/openwebui.yaml new file mode 100644 index 0000000..512eb29 --- /dev/null +++ b/argocd/apps/openwebui.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: openwebui + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: k3s-cluster + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: openwebui + directory: + recurse: true + destination: + server: https://kubernetes.default.svc + namespace: openwebui + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/argocd/apps/phoenix.yaml b/argocd/apps/phoenix.yaml new file mode 100644 index 0000000..d84ea44 --- /dev/null +++ b/argocd/apps/phoenix.yaml @@ -0,0 +1,25 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: phoenix + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: k3s-cluster + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: phoenix + directory: + recurse: true + destination: + server: https://kubernetes.default.svc + namespace: phoenix + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false + - Validate=false diff --git a/argocd/apps/pihole.yaml b/argocd/apps/pihole.yaml new file mode 100644 index 0000000..818cfe8 --- /dev/null +++ b/argocd/apps/pihole.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: pihole + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: k3s-cluster + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: pihole + directory: + recurse: true + destination: + server: https://kubernetes.default.svc + namespace: pihole + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/argocd/apps/project.yaml b/argocd/apps/project.yaml new file mode 100644 index 0000000..a29867d --- /dev/null +++ b/argocd/apps/project.yaml @@ -0,0 +1,17 @@ +apiVersion: argoproj.io/v1alpha1 +kind: AppProject +metadata: + name: k3s-cluster + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "-1" +spec: + description: Applications for the rogi.casa K3s cluster (managed in Git) + sourceRepos: + - https://git.rogi.casa/roger/k3s-cluster.git + destinations: + - server: https://kubernetes.default.svc + namespace: "*" + clusterResourceWhitelist: + - group: "*" + kind: "*" diff --git a/argocd/apps/qbittorrent.yaml b/argocd/apps/qbittorrent.yaml new file mode 100644 index 0000000..3a3dc48 --- /dev/null +++ b/argocd/apps/qbittorrent.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: qbittorrent + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: k3s-cluster + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: qbittorrent + directory: + recurse: true + destination: + server: https://kubernetes.default.svc + namespace: qbittorrent + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/argocd/apps/vaultwarden.yaml b/argocd/apps/vaultwarden.yaml new file mode 100644 index 0000000..8d5dcd1 --- /dev/null +++ b/argocd/apps/vaultwarden.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: vaultwarden + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "0" +spec: + project: k3s-cluster + source: + repoURL: https://git.rogi.casa/roger/k3s-cluster.git + targetRevision: main + path: vaultwarden + directory: + recurse: true + destination: + server: https://kubernetes.default.svc + namespace: vaultwarden + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false diff --git a/argocd/gen-apps.sh b/argocd/gen-apps.sh new file mode 100755 index 0000000..b5d7e63 --- /dev/null +++ b/argocd/gen-apps.sh @@ -0,0 +1,140 @@ +#!/usr/bin/env bash +# Generates ArgoCD Application manifests (one per app folder) + an AppProject. +# +# Layout produced: +# argocd/apps/project.yaml -> AppProject "k3s-cluster" (sync-wave -1) +# argocd/apps/.yaml -> Application for that app folder +# argocd-bootstrap.yaml (repo root) -> app-of-apps: syncs everything in argocd/apps/ +# +# Bootstrap (one-time, after ArgoCD + cert-manager are installed): +# kubectl apply -f argocd-bootstrap.yaml +# +# Re-run this script after adding/removing an app folder to regenerate the manifests. +set -euo pipefail + +cd "$(dirname "$0")/.." # repo root + +REPO="${REPO:-https://git.rogi.casa/roger/k3s-cluster.git}" +REV="${REV:-main}" +APPS_DIR="argocd/apps" +mkdir -p "$APPS_DIR" + +# app-name | namespace | path | recurse | validate +APPS=( + "argocd|argocd|argocd|false|true" + "cert-manager|cert-manager|cert-manager|true|true" + "fava|fava|fava|true|true" + "gitea|gitea|gitea|true|true" + "glance|glance|glance|true|true" + "gym-tracker|gym-tracker|gym-tracker|true|true" + "homeassistant|home-assistant|homeassistant|true|true" + "jellyfin|jellyfin|jellyfin|true|true" + "litellm|litellm|litellm|true|true" + "minecraft-server|minecraft|minecraft-server|true|true" + "monitoring|monitoring|monitoring|true|true" + "myorg-assistant|myorg-assistant|myorg-assistant|true|true" + "n8n|n8n|n8n|true|true" + "nas|nas-proxy|nas|true|true" + "openwebui|openwebui|openwebui|true|true" + "phoenix|phoenix|phoenix|true|false" + "pihole|pihole|pihole|true|true" + "qbittorrent|qbittorrent|qbittorrent|true|true" + "vaultwarden|vaultwarden|vaultwarden|true|true" +) + +# --------------------------------------------------------------------------- +# AppProject +# --------------------------------------------------------------------------- +cat > "$APPS_DIR/project.yaml" < "$APPS_DIR/${name}.yaml" < argocd-bootstrap.yaml <