Chapitre 02

Provisionner par le code

Des VM au cluster Kubernetes prêt, une commande et trois minutes. Ce chapitre montre ce qu'il y a derrière cette commande, et comment les secrets n'en sortent jamais.

Niveau avancé  ·  Lecture 14 min  ·  Base Talos 1.14, Kubernetes 1.36

01Le dépôt, seule source de vérité

Tout l'état désiré de la plateforme vit dans un dépôt Git. Le poste d'administration, un bastion hors du cluster, en a une copie et détient la seule clé capable de déchiffrer les secrets.

Arborescence
k8s-proxmox/
├── scripts/            # préparation Proxmox, bootstraps des clusters
├── tofu/               # OpenTofu : VM et configuration Talos
│   ├── tofu.sh         # lanceur : tunnel, passphrase, HA après apply
│   ├── clusters.tf     # les clusters demo et mgmt, le routeur
│   └── modules/talos-cluster/
├── ansible/            # routeur et serveur de sauvegarde
├── k8s/                # un dossier par composant : version + valeurs
│   ├── cilium/
│   │   ├── version
│   │   ├── values.yaml
│   │   └── values-demo.yaml
│   └── ...
├── secrets/secrets.sops.yaml
└── renovate.json

Une convention simple rend le tout lisible par un humain et par Renovate : chaque composant a son dossier sous k8s/, un fichier version d'une ligne, et ses valeurs Helm, communes puis par cluster. Les scripts lisent la version dans ce fichier, Renovate la met à jour, et personne n'a à chercher où elle est écrite.

Enfin, tous les scripts sont idempotents : les relancer réapplique l'état du dépôt sans rien casser. C'est aussi la façon de corriger une dérive, ce réglage « temporaire » fait à la main un soir de stress.

02Les secrets avec SOPS et age

Jetons d'API Proxmox et OVH, clé Ceph, mots de passe des consoles, clés S3 : tous les secrets sont dans un seul fichier YAML, chiffré par SOPS avec une clé age. Le fichier est versionné ; seules les valeurs sont chiffrées, les noms restent lisibles dans les diffs.

.sops.yaml
creation_rules:
  - path_regex: secrets/.*\.sops\.yaml$
    age: age1...                 # la clé publique age du bastion

Un secret généré pendant l'installation ne passe jamais par l'écran : il va directement dans SOPS. Et pour l'injecter dans Kubernetes, aucun fichier intermédiaire :

Écrire, puis injecter un secret
# générer un mot de passe et l'écrire dans SOPS, sans l'afficher
sops set secrets/secrets.sops.yaml '["rancher"]["admin_password"]' \
  "\"$(openssl rand -base64 24)\""

# le passer à Kubernetes, sans fichier temporaire
SECRETS=secrets/secrets.sops.yaml
kubectl -n cattle-system create secret generic bootstrap-secret \
  --from-literal=bootstrapPassword="$(sops -d --extract '["rancher"]["admin_password"]' $SECRETS)" \
  --dry-run=client -o yaml | kubectl apply -f -
La clé age, votre talon d'Achille

Sans la clé privée age, plus aucun secret n'est lisible : ni pour vous, ni pour reconstruire la plateforme. Gardez-en une copie hors du bastion, dans un coffre de mots de passe. Un secret en clair dans Git, c'est la cape coincée dans la porte ; une clé age perdue, c'est la porte murée.

03Préparer Proxmox une fois

Quatre scripts préparent le cluster Proxmox, une seule fois : la zone SDN et ses VNets, le modèle de VM Talos, le modèle Debian du routeur, et le pool Ceph vu au chapitre précédent.

Extrait de scripts/01-sdn.sh
pvesh create /cluster/sdn/zones --zone k8s --type vxlan \
  --peers 172.16.0.11,172.16.0.12,172.16.0.13,172.16.0.14 --mtu 8950
pvesh create /cluster/sdn/vnets --vnet k8s5000 --zone k8s --tag 5000
pvesh create /cluster/sdn/vnets --vnet k8s5001 --zone k8s --tag 5001
pvesh set /cluster/sdn     # applique la configuration sur tous les noeuds

Le modèle Talos est une VM 9100 créée depuis l'image nocloud de l'Image Factory, avec l'agent invité activé. OpenTofu la clonera pour chaque noeud.

04Les VM avec OpenTofu

OpenTofu s'appuie sur deux fournisseurs : bpg/proxmox pour les VM et siderolabs/talos pour générer les secrets du cluster, appliquer la configuration et amorcer etcd. Un module talos-cluster fait tout le travail ; chaque cluster se résume à sa description :

