Renseignez votre domaine et vos adresses : les commandes et les fichiers de la page s'adaptent. Les valeurs restent dans votre navigateur et ne nous sont jamais transmises.
01Un script, un ordre
Chaque cluster a son script de bootstrap. Il déclare les dépôts Helm, injecte les secrets depuis SOPS, puis installe les composants dans un ordre qui respecte leurs dépendances : pas de stockage avant le réseau, pas de certificat avant l'ingress.
| Ordre | Composant | Pourquoi à ce moment |
|---|---|---|
| 1 | Cilium | Sans réseau des pods, rien d'autre ne démarre |
| 2 | Approbateur des certificats kubelet, metrics-server, tuppr | Le minimum vital d'exploitation |
| 3 | ceph-csi et contrôleur de snapshots | Les volumes, et leurs instantanés pour Velero |
| 4 | cert-manager | Ses CRD doivent exister avant les Ingress |
| 5 | CrowdSec | Le middleware doit exister avant Traefik |
| 6 | Traefik | L'ingress et ses journaux d'accès |
| 7 | external-dns | Publie les noms des Ingress |
| 8 | Velero et talos-backup | Les sauvegardes (chapitre 06) |
Chaque installation suit le même motif, qui rend le script relançable à volonté :
helm upgrade --install traefik traefik/traefik \ --version "$(cat k8s/traefik/version)" \ -n traefik --create-namespace \ -f k8s/traefik/values.yaml -f k8s/traefik/values-demo.yaml \ --wait
Un tour complet prend une à deux minutes. Et si un composant a été modifié à la main, il suffit de relancer le script pour revenir à l'état du dépôt.
02Cilium : réseau et adresses
Cilium fournit le réseau des pods, remplace kube-proxy, et attribue aux services de type
LoadBalancer des adresses prises dans une plage du VNet, annoncées en ARP. Sur
Talos, quelques réglages sont imposés par le système :
ipam:
mode: kubernetes
kubeProxyReplacement: true
k8sServiceHost: localhost # KubePrism, le proxy local de l'API sur Talos
k8sServicePort: 7445
cgroup:
autoMount: { enabled: false }
hostRoot: /sys/fs/cgroup
l2announcements:
enabled: true
apiVersion: cilium.io/v2
kind: CiliumLoadBalancerIPPool
metadata:
name: demo-pool
spec:
blocks:
- start: 10.20.1.100
stop: 10.20.1.150
---
apiVersion: cilium.io/v2alpha1
kind: CiliumL2AnnouncementPolicy
metadata:
name: demo-l2
spec:
loadBalancerIPs: true
Dès que Cilium tourne, les noeuds passent en Ready.
03ceph-csi : des volumes Ceph
Le chart ceph-csi-rbd reçoit l'identifiant du cluster Ceph, ses moniteurs, et la
clé de l'utilisateur client.k8s, injectée depuis SOPS. Il crée la classe de
stockage par défaut :
csiConfig:
- clusterID: <fsid du cluster Ceph>
monitors: [172.16.0.11:6789, 172.16.0.12:6789, 172.16.0.13:6789]
storageClass:
create: true
name: ceph-rbd
clusterID: <fsid du cluster Ceph>
pool: k8s
reclaimPolicy: Delete
allowVolumeExpansion: true
annotations:
storageclass.kubernetes.io/is-default-class: "true"
Talos applique par défaut le niveau de sécurité baseline à tous les pods. Les pilotes CSI ont besoin de privilèges pour monter des disques sur le noeud : leur namespace reçoit le label pod-security.kubernetes.io/enforce=privileged, et lui seul.
On y ajoute le contrôleur de snapshots et une VolumeSnapshotClass pour
ceph-rbd : Velero en aura besoin pour sauvegarder les volumes.
04Traefik : la porte d'entrée
Traefik reçoit tout le trafic HTTP et HTTPS du cluster. Sa configuration pour demo concentre plusieurs leçons apprises :
deployment:
replicas: 2 # un par worker
service:
spec:
externalTrafficPolicy: Local # conserve l'IP réelle des visiteurs
annotations:
lbipam.cilium.io/ips: "10.20.1.100" # cible du DNAT du routeur
# les Ingress affichent l'IP publique : external-dns publie cette adresse
providers:
kubernetesIngress:
publishedService: { enabled: false }
additionalArguments:
- --providers.kubernetesingress.ingressendpoint.ip=203.0.113.47
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
nodeTaintsPolicy: Honor
matchLabelKeys: [pod-template-hash]
labelSelector:
matchLabels: { app.kubernetes.io/name: traefik }
accessLog:
enabled: true # lus par CrowdSec
externalTrafficPolicy: Local: sans lui, chaque requête arrive avec l'adresse d'un noeud, et CrowdSec bannirait... votre propre cluster.- L'adresse publiée : par défaut, un Ingress affiche l'IP interne du service. external-dns créerait alors des noms pointant vers 10.20.1.100, injoignable depuis Internet.
- La répartition : un Traefik par worker, mais sans
nodeTaintsPolicy: Honorles control planes comptent dans le calcul, et sansmatchLabelKeysune mise à jour progressive reste bloquée, l'ancien pod occupant la place du nouveau.
05cert-manager et external-dns
Un développeur qui écrit un Ingress avec un nom sous le domaine de la plateforme doit obtenir, sans rien demander, un enregistrement DNS et un certificat. Deux composants s'en chargent.
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@exemple.fr
privateKeySecretRef: { name: letsencrypt-account }
solvers:
- http01:
ingress: { ingressClassName: traefik }
provider: name: ovh sources: [ingress] domainFilters: [k8s.exemple.fr] policy: upsert-only # crée et met à jour, ne supprime jamais txtOwnerId: demo env: - name: OVH_APPLICATION_KEY valueFrom: { secretKeyRef: { name: ovh-credentials, key: application_key } } # ... OVH_APPLICATION_SECRET, OVH_CONSUMER_KEY
Nous avons préféré le défi HTTP-01, un certificat par nom, à un certificat générique obtenu
par défi DNS : la clé de l'API DNS n'a pas à créer d'enregistrements de validation, et un
certificat compromis ne vaut que pour un nom. La clé OVH est limitée à l'IP de sortie
203.0.113.35, et le mode upsert-only garantit qu'une fausse manipulation ne vide
pas la zone.
06CrowdSec : le videur
CrowdSec lit les journaux d'accès de Traefik, repère les comportements hostiles (scans, force brute, chemins connus des outils d'attaque) et partage ses décisions avec la communauté. Un plugin de Traefik, le bouncer, applique ces décisions en refusant les adresses bannies.
ports:
web:
http:
middlewares: [traefik-crowdsec@kubernetescrd]
websecure:
http:
middlewares: [traefik-crowdsec@kubernetescrd]
Le middleware est posé sur les points d'entrée de Traefik, pas sur chaque Ingress : toute application publiée est protégée d'office, y compris celle qu'un développeur pressé met en ligne un vendredi soir. Notre page CrowdSec et Wazuh détaille le fonctionnement de l'outil.
07Vérifier le socle
kubectl get nodes # tous Ready kubectl -n kube-system exec ds/cilium -- cilium status --brief kubectl get storageclass # ceph-rbd (default) kubectl -n traefik get svc traefik # EXTERNAL-IP 10.20.1.100 kubectl -n crowdsec exec deploy/crowdsec-lapi -- cscli bouncers list
Dernier test, le plus parlant : déployer une petite application avec un Ingress, et vérifier qu'elle répond en HTTPS sur son nom une à deux minutes plus tard.
curl -sI https://whoami.demo.k8s.exemple.fr | head -1 dig +short whoami.demo.k8s.exemple.fr # 203.0.113.47
Une plateforme Kubernetes, sans y laisser vos nuits
Nous concevons, montons et exploitons des plateformes Kubernetes sur Proxmox VE pour des équipes qui veulent se consacrer à leur code : mises à jour nocturnes, sauvegardes testées, déploiement en GitOps. Reprise d'un cluster existant, plateforme clé en main ou astreinte : nous intervenons au forfait comme au long cours.