xpeditis2.0/docs/mise-en-prod/05-cluster-k3s.md
David b22f4e0b74 docs: procedure de mise en production pas a pas
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018BAUeCFpDkRD6tU5wGsc1C
2026-09-07 21:40:50 +02:00

6.6 KiB

05 — Cluster k3s

Durée : environ 1 h 30.

k3s est une distribution Kubernetes complète en un seul binaire. Sur un nœud, il consomme environ 500 Mo de RAM — comparable à Docker Swarm, pour un modèle de déploiement bien plus riche (sondes, rolling updates sans coupure, politiques réseau, quotas).


1. Installation

scp -i ~/.ssh/xpeditis_prod infra/prod/scripts/02-setup-k3s-server.sh \
    deploy@<app_public_ipv4>:/tmp/

ssh -i ~/.ssh/xpeditis_prod deploy@<app_public_ipv4> \
  "sudo K3S_VERSION=v1.31.5+k3s1 PUBLIC_IP=<app_public_ipv4> PRIVATE_IP=10.10.1.10 \
   bash /tmp/02-setup-k3s-server.sh"

Comptez trois à cinq minutes.

Ce que le script durcit, et pourquoi

Option Effet
--secrets-encryption Les Secret sont chiffrés dans la base d'état de k3s. Sans cela, un instantané de disque ou un vol de volume livre tous les secrets en clair.
--protect-kernel-defaults kubelet refuse de démarrer si les sysctl attendus ne sont pas posés. Échec bruyant plutôt que dérive silencieuse.
audit-log-* Journal d'audit de l'API, 30 jours. Sans lui, « qui a supprimé ce déploiement ? » reste sans réponse. La politique fournie ne journalise jamais le contenu des Secret.
--write-kubeconfig-mode=0600 Le kubeconfig n'est pas lisible par tous les utilisateurs du serveur.
--advertise-address=10.10.1.10 Le cluster s'annonce sur le réseau privé.
--etcd-expose-metrics=false Réduit la surface exposée.

Traefik

Le script écrit /var/lib/rancher/k3s/server/manifests/traefik-config.yaml avant l'installation, pour que k3s applique la configuration dès le premier démarrage :

  • redirection HTTP → HTTPS au niveau de l'entrypoint — aucun Ingress ne peut l'oublier ;
  • IP Cloudflare déclarées de confiance pour X-Forwarded-For : sans cela, la limitation de débit et les audit_logs verraient tous l'IP de Cloudflare, et un seul abus bloquerait tout le monde ;
  • journaux d'accès en JSON, en-têtes filtrés (seuls User-Agent et Cf-Connecting-Ip sont conservés) — les autres peuvent contenir des jetons ;
  • tableau de bord Traefik désactivé ;
  • métriques Prometheus activées.

2. Récupérer le kubeconfig

ssh -i ~/.ssh/xpeditis_prod deploy@<app_public_ipv4> 'cat ~/.kube/config' \
  | sed "s/127.0.0.1/<app_public_ipv4>/" > ~/.kube/xpeditis-prod.yaml
chmod 600 ~/.kube/xpeditis-prod.yaml

export KUBECONFIG=~/.kube/xpeditis-prod.yaml
kubectl get nodes -o wide

Ce fichier donne les pleins pouvoirs sur le cluster. Traitez-le comme une clé privée : chmod 600, jamais dans Git, jamais dans un secret GitHub. Il n'est utilisable que depuis vos IP d'administration (firewall Hetzner).

Pour l'utiliser en permanence :

echo 'export KUBECONFIG=~/.kube/xpeditis-prod.yaml' >> ~/.zshrc

3. Vérifications

kubectl get nodes
# NAME                   STATUS   ROLES                  VERSION
# xpeditis-prod-app-01   Ready    control-plane,master   v1.31.5+k3s1

kubectl -n kube-system get pods
# coredns, local-path-provisioner, metrics-server, traefik : tous Running