Extrait de tofu/clusters.tf
module "demo" {
  source             = "./modules/talos-cluster"
  name               = "demo"
  vnet               = "k8s5001"
  vip                = "10.20.1.10"
  talos_version      = "v1.14.4"
  kubernetes_version = "1.36.5"

  nodes = {
    "demo-cp1" = { role = "controlplane", host = "pve1", ip = "10.20.1.11" }
    "demo-cp2" = { role = "controlplane", host = "pve2", ip = "10.20.1.12" }
    "demo-cp3" = { role = "controlplane", host = "pve3", ip = "10.20.1.13" }
    "demo-w1"  = { role = "worker", host = "pve4", ip = "10.20.1.21", memory = 8192 }
    "demo-w2"  = { role = "worker", host = "pve1", ip = "10.20.1.22", memory = 8192 }
  }
}

Le module clone le modèle, pose le CPU en x86-64-v3, le disque sur Ceph et la carte réseau sur le VNet, puis génère et applique la configuration Talos de chaque noeud. Les versions de Talos et de Kubernetes sont écrites ici en clair : Renovate saura les trouver.

Deux précautions complètent le tableau :

  • L'état OpenTofu contient des secrets (certificats du cluster, jetons). Il est chiffré par OpenTofu lui-même (AES-GCM, clé dérivée d'une passphrase) et la passphrase est dans SOPS.
  • L'API Proxmox n'est pas exposée au bastion : le lanceur tofu.sh ouvre un tunnel SSH vers le port 8006 d'un noeud, injecte la passphrase depuis SOPS, lance OpenTofu, puis referme le tunnel.

05La configuration Talos

Talos 1.14 découpe la configuration d'une machine en documents spécialisés. Le module passe à chaque noeud une série de correctifs courts, plutôt qu'un gros fichier :

Correctifs Talos d'un control plane (extrait)
apiVersion: v1alpha1
kind: UnattendedInstallConfig
installer:
  image: factory.talos.dev/nocloud-installer/<schematic>:v1.14.4
provisioning:
  diskSelector:
    match: disk.dev_path == "/dev/sda"
---
apiVersion: v1alpha1
kind: ResolverConfig
nameservers:
  - address: 9.9.9.9
  - address: 149.112.112.112
---
# pas de Flannel ni de kube-proxy : Cilium s'en charge
$patch: delete
apiVersion: v1alpha1
kind: KubeFlannelCNIConfig
---
apiVersion: v1alpha1
kind: KubeProxyConfig
enabled: false
---
# adresse virtuelle de l'API, portée par les control planes
machine:
  network:
    interfaces:
      - deviceSelector: { physical: true }
        mtu: 8950
        vip: { ip: 10.20.1.10 }
Talos 1.14 et les anciennes clés

Les clés historiques machine.install, cluster.proxy, cluster.network ou cluster.allowSchedulingOnControlPlanes sont refusées dès que le document dédié existe. Les exemples trouvés en ligne datent souvent d'avant ce découpage : si Talos rejette une configuration qui a l'air juste, c'est presque toujours ça.

Un dernier document mérite d'être signalé : KubeTalosAPIAccessConfig, qui autorise des pods à appeler l'API Talos avec un rôle précis. Il servira au chapitre 06, pour la sauvegarde d'etcd.

06Haute disponibilité et anti-affinité

Trois control planes sur le même hôte Proxmox, c'est une haute disponibilité de façade. Les VM sont donc confiées à la haute disponibilité de Proxmox, avec des règles d'anti-affinité : les control planes sur trois hôtes distincts, les workers sur deux.

Extrait de scripts/05-ha.sh (Proxmox VE 9)
for vm in 5001011 5001012 5001013 5001021 5001022; do
  ha-manager add vm:$vm --state started
done
ha-manager rules add resource-affinity k8s-demo-cp --affinity negative \
  --resources vm:5001011,vm:5001012,vm:5001013
ha-manager rules add resource-affinity k8s-demo-workers --affinity negative \
  --resources vm:5001021,vm:5001022

Le script est relancé automatiquement par tofu.sh après chaque apply réussi : une VM ajoutée est protégée sans qu'on y pense.

07Lancer et vérifier

Sur le bastion
./tofu/tofu.sh plan
./tofu/tofu.sh apply

# récupérer les accès depuis les sorties OpenTofu
tofu -chdir=tofu output -raw demo_kubeconfig  > ~/.kube/config
tofu -chdir=tofu output -raw demo_talosconfig > ~/.talos/config

kubectl get nodes

Les VM et Talos montent en trois minutes environ. Les noeuds restent alors en NotReady : c'est normal, il n'y a pas encore de réseau des pods. Pas de panique, le chapitre suivant s'en occupe.

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.