mirror of
https://github.com/Alkatrazz24/Funk-lab.git
synced 2026-07-08 06:24:42 +02:00
docs: kubernetes — section NFS provisioner complète (install, usage, admin, pièges)
Ajout section 16 (NFS provisioner) dans le guide d'installation k8s : - Architecture du provisionnement dynamique (StorageClass → NFS RAID5) - Prérequis storage-01, fichiers de config, pattern App-of-Apps - Utilisation dans les pods (PVC, Deployment, Grafana, Prometheus) - Section admin : diagnostics, PVC manuels, cleanup, re-sync ArgoCD Ajout dans section admin courante : commandes de gestion NFS, tableau diagnostics PVC Pending, procédure test PVC manuel. Ajout dans pièges : StorageClass not found, SharedResourceWarning (boucle nom ArgoCD), StatefulSet volumeClaimTemplate immutable, PodSecurity baseline. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
f42c6c17dc
commit
8b6f906a89
1 changed files with 407 additions and 6 deletions
|
|
@ -21,9 +21,10 @@ Guide d'installation de A à Z — écrit après avoir effectué l'installation
|
|||
13. [Installer MetalLB](#13-installer-metalLB)
|
||||
14. [Installer Traefik](#14-installer-traefik)
|
||||
15. [Configurer le DNS wildcard *.lab.local](#15-configurer-le-dns-wildcard-lablocal)
|
||||
16. [Vérification finale](#16-vérification-finale)
|
||||
17. [Administration courante](#17-administration-courante)
|
||||
18. [Pièges et erreurs rencontrés](#18-pièges-et-erreurs-rencontrés)
|
||||
16. [Stockage persistant — NFS provisioner](#16-stockage-persistant--nfs-provisioner)
|
||||
17. [Vérification finale](#17-vérification-finale)
|
||||
18. [Administration courante](#18-administration-courante)
|
||||
19. [Pièges et erreurs rencontrés](#19-pièges-et-erreurs-rencontrés)
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -679,7 +680,199 @@ Avec ça, n'importe quel `<service>.lab.local` sera résolu vers Traefik, qui se
|
|||
|
||||
---
|
||||
|
||||
## 16. Vérification finale
|
||||
## 16. Stockage persistant — NFS provisioner
|
||||
|
||||
Sans stockage persistant, les pods comme Grafana ou Prometheus perdent toutes leurs données à chaque redémarrage. Le cluster Funk utilise le RAID5 de storage-01 comme backend via NFS.
|
||||
|
||||
### Architecture
|
||||
|
||||
```
|
||||
Pod (Grafana, Prometheus, etc.)
|
||||
└── PersistentVolumeClaim (PVC)
|
||||
└── StorageClass "nfs"
|
||||
└── nfs-subdir-external-provisioner (Deployment, namespace nfs-provisioner)
|
||||
└── NFS export → /srv/data/nfs/k8s sur storage-01 (RAID5)
|
||||
```
|
||||
|
||||
Quand un pod demande du stockage (`PersistentVolumeClaim`), le provisioner :
|
||||
1. Reçoit la demande via l'API Kubernetes
|
||||
2. Crée automatiquement un sous-répertoire dans `/srv/data/nfs/k8s/` sur storage-01
|
||||
3. Crée un `PersistentVolume` pointant vers ce sous-répertoire
|
||||
4. Bind le PV au PVC — le pod peut monter son volume
|
||||
|
||||
### Prérequis sur storage-01
|
||||
|
||||
Le répertoire NFS doit exister et être exporté **avant** de déployer le provisioner :
|
||||
|
||||
```bash
|
||||
# Sur storage-01 — vérifier l'export
|
||||
sudo exportfs -v | grep k8s
|
||||
# → /srv/data/nfs/k8s 192.168.10.0/24(rw,sync,no_subtree_check,no_root_squash)
|
||||
|
||||
# Si le répertoire n'existe pas encore
|
||||
sudo mkdir -p /srv/data/nfs/k8s
|
||||
sudo chown nobody:nobody /srv/data/nfs/k8s
|
||||
sudo chmod 0777 /srv/data/nfs/k8s
|
||||
|
||||
# Recharger les exports
|
||||
sudo exportfs -ra
|
||||
sudo systemctl status nfs-server
|
||||
```
|
||||
|
||||
> `no_root_squash` est requis : le provisioner tourne en root dans le conteneur et doit pouvoir créer des sous-répertoires sur le partage.
|
||||
|
||||
### Fichiers de configuration
|
||||
|
||||
**`k8s/apps-of-apps/apps/nfs-provisioner.yaml`** — Application ArgoCD parente :
|
||||
```yaml
|
||||
spec:
|
||||
source:
|
||||
repoURL: git@github.com:Alkatrazz24/Funk-lab.git
|
||||
path: k8s/infra/nfs-provisioner
|
||||
```
|
||||
|
||||
**`k8s/infra/nfs-provisioner/helmrelease.yaml`** — Application ArgoCD enfant (multi-source) :
|
||||
```yaml
|
||||
spec:
|
||||
sources:
|
||||
- repoURL: https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/
|
||||
chart: nfs-subdir-external-provisioner
|
||||
targetRevision: 4.0.18
|
||||
helm:
|
||||
valueFiles:
|
||||
- $values/k8s/infra/nfs-provisioner/values.yaml
|
||||
- repoURL: git@github.com:Alkatrazz24/Funk-lab.git
|
||||
targetRevision: main
|
||||
ref: values
|
||||
```
|
||||
|
||||
**`k8s/infra/nfs-provisioner/values.yaml`** — paramètres Helm :
|
||||
```yaml
|
||||
nfs:
|
||||
server: 192.168.10.1 # IP de storage-01
|
||||
path: /srv/data/nfs/k8s # Répertoire exporté
|
||||
|
||||
storageClass:
|
||||
name: nfs
|
||||
defaultClass: true # Classe par défaut du cluster
|
||||
reclaimPolicy: Retain # Conserver les données si le PVC est supprimé
|
||||
archiveOnDelete: false # Ne pas archiver à la suppression
|
||||
```
|
||||
|
||||
> `reclaimPolicy: Retain` signifie que si tu supprimes un PVC, le sous-répertoire NFS reste. Les données sont protégées. Il faut supprimer manuellement le répertoire si souhaité.
|
||||
|
||||
### Pattern App-of-Apps pour ce déploiement
|
||||
|
||||
```
|
||||
root Application (watches apps-of-apps/apps/)
|
||||
└── nfs-provisioner Application (watches k8s/infra/nfs-provisioner/)
|
||||
└── nfs-subdir-external-provisioner Application (multi-source Helm)
|
||||
├── Deployment nfs-subdir-external-provisioner (namespace nfs-provisioner)
|
||||
└── StorageClass "nfs"
|
||||
```
|
||||
|
||||
> **Important** : le `helmrelease.yaml` dans `k8s/infra/nfs-provisioner/` doit avoir un nom différent de son Application parente. Ici `nfs-subdir-external-provisioner` ≠ `nfs-provisioner`. Un même nom créerait une boucle de gestion ArgoCD (SharedResourceWarning).
|
||||
|
||||
### Déploiement initial (déjà fait via ArgoCD)
|
||||
|
||||
```bash
|
||||
# ArgoCD déploie automatiquement via Git. Pour forcer manuellement :
|
||||
kubectl -n argocd annotate application nfs-provisioner \
|
||||
argocd.argoproj.io/refresh=hard --overwrite
|
||||
|
||||
# Vérifier que tout est Synced
|
||||
kubectl get applications -n argocd | grep nfs
|
||||
# nfs-provisioner Synced Healthy
|
||||
# nfs-subdir-external-provisioner Synced Healthy
|
||||
```
|
||||
|
||||
### Utiliser le stockage NFS dans un pod
|
||||
|
||||
#### Créer un PVC
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: mon-app-data
|
||||
namespace: mon-namespace
|
||||
spec:
|
||||
storageClassName: nfs # Doit correspondre à la StorageClass
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
resources:
|
||||
requests:
|
||||
storage: 5Gi
|
||||
```
|
||||
|
||||
> `ReadWriteOnce` (RWO) : monté par un seul pod à la fois. Suffisant pour des bases de données, Prometheus, Grafana.
|
||||
> `ReadWriteMany` (RWX) : monté par plusieurs pods simultanément. NFS le supporte — utile pour du contenu statique partagé.
|
||||
|
||||
#### Monter le PVC dans un Deployment
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: mon-app
|
||||
image: mon-image
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /data # Chemin dans le conteneur
|
||||
volumes:
|
||||
- name: data
|
||||
persistentVolumeClaim:
|
||||
claimName: mon-app-data # Nom du PVC ci-dessus
|
||||
```
|
||||
|
||||
#### Comment Grafana utilise le NFS
|
||||
|
||||
Grafana stocke dans son volume NFS :
|
||||
- Sa base de données SQLite (`grafana.db`) — dashboards, utilisateurs, alertes, préférences
|
||||
- Le cache des images PNG/PDF exportées depuis les dashboards
|
||||
- Les plugins installés à chaud
|
||||
|
||||
Dans `k8s/infra/monitoring/values.yaml` :
|
||||
```yaml
|
||||
grafana:
|
||||
persistence:
|
||||
enabled: true
|
||||
storageClassName: nfs
|
||||
size: 2Gi
|
||||
```
|
||||
|
||||
Le chart Grafana crée automatiquement un PVC nommé `kube-prometheus-stack-grafana`. Le provisioner NFS provisionne un répertoire dans `/srv/data/nfs/k8s/monitoring-kube-prometheus-stack-grafana-pvc-<uid>/`.
|
||||
|
||||
#### Comment Prometheus utilise le NFS
|
||||
|
||||
Prometheus utilise un `StatefulSet` avec un `volumeClaimTemplate` dans le CRD `Prometheus` :
|
||||
|
||||
```yaml
|
||||
prometheus:
|
||||
prometheusSpec:
|
||||
storageSpec:
|
||||
volumeClaimTemplate:
|
||||
spec:
|
||||
storageClassName: nfs
|
||||
accessModes: ["ReadWriteOnce"]
|
||||
resources:
|
||||
requests:
|
||||
storage: 20Gi
|
||||
```
|
||||
|
||||
Le PVC créé s'appelle `prometheus-kube-prometheus-stack-prometheus-db-prometheus-kube-prometheus-stack-prometheus-0` et est lié à un répertoire dans `/srv/data/nfs/k8s/`.
|
||||
|
||||
> **Attention** : Les `volumeClaimTemplate` de StatefulSet ne peuvent **pas** être mis à jour une fois créés. Si tu changes la taille ou la storageClass, tu dois :
|
||||
> 1. Patcher le CRD Prometheus pour retirer `storageSpec`
|
||||
> 2. Supprimer le StatefulSet (sans `--cascade=foreground` pour ne pas tuer les pods)
|
||||
> 3. Supprimer le PVC
|
||||
> 4. Remettre `storageSpec` dans values.yaml
|
||||
> 5. Git push → ArgoCD recrée tout
|
||||
|
||||
---
|
||||
|
||||
## 17. Vérification finale
|
||||
|
||||
```bash
|
||||
# État des nœuds
|
||||
|
|
@ -711,7 +904,7 @@ compute-03 Ready <none> 1h v1.33.1
|
|||
|
||||
---
|
||||
|
||||
## 17. Administration courante
|
||||
## 18. Administration courante
|
||||
|
||||
### Variables d'environnement (à mettre dans ~/.bashrc)
|
||||
|
||||
|
|
@ -794,9 +987,124 @@ talhelper genconfig
|
|||
talosctl kubeconfig --nodes 192.168.10.11 ~/.kube/config
|
||||
```
|
||||
|
||||
### Administrer le stockage NFS
|
||||
|
||||
```bash
|
||||
# État du provisioner
|
||||
kubectl get pods -n nfs-provisioner
|
||||
kubectl get deployment -n nfs-provisioner
|
||||
|
||||
# État de la StorageClass
|
||||
kubectl get storageclass
|
||||
|
||||
# Tous les PVCs du cluster (toutes namespaces)
|
||||
kubectl get pvc -A
|
||||
|
||||
# Tous les PVs (volumes physiques côté cluster)
|
||||
kubectl get pv
|
||||
|
||||
# Détail d'un PVC (binding, capacité, storageClass)
|
||||
kubectl describe pvc <nom-pvc> -n <namespace>
|
||||
|
||||
# Vérifier l'espace utilisé côté NFS (storage-01)
|
||||
ssh storage-01 "du -sh /srv/data/nfs/k8s/*"
|
||||
ssh storage-01 "df -h /srv/data"
|
||||
|
||||
# Logs du provisioner (utile si un PVC reste en Pending)
|
||||
kubectl logs -n nfs-provisioner deployment/nfs-subdir-external-provisioner --tail=30
|
||||
```
|
||||
|
||||
#### Pourquoi un PVC reste-t-il en Pending ?
|
||||
|
||||
Un PVC reste `Pending` quand le provisioner ne peut pas créer le volume. Causes courantes :
|
||||
|
||||
| Cause | Diagnostic | Fix |
|
||||
|---|---|---|
|
||||
| StorageClass `nfs` inexistante | `kubectl get sc` → vide | Forcer sync ArgoCD `nfs-provisioner` |
|
||||
| Provisioner pod en erreur | `kubectl get pods -n nfs-provisioner` | Lire les logs, redéployer |
|
||||
| storage-01 inaccessible | `ping 192.168.10.1` depuis un pod | Vérifier réseau/NFS |
|
||||
| Répertoire NFS non exporté | `ssh storage-01 "exportfs -v"` | Relancer le playbook Ansible |
|
||||
| Permissions insuffisantes | Logs provisioner : `permission denied` | Vérifier `no_root_squash` dans `/etc/exports` |
|
||||
|
||||
```bash
|
||||
# Diagnostic complet pour un PVC bloqué
|
||||
kubectl describe pvc <pvc-name> -n <namespace>
|
||||
# → Section "Events" montre la raison du blocage
|
||||
|
||||
# Test de connectivité NFS depuis un node k8s
|
||||
kubectl run nfs-test --image=busybox --rm -it --restart=Never -- \
|
||||
mount -t nfs 192.168.10.1:/srv/data/nfs/k8s /mnt
|
||||
```
|
||||
|
||||
#### Créer un PVC manuellement (hors ArgoCD)
|
||||
|
||||
```bash
|
||||
kubectl apply -f - <<EOF
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: test-nfs
|
||||
namespace: default
|
||||
spec:
|
||||
storageClassName: nfs
|
||||
accessModes: [ReadWriteOnce]
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
EOF
|
||||
|
||||
# Vérifier que le PVC passe en Bound
|
||||
kubectl get pvc test-nfs -w
|
||||
|
||||
# Vérifier le répertoire créé sur storage-01
|
||||
ssh storage-01 "ls /srv/data/nfs/k8s/ | grep test-nfs"
|
||||
|
||||
# Nettoyage
|
||||
kubectl delete pvc test-nfs
|
||||
# → Le répertoire NFS reste (reclaimPolicy: Retain) — supprimer manuellement si souhaité
|
||||
```
|
||||
|
||||
#### Supprimer un PVC et ses données
|
||||
|
||||
```bash
|
||||
# 1. Supprimer le PVC
|
||||
kubectl delete pvc <pvc-name> -n <namespace>
|
||||
|
||||
# 2. Le PV passe en "Released" (pas automatiquement supprimé car reclaimPolicy=Retain)
|
||||
kubectl get pv # chercher le PV en Released
|
||||
|
||||
# 3. Si tu veux libérer l'espace, supprimer aussi le PV et le répertoire NFS
|
||||
kubectl delete pv <pv-name>
|
||||
ssh storage-01 "sudo rm -rf /srv/data/nfs/k8s/<répertoire-correspondant>"
|
||||
```
|
||||
|
||||
#### Forcer la re-synchronisation ArgoCD du provisioner
|
||||
|
||||
Le provisioner peut être purgé par ArgoCD si l'Application parente est OutOfSync. Pattern de récupération :
|
||||
|
||||
```bash
|
||||
# 1. Forcer refresh root pour recréer les applications enfants
|
||||
kubectl -n argocd annotate application root \
|
||||
argocd.argoproj.io/refresh=hard --overwrite
|
||||
|
||||
# 2. Forcer sync nfs-provisioner spécifiquement
|
||||
kubectl -n argocd annotate application nfs-provisioner \
|
||||
argocd.argoproj.io/refresh=hard --overwrite
|
||||
|
||||
# 3. Attendre que les deux apps soient Synced/Healthy
|
||||
kubectl get applications -n argocd | grep nfs
|
||||
# nfs-provisioner Synced Healthy
|
||||
# nfs-subdir-external-provisioner Synced Healthy
|
||||
|
||||
# 4. Vérifier la StorageClass et le pod
|
||||
kubectl get sc && kubectl get pods -n nfs-provisioner
|
||||
```
|
||||
|
||||
> Si des PVCs étaient en Pending pendant l'absence du provisioner, elles se resolveront automatiquement dès que la StorageClass et le provisioner sont de nouveau présents.
|
||||
|
||||
---
|
||||
|
||||
## 18. Pièges et erreurs rencontrés
|
||||
## 19. Pièges et erreurs rencontrés
|
||||
|
||||
Tout ce qui a planté lors de l'installation réelle, pour ne pas y retomber.
|
||||
|
||||
|
|
@ -919,6 +1227,96 @@ dial tcp 10.42.2.2:9443: connect: connection refused
|
|||
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
### ❌ PVC reste en Pending — StorageClass "nfs" not found
|
||||
|
||||
**Symptôme** :
|
||||
```
|
||||
Warning ProvisioningFailed persistentvolume-controller storageclass.storage.k8s.io "nfs" not found
|
||||
```
|
||||
|
||||
**Cause** : L'Application ArgoCD `nfs-provisioner` (ou `nfs-subdir-external-provisioner`) a été purgée ou est OutOfSync. La StorageClass disparaît du cluster.
|
||||
|
||||
**Fix** :
|
||||
```bash
|
||||
kubectl -n argocd annotate application root \
|
||||
argocd.argoproj.io/refresh=hard --overwrite
|
||||
kubectl -n argocd annotate application nfs-provisioner \
|
||||
argocd.argoproj.io/refresh=hard --overwrite
|
||||
# Attendre ~60s, puis vérifier :
|
||||
kubectl get sc && kubectl get pods -n nfs-provisioner
|
||||
```
|
||||
|
||||
Les PVCs en Pending se resolvent automatiquement dès que la StorageClass est recréée.
|
||||
|
||||
---
|
||||
|
||||
### ❌ helmrelease.yaml — même nom que l'Application parente (SharedResourceWarning)
|
||||
|
||||
**Symptôme** :
|
||||
```
|
||||
Application/nfs-provisioner is part of applications argocd/nfs-provisioner and root
|
||||
ComparisonError: Failed to load target state: permission denied
|
||||
```
|
||||
|
||||
**Cause** : Le `helmrelease.yaml` dans `k8s/infra/nfs-provisioner/` était une Application ArgoCD nommée `nfs-provisioner` — même nom que l'Application parente qui le contient. ArgoCD essayait de gérer une ressource qui portait son propre nom → boucle.
|
||||
|
||||
**Fix** : Renommer l'Application dans `helmrelease.yaml` avec un nom différent (`nfs-subdir-external-provisioner`). Toujours suivre le pattern monitoring : l'Application enfant doit avoir un nom distinct de son parent.
|
||||
|
||||
---
|
||||
|
||||
### ❌ Prometheus StatefulSet bloqué — impossible de mettre à jour volumeClaimTemplate
|
||||
|
||||
**Symptôme** : ArgoCD signale l'Application `kube-prometheus-stack` en erreur après modification de `storageSpec` dans `values.yaml` :
|
||||
```
|
||||
cannot patch "prometheus-kube-prometheus-stack-prometheus" with kind StatefulSet:
|
||||
StatefulSet.apps "..." is invalid: spec.volumeClaimTemplates: Forbidden: updates to statefulset
|
||||
```
|
||||
|
||||
**Cause** : Kubernetes n'autorise pas la modification des `volumeClaimTemplates` d'un StatefulSet existant.
|
||||
|
||||
**Fix** :
|
||||
```bash
|
||||
# 1. Retirer storageSpec du CRD Prometheus pour que l'operator le détache
|
||||
kubectl patch prometheus kube-prometheus-stack-prometheus -n monitoring \
|
||||
--type=merge -p '{"spec":{"storage":null}}'
|
||||
|
||||
# 2. Supprimer le StatefulSet sans cascade (les pods continuent)
|
||||
kubectl delete statefulset prometheus-kube-prometheus-stack-prometheus-0 \
|
||||
-n monitoring --cascade=orphan
|
||||
|
||||
# 3. Supprimer le PVC
|
||||
kubectl delete pvc <pvc-name> -n monitoring
|
||||
|
||||
# 4. Remettre storageSpec dans values.yaml → git push → ArgoCD recrée tout
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### ❌ node-exporter bloqué par PodSecurity (baseline → privileged requis)
|
||||
|
||||
**Symptôme** : Les pods `node-exporter` restent en `Pending` ou sont rejetés :
|
||||
```
|
||||
pods "kube-prometheus-stack-node-exporter-xxx" is forbidden:
|
||||
violates PodSecurity "baseline:latest": host namespaces (hostNetwork=true, hostPID=true),
|
||||
hostPath volumes
|
||||
```
|
||||
|
||||
**Cause** : Talos applique par défaut la politique `baseline:latest` sur les namespaces. `node-exporter` a besoin de `hostNetwork`, `hostPID`, et de montages `hostPath` pour lire les métriques système — ce qui est refusé par `baseline`.
|
||||
|
||||
**Fix** : Labeler le namespace `monitoring` en `privileged` dans `k8s/infra/monitoring/namespace.yaml` :
|
||||
```yaml
|
||||
metadata:
|
||||
name: monitoring
|
||||
labels:
|
||||
pod-security.kubernetes.io/enforce: privileged
|
||||
pod-security.kubernetes.io/audit: privileged
|
||||
pod-security.kubernetes.io/warn: privileged
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Résumé des points d'attention
|
||||
|
||||
| Sujet | Règle |
|
||||
|
|
@ -933,3 +1331,6 @@ dial tcp 10.42.2.2:9443: connect: connection refused
|
|||
| etcd backup | Critique sur single control-plane — cron hebdomadaire minimum |
|
||||
| RAM workers | compute-02/03 = 8 GB — toujours mettre `resources.requests/limits` |
|
||||
| clusterconfig/ | Généré par talhelper — **ne pas committer**, dans `.gitignore` |
|
||||
| NFS helmrelease | Nom de l'Application enfant ≠ nom du parent ArgoCD |
|
||||
| StatefulSet storage | `volumeClaimTemplate` immutable — delete StatefulSet + PVC pour changer |
|
||||
| PodSecurity monitoring | Namespace `monitoring` doit être `privileged` pour node-exporter |
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue