# 15 — Opérations, Scaling et Troubleshooting Référence quotidienne pour gérer le cluster en production. --- ## Commandes kubectl essentielles ### Vue d'ensemble rapide ```bash # État du cluster kubectl get nodes kubectl get pods -n xpeditis-prod kubectl get pods -n xpeditis-prod -o wide # + infos sur les nœuds # Ressources consommées kubectl top nodes kubectl top pods -n xpeditis-prod --sort-by=cpu # Événements récents (erreurs, warnings) kubectl get events -n xpeditis-prod --sort-by='.lastTimestamp' | tail -30 kubectl get events -n xpeditis-prod -w # En temps réel # État des déploiements kubectl get deployments -n xpeditis-prod kubectl get hpa -n xpeditis-prod kubectl get pvc -n xpeditis-prod ``` ### Logs ```bash # Logs backend (tous les pods) kubectl logs -l app=xpeditis-backend -n xpeditis-prod --since=1h # Logs frontend kubectl logs -l app=xpeditis-frontend -n xpeditis-prod --since=1h # Logs en temps réel (un pod spécifique) kubectl logs -f pod/xpeditis-backend-5b8d6c7f9-xxxxx -n xpeditis-prod # Logs multi-pods en temps réel (avec stern) stern xpeditis-backend -n xpeditis-prod stern xpeditis -n xpeditis-prod # Backend + frontend # Filtrer les erreurs kubectl logs -l app=xpeditis-backend -n xpeditis-prod --since=1h | grep -E "ERROR|error|Error" # Logs des dernières 100 lignes d'un pod crashé kubectl logs --previous pod/xpeditis-backend-xxx -n xpeditis-prod | tail -100 ``` ### Exécution dans un pod ```bash # Shell interactif dans un pod backend kubectl exec -it deployment/xpeditis-backend -n xpeditis-prod -- /bin/sh # Commande unique kubectl exec deployment/xpeditis-backend -n xpeditis-prod -- \ node -e "console.log(process.env.NODE_ENV)" # Vérifier la connectivité DB depuis un pod kubectl exec deployment/xpeditis-backend -n xpeditis-prod -- \ nc -zv 10.0.1.100 5432 ``` --- ## Déploiements ### Déploiement d'une nouvelle version ```bash # Via CI/CD (automatique sur push main) — voir doc 11 # Manuel : mettre à jour l'image IMAGE_TAG="sha-$(git rev-parse --short HEAD)" kubectl set image deployment/xpeditis-backend \ backend=ghcr.io//xpeditis-backend:${IMAGE_TAG} \ -n xpeditis-prod # Suivre le déploiement kubectl rollout status deployment/xpeditis-backend -n xpeditis-prod --timeout=300s # Vérifier la version déployée kubectl get deployment xpeditis-backend -n xpeditis-prod \ -o jsonpath='{.spec.template.spec.containers[0].image}' ``` ### Rollback ```bash # Rollback vers la version précédente kubectl rollout undo deployment/xpeditis-backend -n xpeditis-prod # Rollback vers une version spécifique kubectl rollout history deployment/xpeditis-backend -n xpeditis-prod # REVISION CHANGE-CAUSE # 1 Initial deployment # 2 sha-abc1234 # 3 sha-def5678 ← actuelle kubectl rollout undo deployment/xpeditis-backend \ --to-revision=2 \ -n xpeditis-prod # Vérifier kubectl rollout status deployment/xpeditis-backend -n xpeditis-prod ``` ### Redémarrage forcé (sans changer l'image) ```bash # Utile après modification des secrets ou configmaps kubectl rollout restart deployment/xpeditis-backend -n xpeditis-prod kubectl rollout restart deployment/xpeditis-frontend -n xpeditis-prod # Ou redémarrer un pod spécifique (K8s en recrée un nouveau) kubectl delete pod xpeditis-backend-5b8d6c7f9-xxxxx -n xpeditis-prod ``` --- ## Scaling manuel ```bash # Scale horizontal (nombre de pods) kubectl scale deployment xpeditis-backend \ --replicas=5 \ -n xpeditis-prod # Scale horizontal frontend kubectl scale deployment xpeditis-frontend \ --replicas=3 \ -n xpeditis-prod # Désactiver temporairement le HPA (maintenance) kubectl patch hpa backend-hpa -n xpeditis-prod \ -p '{"spec":{"minReplicas":0,"maxReplicas":0}}' # Réactiver le HPA kubectl patch hpa backend-hpa -n xpeditis-prod \ -p '{"spec":{"minReplicas":2,"maxReplicas":15}}' ``` --- ## Gestion des nœuds ### Maintenance d'un nœud (drain) ```bash # 1. Mettre le nœud en maintenance (draine les pods, bloque les nouveaux) kubectl cordon xpeditis-prod-cx32-worker-1 kubectl drain xpeditis-prod-cx32-worker-1 \ --ignore-daemonsets \ --delete-emptydir-data \ --grace-period=30 # 2. Effectuer la maintenance (mise à jour OS, etc.) ssh -i ~/.ssh/xpeditis_hetzner root@ apt-get update && apt-get upgrade -y reboot # 3. Remettre le nœud en service kubectl uncordon xpeditis-prod-cx32-worker-1 # Vérifier que les pods reviennent kubectl get pods -n xpeditis-prod -o wide | grep worker-1 ``` ### Ajouter un nœud worker ```bash # Méthode 1 : Via hetzner-k3s (recommandé) # Modifier cluster.yaml → instance_count: 3 (ou plus) hetzner-k3s apply --config ~/.xpeditis/cluster.yaml # Méthode 2 : Via Cluster Autoscaler (automatique) # Le CA crée des nœuds quand des pods sont en état "Pending" # Pour forcer : déployer une charge kubectl scale deployment xpeditis-backend --replicas=20 -n xpeditis-prod # Le CA va créer des nœuds automatiquement # Remettre en place après test kubectl scale deployment xpeditis-backend --replicas=2 -n xpeditis-prod ``` --- ## Mise à jour de k3s Le System Upgrade Controller gère les upgrades automatiquement. Pour une mise à jour manuelle : ```bash # Vérifier la version actuelle kubectl get nodes -o jsonpath='{.items[0].status.nodeInfo.kubeletVersion}' # v1.30.4+k3s1 # Créer un Plan de mise à jour cat > /tmp/k3s-upgrade.yaml << 'EOF' apiVersion: upgrade.cattle.io/v1 kind: Plan metadata: name: k3s-server namespace: system-upgrade spec: concurrency: 1 # Un nœud à la fois cordon: true serviceAccountName: system-upgrade version: v1.31.0+k3s1 # Nouvelle version upgrade: image: rancher/k3s-upgrade channel: https://update.k3s.io/v1-release/channels/stable nodeSelector: matchExpressions: - {key: node-role.kubernetes.io/control-plane, operator: Exists} --- apiVersion: upgrade.cattle.io/v1 kind: Plan metadata: name: k3s-agent namespace: system-upgrade spec: concurrency: 1 cordon: true serviceAccountName: system-upgrade version: v1.31.0+k3s1 prepare: image: rancher/k3s-upgrade args: ["prepare", "k3s-server"] upgrade: image: rancher/k3s-upgrade channel: https://update.k3s.io/v1-release/channels/stable nodeSelector: matchExpressions: - {key: node-role.kubernetes.io/control-plane, operator: DoesNotExist} EOF kubectl apply -f /tmp/k3s-upgrade.yaml # Suivre la progression kubectl get plans -n system-upgrade kubectl get jobs -n system-upgrade ``` --- ## Troubleshooting — Problèmes courants ### Pod en CrashLoopBackOff ```bash # 1. Voir les logs du crash kubectl logs pod/xpeditis-backend-xxx -n xpeditis-prod --previous # 2. Décrire le pod kubectl describe pod xpeditis-backend-xxx -n xpeditis-prod # Chercher : "Error", "OOMKilled", "Exit Code" # Causes fréquentes : # - OOMKilled (Exit 137) → Augmenter limits.memory # - Exit 1 → Erreur applicative (DB unreachable, env var manquante) # - Exit 126 → Problème de permissions sur le fichier d'entrée # 3. Si env var manquante kubectl exec deployment/xpeditis-backend -n xpeditis-prod -- env | sort | grep -E "DB|REDIS|JWT" ``` ### Pod en Pending (pas démarré) ```bash # Voir pourquoi le pod ne démarre pas kubectl describe pod xpeditis-backend-xxx -n xpeditis-prod | grep -A 20 Events # Causes fréquentes : # "Insufficient cpu/memory" → Pas assez de ressources sur les nœuds → Scale up # "0/2 nodes are available" → Vérifier les taints/tolerations # "did not trigger scale-up" → Cluster Autoscaler peut-être désactivé # Vérifier le Cluster Autoscaler kubectl logs -n kube-system deployment/cluster-autoscaler | tail -30 ``` ### L'API backend retourne des 500 ```bash # 1. Vérifier les logs récents kubectl logs -l app=xpeditis-backend -n xpeditis-prod --since=15m | grep -E "Error|error|500" # 2. Tester le health check directement kubectl exec deployment/xpeditis-backend -n xpeditis-prod -- \ wget -qO- http://localhost:4000/api/v1/health | jq . # 3. Tester la connexion DB kubectl exec deployment/xpeditis-backend -n xpeditis-prod -- \ node -e " const { Client } = require('pg'); const c = new Client({connectionString: process.env.DATABASE_URL || 'postgres://'+process.env.DATABASE_USER+':'+process.env.DATABASE_PASSWORD+'@'+process.env.DATABASE_HOST+':'+process.env.DATABASE_PORT+'/'+process.env.DATABASE_NAME}); c.connect().then(() => { console.log('DB OK'); c.end(); }).catch(e => { console.error('DB Error:', e.message); }); " # 4. Tester la connexion Redis kubectl exec deployment/xpeditis-backend -n xpeditis-prod -- \ node -e " const Redis = require('ioredis'); const r = new Redis({host:process.env.REDIS_HOST,port:process.env.REDIS_PORT,password:process.env.REDIS_PASSWORD}); r.ping().then(res => { console.log('Redis OK:', res); r.quit(); }).catch(e => { console.error('Redis Error:', e.message); }); " ``` ### TLS ne fonctionne pas ```bash # Vérifier cert-manager kubectl get certificates -n xpeditis-prod kubectl describe certificate xpeditis-tls-prod -n xpeditis-prod # Voir les challenges ACME kubectl get challenges -n xpeditis-prod # Si challenge bloqué : vérifier que l'IP du LB est dans le DNS Cloudflare dig +short api.xpeditis.com # Doit retourner l'IP du Hetzner LB # Forcer le renouvellement du certificat kubectl delete certificate xpeditis-tls-prod -n xpeditis-prod kubectl apply -f k8s/07-ingress.yaml # Le certificat sera recréé automatiquement ``` ### WebSocket se déconnecte fréquemment ```bash # 1. Vérifier les sticky sessions dans Traefik kubectl logs -l app.kubernetes.io/name=traefik -n kube-system | grep -i sticky # 2. Vérifier Cloudflare WebSocket est activé # Cloudflare → Votre domaine → Network → WebSockets → ON # 3. Vérifier le timeout WebSocket # Cloudflare → Rules → Configuration Rules # Créer une règle pour api.xpeditis.com/* → WebSocket timeout : 300s # 4. Vérifier les logs Socket.IO kubectl logs -l app=xpeditis-backend -n xpeditis-prod | grep -i socket ``` --- ## Mise en maintenance planifiée ```bash #!/bin/bash # scripts/maintenance-mode.sh echo "🔧 Activation du mode maintenance" # 1. Mettre à jour le ConfigMap pour afficher une page de maintenance kubectl patch configmap frontend-config -n xpeditis-prod \ --type='json' \ -p='[{"op":"add","path":"/data/MAINTENANCE_MODE","value":"true"}]' # 2. Redémarrer le frontend kubectl rollout restart deployment/xpeditis-frontend -n xpeditis-prod kubectl rollout status deployment/xpeditis-frontend -n xpeditis-prod # 3. Prévenir l'équipe echo "✅ Mode maintenance activé. L'app affiche une page de maintenance." echo "Pour désactiver : kubectl patch configmap frontend-config -n xpeditis-prod --type='json' -p='[{\"op\":\"remove\",\"path\":\"/data/MAINTENANCE_MODE\"}]'" ``` --- ## Surveillance quotidienne (5 min/jour) ```bash #!/bin/bash # scripts/daily-check.sh echo "=== Rapport Quotidien Xpeditis $(date) ===" echo -e "\n--- CLUSTER ---" kubectl get nodes kubectl top nodes echo -e "\n--- PODS ---" kubectl get pods -n xpeditis-prod echo -e "\n--- HPA ---" kubectl get hpa -n xpeditis-prod echo -e "\n--- EVENTS RÉCENTS (warnings) ---" kubectl get events -n xpeditis-prod \ --field-selector type=Warning \ --sort-by='.lastTimestamp' | tail -10 echo -e "\n--- HEALTH CHECK ---" curl -sf https://api.xpeditis.com/api/v1/health | jq '.status' || echo "❌ API DOWN" curl -sf -o /dev/null -w "Frontend: %{http_code}\n" https://app.xpeditis.com/ echo -e "\n--- CERTIFICATS ---" kubectl get certificate -n xpeditis-prod echo -e "\n--- STOCKAGE ---" kubectl get pvc -n xpeditis-prod echo "=== Fin du rapport ===" ``` --- ## Liens utiles | Ressource | URL | |---|---| | Dashboard Grafana | https://monitoring.xpeditis.com | | API Swagger | https://api.xpeditis.com/api/docs | | Hetzner Console | https://console.hetzner.cloud | | Cloudflare Dashboard | https://dash.cloudflare.com | | Neon Dashboard | https://console.neon.tech | | Upstash Console | https://console.upstash.com | | GitHub Actions | https://github.com//xpeditis2.0/actions | | GitHub GHCR | https://github.com//xpeditis2.0/pkgs/container |