# Chiffrement des Secrets au repos
ssh deploy@<app_public_ipv4> 'sudo k3s secrets-encrypt status'
# Encryption Status: Enabled

# Journal d'audit alimenté
ssh deploy@<app_public_ipv4> 'sudo tail -2 /var/log/k3s/audit.log | head -c 300'

# Traefik écoute bien sur 80 et 443
ssh deploy@<app_public_ipv4> 'sudo ss -tlnp | grep -E ":(80|443) "'

4. Composants du cluster

Depuis votre poste, kubeconfig chargé :

cd infra/prod
REGISTRY_TOKEN='<jeton Scaleway>' bash scripts/03-install-cluster-addons.sh

Le script installe :

  1. les namespaces xpeditis-prod et monitoring, avec l'admission de sécurité des pods — restricted pour l'application, baseline pour la supervision (Promtail doit lire les journaux de l'hôte) ;
  2. cert-manager depuis son manifeste officiel épinglé (pas de Helm à maintenir) ;
  3. le Secret d'accès au registre Scaleway (regcred) ;
  4. le ClusterIssuer Let's Encrypt — seulement si le secret Cloudflare existe déjà, sinon il vous le rappelle. C'est normal à ce stade : il sera appliqué après 06 — Secrets.
kubectl -n cert-manager get pods    # 3 pods Running
kubectl get ns                      # xpeditis-prod, monitoring, cert-manager
kubectl -n xpeditis-prod get secret regcred

5. Éprouver les garde-fous

Cette étape est facultative mais rassurante : elle vérifie que les protections mordent réellement.

# Un pod privilégié doit être REFUSÉ par le namespace restricted
kubectl -n xpeditis-prod run test-privilegie --image=alpine --restart=Never \
  --overrides='{"spec":{"containers":[{"name":"c","image":"alpine","securityContext":{"privileged":true}}]}}' \
  -- sleep 10
# Attendu : "violates PodSecurity restricted:latest"

# Un pod root doit être REFUSÉ
kubectl -n xpeditis-prod run test-root --image=alpine --restart=Never \
  --overrides='{"spec":{"containers":[{"name":"c","image":"alpine","securityContext":{"runAsUser":0}}]}}' \
  -- sleep 10
# Attendu : refus également

Si l'un des deux est accepté, les étiquettes du namespace n'ont pas été appliquées :

kubectl apply -f infra/prod/k8s/base/00-namespaces.yaml
kubectl get ns xpeditis-prod -o jsonpath='{.metadata.labels}' | jq

6. Ce qu'il ne faut pas faire

À éviter Pourquoi
Ouvrir 6443 à 0.0.0.0/0 L'API Kubernetes exposée publiquement est une cible permanente. Terraform la restreint à vos IP.
Mettre le kubeconfig dans un secret GitHub Un dépôt compromis donnerait le contrôle total du cluster. La CI passe par SSH avec une clé restreinte à un script.
Installer un tableau de bord Kubernetes Surface d'attaque considérable pour un gain nul face à kubectl et Grafana.
Exécuter des charges de travail en hostNetwork Seul node-exporter le fait, et c'est déjà un compromis assumé.
Désactiver les NetworkPolicy Elles empêchent un pod compromis de balayer le réseau privé.

7. Contrôle

[ ] Nœud Ready, k3s v1.31.x
[ ] secrets-encrypt status = Enabled
[ ] Journal d'audit alimenté dans /var/log/k3s/audit.log
[ ] Traefik écoute sur 80 et 443, tableau de bord désactivé
[ ] cert-manager : 3 pods Running
[ ] Namespaces xpeditis-prod (restricted) et monitoring (baseline) créés
[ ] Secret regcred présent
[ ] Un pod privilégié est refusé
[ ] kubeconfig récupéré en chmod 600, hors de Git

→ Suite : 06 — Secrets SOPS