feat(talos): bootstrap Kubernetes cluster funk (3 nodes, v1.33.1)

- Add talconfig.yaml with compute-01/02/03 (nvme0n1, Flannel CNI)
- Add SOPS/age encryption for talsecret.sops.yaml
- Add patches: NTP/DNS → storage-01, kubelet reserved for 8GB workers
- Fix nftables: open DHCP port 67 for cluster LAN
- Add dnsmasq DHCP with static leases for all 3 compute nodes
- Add admin/talos.md: full install procedure + admin commands
- Install kubectl + talosctl on storage-01

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
alkatrazz 2026-05-12 22:11:38 +02:00
parent a87d1baf76
commit bb72145365
10 changed files with 392 additions and 3 deletions

1
.gitignore vendored
View file

@ -14,6 +14,7 @@ talos/clusterconfig/
# SOPS / age (clés privées — jamais dans git) # SOPS / age (clés privées — jamais dans git)
*.age *.age
keys.txt keys.txt
.config/sops/
# Claude Code (settings locaux à la machine) # Claude Code (settings locaux à la machine)
.claude/settings.local.json .claude/settings.local.json

3
.sops.yaml Normal file
View file

@ -0,0 +1,3 @@
creation_rules:
- path_regex: \.sops\.yaml$
age: age16rg9hnvnu89rll5schg8d2q5sccxlp7cxms9jmflguxapmtjp3lq0j4393

239
admin/talos.md Normal file
View file

