Comment configurer les annonces L2 de Cilium sur Talos Linux¶
Objectif : Configurer Cilium pour annoncer les IP LoadBalancer sur les réseaux de couche 2 pour l'accessibilité externe.
Scénario : Vous avez un cluster Talos Linux avec Cilium CNI et vous avez besoin que les services LoadBalancer soient accessibles depuis l'extérieur du cluster sans MetalLB ou intégration de fournisseur cloud.
Durée : 20-30 minutes
Prérequis :
- Cluster Talos Linux (v1.x)
- Cilium installé comme CNI (v1.16.0+)
- Accès
kubectlau cluster - Helm 3 installé (recommandé pour les mises à jour)
- Pool d'adresses IP disponible sur votre LAN
Comprendre l'approche de configuration¶
Les annonces L2 de Cilium nécessitent trois composants principaux :
- Configuration LB-IPAM - Gestion du pool d'IP
- Annonces L2 activées - Activation de la fonctionnalité
- Politique d'annonce L2 - Interface réseau et sélection des nœuds
Vous pouvez les configurer en utilisant :
Avantages :
- Versionné
- Plus facile à maintenir
- Déploiements reproductibles
- Piste d'audit claire
Inconvénients :
- Nécessite des connaissances Helm
- Mise à jour complète du cluster nécessaire
Avantages :
- Changements rapides
- Pas de mise à jour à l'échelle du cluster
- Bon pour les tests
Inconvénients :
- Risque de dérive de configuration
- Plus difficile de suivre les changements
- Doit gérer RBAC séparément
Bonne pratique
Utilisez les valeurs Helm pour les environnements de production. Utilisez kubectl apply uniquement pour les tests ou les correctifs temporaires.
Méthode 1 : Configurer avec les valeurs Helm¶
Étape 1 : Vérifier l'installation actuelle de Cilium¶
D'abord, vérifiez que Cilium est installé via Helm :
Sortie attendue :
Si Cilium n'a pas été installé via Helm, voir le Guide de migration.
Étape 2 : Exporter les valeurs actuelles¶
Paramètres spécifiques à Talos
Ne modifiez pas ces paramètres requis par Talos :
- `k8sServiceHost: localhost`
- `k8sServicePort: "7445"` (KubePrism)
- `cgroup.autoMount.enabled: false`
- `cgroup.hostRoot: /sys/fs/cgroup`
Étape 3 : Créer les valeurs Helm complètes¶
Créez cilium-values.yaml avec le support L2 activé :
# Configuration API Kubernetes spécifique à Talos
k8sServiceHost: localhost
k8sServicePort: "7445"
# Configuration cgroup v2 de Talos
cgroup:
autoMount:
enabled: false
hostRoot: /sys/fs/cgroup
# Gestion des adresses IP (IPAM)
ipam:
mode: kubernetes
operator:
clusterPoolIPv4PodCIDRList: ["10.244.0.0/16"] # (1)!
# Gestion des adresses IP LoadBalancer
l2announcements:
enabled: true # (2)!
leaseDuration: 120s
leaseRenewDeadline: 60s
leaseRetryPeriod: 1s
externalIPs:
enabled: true
# Activer les fonctionnalités nécessaires
ingressController:
enabled: false
loadbalancerMode: dedicated
# Support Gateway API (optionnel)
gatewayAPI:
enabled: false
# Plan de contrôle BGP (si utilisation de BGP avec L2)
bgpControlPlane:
enabled: false
# Sécurité et surveillance
hubble:
enabled: true
relay:
enabled: true
ui:
enabled: true
operator:
replicas: 1
prometheus:
enabled: true
prometheus:
enabled: true
# Remplacement de kubeproxy
kubeProxyReplacement: true
- Correspond au CIDR des pods de votre cluster
- Ceci active la fonctionnalité d'annonces L2
Étape 4 : Créer les permissions RBAC¶
Cilium a besoin de permissions RBAC pour l'élection de leader utilisant les leases.
Créez cilium-l2-rbac.yaml :
apiVersion: v1
kind: ServiceAccount
metadata:
name: cilium-l2-announcement
namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: cilium-l2-announcement
namespace: kube-system
rules:
- apiGroups: ["coordination.k8s.io"]
resources: ["leases"]
verbs: ["create", "get", "update"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: cilium-l2-announcement
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: cilium-l2-announcement
subjects:
- kind: ServiceAccount
name: cilium-l2-announcement
namespace: kube-system
Appliquez RBAC :
Étape 5 : Mettre à jour Cilium avec les nouvelles valeurs¶
helm upgrade cilium cilium/cilium \
--namespace kube-system \
--reuse-values \
--values cilium-values.yaml \
--version 1.16.5
Sélection de version
Vérifiez les versions disponibles : helm search repo cilium/cilium --versions
Attendez le déploiement :
kubectl rollout status daemonset/cilium -n kube-system
kubectl rollout status deployment/cilium-operator -n kube-system
Étape 6 : Vérifier la fonctionnalité d'annonces L2¶
Sortie attendue :
Vérifiez également les logs de l'opérateur :
Devrait afficher :
Méthode 2 : Configurer avec des pools IP et des politiques¶
Étape 1 : Créer un pool d'adresses IP¶
Choisissez entre CiliumLoadBalancerIPPool (plus récent, recommandé) ou ConfigMap (legacy).
Créez lb-ip-pool.yaml :
apiVersion: cilium.io/v2alpha1
kind: CiliumLoadBalancerIPPool
metadata:
name: prod-pool
spec:
blocks:
- cidr: "192.168.10.70/28" # (1)!
serviceSelector:
matchExpressions:
- key: io.kubernetes.service.namespace
operator: In
values:
- default
- monitoring
- ingress
- Fournit les IP : 192.168.10.64 - 192.168.10.79 (16 adresses, ~14 utilisables)
Appliquez :
Créez lb-ip-pool-configmap.yaml :
apiVersion: v1
kind: ConfigMap
metadata:
name: bgp-config
namespace: kube-system
data:
config.yaml: |
address-pools:
- name: default
protocol: layer2
addresses:
- 192.168.10.70-192.168.10.90
Appliquez :
Approche obsolète
La configuration basée sur ConfigMap est en cours de suppression progressive au profit de la CRD CiliumLoadBalancerIPPool.
Étape 2 : Créer une politique d'annonce L2¶
Cette politique définit quels nœuds annoncent les IP sur quelles interfaces.
Créez l2-announcement-policy.yaml :
apiVersion: cilium.io/v2alpha1
kind: CiliumL2AnnouncementPolicy
metadata:
name: default-l2-policy
spec:
serviceSelector:
matchLabels: {} # (1)!
nodeSelector:
matchExpressions:
- key: node-role.kubernetes.io/control-plane
operator: DoesNotExist # (2)!
interfaces:
- ^enp0s.* # (3)!
- ^eth0$
- ^ens18$
externalIPs: true
loadBalancerIPs: true
- Correspond à tous les services (pas de filtrage par label)
- Seuls les nœuds workers annoncent (exclut le control plane)
- Motifs regex pour les noms d'interface Talos courants
Appliquez :
Étape 3 : Vérifier la création de la politique¶
Sortie attendue :
Vérifiez les détails :
Configuration de la sélection d'interface réseau¶
Trouver l'interface réseau de votre nœud¶
Sur Talos, listez les interfaces réseau :
Exemple de sortie :
Ou depuis un pod :
Motifs d'interface courants¶
| Environnement | Nom d'interface | Motif Regex |
|---|---|---|
| VirtualBox | enp0s3, enp0s8 | ^enp0s.* |
| VMware | ens192, ens224 | ^ens.* |
| Proxmox | ens18, ens19 | ^ens1[89]$ |
| VM Cloud | eth0, eth1 | ^eth[01]$ |
| Bare Metal | eno1, enp1s0 | Spécifique au périphérique |
Mettre à jour la politique L2 avec l'interface correcte¶
Éditez votre politique :
Mettez à jour la section interfaces :
Tester plusieurs motifs
Utilisez plusieurs motifs pour couvrir différents types de nœuds :
```yaml
interfaces:
- ^enp0s.* # VMs VirtualBox
- ^ens18$ # VMs Proxmox
- ^eth0$ # Instances cloud
```
Configuration de la politique de trafic¶
Le paramètre externalTrafficPolicy affecte comment le trafic atteint vos pods.
Politique de trafic Cluster vs Local¶
Créez un service de test pour comparer :
apiVersion: v1
kind: Service
metadata:
name: nginx-cluster-policy
spec:
type: LoadBalancer
externalTrafficPolicy: Cluster # (1)!
selector:
app: nginx
ports:
- port: 80
targetPort: 80
- Comportement par défaut
- ✅ Répartit la charge sur tous les pods
- ✅ Fonctionne même si le nœud annonçant l'IP n'a pas de pods locaux
- ❌ L'IP source est SNAT (perte de l'IP client)
- ❌ Saut réseau supplémentaire possible
apiVersion: v1
kind: Service
metadata:
name: nginx-local-policy
spec:
type: LoadBalancer
externalTrafficPolicy: Local # (1)!
selector:
app: nginx
ports:
- port: 80
targetPort: 80
- Préserve l'IP source
- ✅ Préserve l'IP source du client
- ✅ Pas de sauts supplémentaires (direct vers le pod local)
- ❌ Fonctionne uniquement si le nœud annonçant a un pod local
- ❌ Distribution de charge inégale possible
Quand utiliser chaque politique¶
| Scénario | Politique recommandée | Raison |
|---|---|---|
| Applications web nécessitant l'IP client | Local | Les logs d'accès affichent les vraies IP des clients |
| Applications haute disponibilité multi-réplicas | Cluster | Meilleure distribution de charge |
| Politiques de sécurité basées sur l'IP source | Local | Les politiques réseau voient les vraies IP |
| Applications à réplica unique | L'un ou l'autre | Pas de différence |
| Contrôleurs Ingress (Traefik, nginx) | Local | Transmet l'IP client aux applications backend |
Vérifier le comportement de la politique de trafic¶
Déployez une charge de travail de test :
kubectl create deployment nginx --image=nginx --replicas=3
kubectl expose deployment nginx --type=LoadBalancer --port=80 --external-traffic-policy=Local
Vérifiez la distribution des pods :
Obtenez l'IP LoadBalancer :
Testez depuis un client externe :
Vérifiez les logs nginx pour l'IP source :
Avec la politique Local, vous devriez voir votre vraie IP client. Avec Cluster, vous verrez une IP interne du cluster.
Options de configuration avancées¶
1. Pools IP multiples avec sélecteurs de service¶
Créez des pools séparés pour différents environnements :
---
apiVersion: cilium.io/v2alpha1
kind: CiliumLoadBalancerIPPool
metadata:
name: production-pool
spec:
blocks:
- cidr: "192.168.10.64/28"
serviceSelector:
matchLabels:
environment: production
---
apiVersion: cilium.io/v2alpha1
kind: CiliumLoadBalancerIPPool
metadata:
name: development-pool
spec:
blocks:
- cidr: "192.168.20.64/28"
serviceSelector:
matchLabels:
environment: development
Étiquetez votre service :
apiVersion: v1
kind: Service
metadata:
name: prod-app
labels:
environment: production
spec:
type: LoadBalancer
# ...
2. Politiques d'annonce spécifiques aux nœuds¶
Annoncez uniquement depuis des nœuds spécifiques :
apiVersion: cilium.io/v2alpha1
kind: CiliumL2AnnouncementPolicy
metadata:
name: edge-nodes-only
spec:
nodeSelector:
matchLabels:
node-role: edge # (1)!
interfaces:
- ^enp0s1$
loadBalancerIPs: true
- Étiquetez vos nœuds edge :
kubectl label node worker-01 node-role=edge
3. Ajustement de la configuration des leases¶
Ajustez le comportement de l'élection de leader dans les valeurs Helm :
l2announcements:
enabled: true
leaseDuration: 180s # (1)!
leaseRenewDeadline: 90s # (2)!
leaseRetryPeriod: 2s # (3)!
- Combien de temps un leader détient le lease (défaut : 120s)
- Combien de temps pour réessayer le renouvellement avant d'abandonner (défaut : 60s)
- À quelle fréquence réessayer les opérations de lease (défaut : 1s)
!!! info "Directives d'ajustement des leases" - Réseaux stables : Augmentez leaseDuration (ex. 300s) pour réduire le churn - Réseaux instables : Diminuez leaseDuration (ex. 60s) pour un basculement plus rapide - Réseaux à haute latence : Augmentez leaseRetryPeriod (ex. 5s)
4. Attribution d'IP spécifique au service¶
Demandez une IP spécifique du pool :
apiVersion: v1
kind: Service
metadata:
name: critical-app
annotations:
io.cilium/lb-ipam-ips: "192.168.10.75" # (1)!
spec:
type: LoadBalancer
loadBalancerClass: io.cilium/l2-announcer # (2)!
selector:
app: critical-app
ports:
- port: 443
- Demande une IP spécifique (doit être dans le pool configuré)
- Utilise explicitement l'annonceur L2 de Cilium
Vérification et tests¶
Vérifier le statut du pool IP¶
Exemple de sortie :
Vue détaillée :
Vérifier le statut de la politique d'annonce L2¶
Recherchez toutes conditions de statut ou erreurs.
Vérifier que le service obtient une IP¶
Créez un service de test :
kubectl create deployment test-nginx --image=nginx
kubectl expose deployment test-nginx --type=LoadBalancer --port=80
Attendez l'EXTERNAL-IP :
Devrait passer de <pending> à une adresse IP réelle en quelques secondes.
Tester la résolution ARP¶
Depuis une machine sur le même LAN :
Vérifiez la table ARP :
Sortie attendue :
Devrait afficher l'adresse MAC du nœud Kubernetes annonçant l'IP.
Tester la connectivité HTTP¶
Devrait recevoir une réponse de nginx.
Vérifier les logs de Cilium¶
Voir l'activité d'annonce L2 :
Recherchez :
level=info msg="Announcing LoadBalancer IP" ip=192.168.10.75 service=default/test-nginx
level=info msg="Acquired lease for L2 announcement" service=default/test-nginx
Tableau de comparaison des configurations¶
| Méthode de configuration | Cas d'usage | Avantages | Inconvénients |
|---|---|---|---|
| Valeurs Helm | Déploiements de production | Versionné, reproductible | Nécessite une mise à jour du cluster |
| CiliumLoadBalancerIPPool | Gestion dynamique des IP | Mises à jour faciles, sensible aux namespaces | Nécessite une politique L2 séparée |
| CiliumL2AnnouncementPolicy | Sélection interface/nœud | Ciblage flexible | Doit correspondre à la config du pool IP |
| ConfigMap (legacy) | Migration depuis MetalLB | Syntaxe familière | Obsolète, fonctionnalités limitées |
| Annotations de service | Demandes d'IP spécifiques | Contrôle fin | Gestion manuelle par service |
Migration depuis une installation manuelle¶
Si Cilium a été installé manuellement (pas via Helm), migrez vers la gestion Helm :
Étape 1 : Sauvegarder la configuration actuelle¶
kubectl get daemonset cilium -n kube-system -o yaml > cilium-daemonset-backup.yaml
kubectl get configmap cilium-config -n kube-system -o yaml > cilium-config-backup.yaml
Étape 2 : Générer les valeurs Helm équivalentes¶
Étape 3 : Désinstaller l'installation manuelle¶
Interruption de service
Cela interrompra brièvement le réseau. Planifiez une fenêtre de maintenance.
Étape 4 : Installer via Helm¶
helm repo add cilium https://helm.cilium.io/
helm repo update
helm install cilium cilium/cilium \
--namespace kube-system \
--values cilium-equivalent-values.yaml
Étape 5 : Réappliquer la configuration L2¶
kubectl apply -f cilium-l2-rbac.yaml
kubectl apply -f lb-ip-pool.yaml
kubectl apply -f l2-announcement-policy.yaml
Résolution des problèmes courants¶
Problème : Échec de la mise à jour Helm¶
Erreur : Error: UPGRADE FAILED: cannot patch "cilium" with kind DaemonSet
Solution : Utilisez le flag --force :
helm upgrade cilium cilium/cilium --namespace kube-system --reuse-values --values cilium-values.yaml --force
Problème : Fonctionnalité L2 non activée après la mise à jour¶
Vérifiez les logs de l'opérateur :
Si vous voyez L2 announcements: Disabled, vérifiez les valeurs Helm :
Problème : Erreurs RBAC dans les logs¶
Erreur : cannot create resource "leases" in API group "coordination.k8s.io"
Solution : Assurez-vous que RBAC a été appliqué :
kubectl get role cilium-l2-announcement -n kube-system
kubectl get rolebinding cilium-l2-announcement -n kube-system
Réappliquez si manquant :
Problème : Mauvaise interface sélectionnée¶
Symptôme : IP attribuée mais non accessible via ARP.
Vérifiez le regex de l'interface :
Comparez avec les interfaces du nœud :
Mettez à jour la politique avec le bon motif d'interface.
Prochaines étapes¶
Après avoir configuré les annonces L2 :
- Déployez des charges de travail réelles avec des services LoadBalancer
- Configurez le DNS pour pointer vers les IP LoadBalancer
- Configurez la surveillance des métriques d'annonce L2
- Testez le basculement en cordonnant les nœuds et en observant la migration des leases
- Consultez le guide de dépannage pour les problèmes opérationnels
Documentation connexe¶
- Tutoriel : Déployer Cilium avec LoadBalancer L2 sur Talos
- Comment : Résoudre les problèmes de LoadBalancer Cilium
- Explication : Architecture réseau L2 de Cilium