@ -0,0 +1,239 @@
# Talos Linux — Installation et administration du cluster
Cluster Kubernetes **funk** sur 3 ThinkCentre (AMD A10-9700E) via Talos Linux.
---
## Architecture
| Nœud | IP | Rôle | Disque | RAM |
|---|---|---|---|---|
| compute-01 | 192.168.10.11 | control-plane | NVMe 256 GB (PNY/Samsung) | 16 GB |
| compute-02 | 192.168.10.12 | worker | NVMe 256 GB (PNY) | 8 GB |
| compute-03 | 192.168.10.13 | worker | NVMe 256 GB (PNY) | 8 GB |
- **OS** : Talos Linux v1.13.0
- **Kubernetes** : v1.33.1
- **CNI** : Flannel (pods `10.42.0.0/16`, services `10.43.0.0/16`)
- **Single control-plane** : si compute-01 tombe, `kubectl` ne fonctionne plus mais les workloads continuent
---
## Outils requis (poste perso + storage-01)
```bash
# talhelper
curl -sL https://github.com/budimanjojo/talhelper/releases/latest/download/talhelper_linux_amd64.tar.gz | sudo tar xz -C /usr/local/bin talhelper
# age
AGE_VERSION=$(curl -s https://api.github.com/repos/FiloSottile/age/releases/latest | grep tag_name | cut -d'"' -f4)
curl -sL "https://github.com/FiloSottile/age/releases/download/${AGE_VERSION}/age-${AGE_VERSION}-linux-amd64.tar.gz" | sudo tar xz -C /tmp && sudo mv /tmp/age/age /usr/local/bin/ && sudo mv /tmp/age/age-keygen /usr/local/bin/
# sops
sudo curl -sL "https://github.com/getsops/sops/releases/download/v3.9.4/sops-v3.9.4.linux.amd64" -o /usr/local/bin/sops && sudo chmod +x /usr/local/bin/sops
# talosctl
curl -sL https://talos.dev/install | sh
# kubectl
curl -sL "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" -o /tmp/kubectl && sudo install /tmp/kubectl /usr/local/bin/kubectl
```
---
## Structure du repo
```
talos/
├── talconfig.yaml # config déclarative — source de vérité
├── talsecret.sops.yaml # secrets chiffrés (SOPS/age) — commitable
├── patches/
│ ├── all.yaml # NTP + DNS → storage-01
│ └── workers.yaml # kubelet reserved resources (8 GB RAM)
└── clusterconfig/ # généré par talhelper — NE PAS committer
├── funk-compute-01.yaml
├── funk-compute-02.yaml
├── funk-compute-03.yaml
└── talosconfig
```
---
## Clé age (SOPS)
```bash
# Générer une fois par poste admin
mkdir -p ~/.config/sops/age
age-keygen -o ~/.config/sops/age/keys.txt
# → noter la clé publique et l'ajouter dans .sops.yaml
```
> La clé privée (`~/.config/sops/age/keys.txt`) ne doit JAMAIS être committée.
---
## Procédure d'installation (premier déploiement)
### 1. Préparer la clé USB
```bash
# Flasher l'ISO Talos directement (pas Ventoy)
sudo dd if=/mnt/data/talos/1.13/metal-amd64.iso of=/dev/sdX bs=4M status=progress conv=fsync
```
> Utiliser le metal ISO directement (pas Ventoy) — Talos doit être le seul bootable sur la clé.
### 2. Générer les configs
```bash
cd talos/
# Générer les secrets (une seule fois)
talhelper gensecret | sops --filename-override talsecret.sops.yaml --encrypt /dev/stdin > talsecret.sops.yaml
# Générer les configs nœuds
talhelper genconfig
```
### 3. Booter chaque nœud en maintenance mode
1. Brancher la clé USB sur le nœud, allumer
2. Le nœud prend une IP DHCP dans `192.168.10.50-99` (dnsmasq sur storage-01)
3. Vérifier les disques **avant** d'appliquer la config :
```bash
export TALOSCONFIG=talos/clusterconfig/talosconfig
talosctl get disks --insecure --nodes <IP-DHCP>
```
> ⚠️ Les ThinkCentre ont un NVMe (`nvme0n1`), pas un SATA. Vérifier que `installDisk: /dev/nvme0n1` dans `talconfig.yaml`.
### 4. Appliquer la config
```bash
# compute-01
talosctl apply-config --insecure --nodes <IP-DHCP> --file talos/clusterconfig/funk-compute-01.yaml
# compute-02
talosctl apply-config --insecure --nodes <IP-DHCP> --file talos/clusterconfig/funk-compute-02.yaml
# compute-03
talosctl apply-config --insecure --nodes <IP-DHCP> --file talos/clusterconfig/funk-compute-03.yaml
```
Talos installe sur nvme0n1 et reboot automatiquement → nœud disponible sur son IP statique.
> Si le nœud reboot sur un ancien OS (EFI entries) : lancer `talosctl upgrade --image ghcr.io/siderolabs/installer:v1.13.0 --nodes <IP>` puis retirer la clé USB pendant le reboot.
### 5. Bootstrap etcd (une seule fois sur compute-01)
```bash
talosctl bootstrap --nodes 192.168.10.11
```
> ⚠️ Ne lancer qu'une seule fois — relancer sur un cluster existant casse etcd.
### 6. Récupérer le kubeconfig
```bash
talosctl kubeconfig --nodes 192.168.10.11 ~/.kube/config
kubectl get nodes
```
### 7. Déployer Flannel (CNI)
```bash
kubectl apply -f https://github.com/flannel-io/flannel/releases/latest/download/kube-flannel.yml
```
Les nœuds passent `NotReady``Ready` en ~1 minute.
---
## Administration quotidienne
### État du cluster
```bash
kubectl get nodes -o wide
kubectl get pods -A
talosctl --nodes 192.168.10.11,192.168.10.12,192.168.10.13 service
```
### Logs et diagnostics
```bash
# Logs d'un service Talos
talosctl --nodes 192.168.10.11 dmesg | tail -30
talosctl --nodes 192.168.10.11 service etcd
# Logs d'un pod k8s
kubectl logs -n <namespace> <pod>
# Events k8s
kubectl get events -A --sort-by='.lastTimestamp'
```
### Reboot / shutdown d'un nœud
```bash
# Reboot propre
talosctl --nodes 192.168.10.12 reboot
# Shutdown
talosctl --nodes 192.168.10.12 shutdown
# Tous les workers
talosctl --nodes 192.168.10.12,192.168.10.13 reboot
```
### Mise à jour de la config d'un nœud
```bash
cd talos/
# 1. Modifier talconfig.yaml
# 2. Régénérer
talhelper genconfig
# 3. Appliquer (sans --insecure cette fois)
talosctl --nodes 192.168.10.11 apply-config --file clusterconfig/funk-compute-01.yaml
```
### Backup etcd (critique — single control-plane)
```bash
talosctl --nodes 192.168.10.11 etcd snapshot /tmp/etcd-backup-$(date +%Y%m%d).db
# Copier vers storage-01 RAID5
scp /tmp/etcd-*.db storage-01:/srv/data/backups/etcd/
```
> À planifier en cron hebdomadaire au minimum.
### Variables d'environnement utiles
```bash
export TALOSCONFIG=~/Projets/lab/talos/clusterconfig/talosconfig
export KUBECONFIG=~/.kube/config
```
---
## MACs des nœuds (baux DHCP statiques)
| Nœud | MAC | IP fixe |
|---|---|---|
| compute-01 | `6c:4b:90:82:8e:47` | 192.168.10.11 |
| compute-02 | `6c:4b:90:cf:7f:c5` | 192.168.10.12 |
| compute-03 | `6c:4b:90:b6:49:20` | 192.168.10.13 |
---
## Points d'attention
| Sujet | Détail |
|---|---|
| installDisk | Toujours `nvme0n1` sur ces ThinkCentre — ne pas mettre `/dev/sda` (clé USB) |
| USB ISO | Flasher le metal ISO directement avec `dd`, pas Ventoy |
| Bootstrap | Une seule fois sur compute-01, jamais relancer |
| etcd backup | Critique sur single control-plane — planifier en cron |
| RAM workers | 8 GB sur compute-02/03 — toujours définir `resources.requests/limits` |
| VIP | Ne pas configurer de VIP = même IP que le nœud — inutile et cassant |

View file

@ -1,7 +1,22 @@
--- ---
dns_upstream: dns_upstream:
- 8.8.8.8 - 1.1.1.1
- 8.8.4.4 - 9.9.9.9
dhcp_range_start: 192.168.10.50
dhcp_range_end: 192.168.10.99
dhcp_lease_time: 12h
dhcp_static_hosts:
- mac: "6c:4b:90:82:8e:47"
name: compute-01
ip: 192.168.10.11
- mac: "6c:4b:90:cf:7f:c5"
name: compute-02
ip: 192.168.10.12
- mac: "6c:4b:90:b6:49:20"
name: compute-03
ip: 192.168.10.13
dns_cluster_hosts: dns_cluster_hosts:
- name: storage-01 - name: storage-01

View file

@ -23,6 +23,16 @@ address=/{{ host.name }}.{{ dns_domain }}/{{ host.ip }}
address=/{{ host.name }}/{{ host.ip }} address=/{{ host.name }}/{{ host.ip }}
{% endfor %} {% endfor %}
# DHCP — plage dynamique pour le LAN cluster
dhcp-range={{ dhcp_range_start }},{{ dhcp_range_end }},{{ dhcp_lease_time }}
dhcp-option=option:dns-server,{{ lan_ip }}
dhcp-option=option:router,{{ lan_ip }}
# Baux statiques (MAC → IP fixe, ajoutés après récupération des MACs)
{% for host in dhcp_static_hosts %}
dhcp-host={{ host.mac }},{{ host.name }},{{ host.ip }}
{% endfor %}
# Cache # Cache
cache-size=1000 cache-size=1000

View file

@ -20,9 +20,10 @@ table inet filter {
# SSH depuis le LAN domestique et le LAN cluster # SSH depuis le LAN domestique et le LAN cluster
tcp dport 22 ip saddr { 192.168.1.0/24, 192.168.10.0/24 } accept tcp dport 22 ip saddr { 192.168.1.0/24, 192.168.10.0/24 } accept
# DNS (dnsmasq) # DNS + DHCP (dnsmasq)
udp dport 53 ip saddr 192.168.10.0/24 accept udp dport 53 ip saddr 192.168.10.0/24 accept
tcp dport 53 ip saddr 192.168.10.0/24 accept tcp dport 53 ip saddr 192.168.10.0/24 accept
udp dport 67 iif {{ lan_interface }} accept
# NFS # NFS
tcp dport { 111, 2049 } ip saddr 192.168.10.0/24 accept tcp dport { 111, 2049 } ip saddr 192.168.10.0/24 accept

8
talos/patches/all.yaml Normal file
View file

@ -0,0 +1,8 @@
machine:
time:
servers:
- 192.168.10.1
- time.cloudflare.com
network:
nameservers:
- 192.168.10.1

View file

@ -0,0 +1,5 @@
machine:
kubelet:
extraArgs:
system-reserved: cpu=500m,memory=1Gi
kube-reserved: cpu=500m,memory=1Gi

64
talos/talconfig.yaml Normal file
View file

@ -0,0 +1,64 @@
clusterName: funk
talosVersion: v1.13.0
kubernetesVersion: v1.33.1
endpoint: https://192.168.10.11:6443
domain: cluster.local
allowSchedulingOnControlPlanes: false
clusterPodNets:
- 10.42.0.0/16
clusterSvcNets:
- 10.43.0.0/16
cniConfig:
name: flannel
patches:
- "@./patches/all.yaml"
nodes:
- hostname: compute-01
ipAddress: 192.168.10.11
installDisk: /dev/nvme0n1
controlPlane: true
networkInterfaces:
- deviceSelector:
driver: r8169
dhcp: false
addresses:
- 192.168.10.11/24
routes:
- network: 0.0.0.0/0
gateway: 192.168.10.1
- hostname: compute-02
ipAddress: 192.168.10.12
installDisk: /dev/nvme0n1
controlPlane: false
patches:
- "@./patches/workers.yaml"
networkInterfaces:
- deviceSelector:
driver: r8169
dhcp: false
addresses:
- 192.168.10.12/24
routes:
- network: 0.0.0.0/0
gateway: 192.168.10.1
- hostname: compute-03
ipAddress: 192.168.10.13
installDisk: /dev/nvme0n1
controlPlane: false
patches:
- "@./patches/workers.yaml"
networkInterfaces:
- deviceSelector:
driver: r8169
dhcp: false
addresses:
- 192.168.10.13/24
routes:
- network: 0.0.0.0/0
gateway: 192.168.10.1

43
talos/talsecret.sops.yaml Normal file

File diff suppressed because one or more lines are too long