Comment résoudre l’épuisement des adresses IPs avec EKS et VPC CNI
Amazon VPC CNI est l’addon réseau d’Amazon pour les clusters EKS. Il implémente la gestion réseau sous forme d’un DaemonSet appelé aws-node
, déployé dans le cluster. Ce DaemonSet est constitué de deux composants principaux : L-IPAM (Local IP Address Management) et le plugin CNI.
L-IPAM :
- Gère la création, l’association et la suppression des Elastic Network Interfaces (ENI) sur chaque nœud.
- Alloue des adresses ou des préfixes IP aux ENI dès qu’un nœud est provisionné.
- Maintient un ensemble pré-assigné d’adresses IP et d’ENI pour accélérer le démarrage des Pods planifiés.
Plugin CNI :
- Configure les interfaces réseau et les paires ethernet virtuelles (veth) pour connecter les Pods.
- Ajoute la bonne interface réseau au namespace du Pod concerné.
- Assure la communication Pod-à-Pod et entre les Pods et les services externes.
- Dialogue avec IPAMD (IP Adress Management Daemon) via le protocole RPC (Remote Procedure Call) pour coordonner les assignations IP.
Les adresses IP sont prises dynamiquement dans le sous-réseau primaire de l’interface réseau principale du nœud. Cette configuration garantit que les Pods et leurs nœuds utilisent le même sous-réseau, simplifiant ainsi la gestion réseau et la connectivité.
Optimiser la configuration de aws-node
Le mode par défaut du CNI Amazon VPC est le Secondary IP mode, dans lequel le binaire CNI (/opt/cni/bin/aws-cni
) utilise IPAMD pour gérer les adresses IP et les ENIs (Elastic Network Interfaces) attachées à chaque instance.
Fonctionnement :
- IPAMD vérifie périodiquement que le nombre correct d’adresses IP et d’ENIs est attaché à l’instance.
- Cette vérification repose sur trois variables d’environnement configurables :
WARM_ENI_TARGET
: Nombre minimum d’ENIs préchauffées (avec des adresses IP) à maintenir.WARM_IP_TARGET
: Nombre minimum d’adresses IP non utilisées prêtes à être assignées aux Pods.MINIMUM_IP_TARGET
: Nombre minimal d’adresses IP à attacher, quelles que soient les ENIs disponibles.
Problèmes du mode par défaut
- Configuration par défaut inefficace (
WARM_ENI_TARGET=1
) :- Cette valeur signifie qu’IPAMD conserve une ENI pleine d’adresses IP attachée à chaque instance, prête à être assignée à des Pods.
- Exemple d’impact :
- Une instance t3.small (max. 3 ENIs, 9 IPs par ENI) avec 5 Pods actives :
- Résultat : 3 ENIs attachées, 9 IPs assignées (5 utilisées, 4 inutilisées).
- Une instance p3dn.24xlarge (max. 15 ENIs, 50 IPs par ENI) avec 3 Pods actives :
- Résultat : 2 ENIs attachées, 100 IPs assignées (3 utilisées, 97 inutilisées).
- Une instance t3.small (max. 3 ENIs, 9 IPs par ENI) avec 5 Pods actives :
- Combinaisons inadaptées de variables :
- Par exemple, avec
WARM_IP_TARGET=5
,MINIMUM_IP_TARGET=10
et 7 Pods actifs, une mauvaise configuration peut entraîner un surplus d’ENIs/IPs inutilisées.
- Par exemple, avec
Comment ajuster les variables d’environnement
Si le plugin Amazon VPC CNI est déjà activé sur un cluster EKS, vous pouvez modifier les variables d’environnement dans le DaemonSet aws-node
dans le namespace kube-system
:
# Configure the WARM_ENI_TARGET, WARM_IP_TARGET,MINIMUM_IP_TARGET
kubectl set env ds aws-node -n kube-system WARM_ENI_TARGET=1
kubectl set env ds aws-node -n kube-system WARM_IP_TARGET=1
kubectl set env ds aws-node -n kube-system MINIMUM_IP_TARGET=1
# Confirm if environment variables are set
kubectl describe daemonset -n kube-system aws-node | grep WARM_ENI_TARGET
kubectl describe daemonset -n kube-system aws-node | grep WARM_IP_TARGET
kubectl describe daemonset -n kube-system aws-node | grep MINIMUM_IP_TARGET
Optimisation recommandée
- Réduire les adresses IP inutilisées : Ajustez
WARM_ENI_TARGET
etWARM_IP_TARGET
en fonction de vos charges de travail pour limiter le gaspillage de ressources. - Évitez une limite trop basse : Un
WARM_IP_TARGET
trop faible peut augmenter le nombre d’appels API AWS, entraînant des latences dans l’attribution des IPs.
Avec une configuration adaptée à vos besoins, vous pouvez optimiser l’utilisation des ressources réseau tout en maintenant des performances élevées.
Configurer un réseau personnalisé pour éviter l’épuisement d’IP
Un réseau personnalisé permet de gérer efficacement les ressources IP en allouant des sous-réseaux dédiés aux Pods. Voici les étapes nécessaires pour configurer un tel réseau :
Étape 1 : Configurer votre VPC
1. Ajouter des sous-réseaux privés :
Créez de nouveaux sous-réseaux dans le VPC souhaité :
SUBNET_ID=$(aws ec2 create-subnet \
--vpc-id vpc-1234567890abcdef0 \
--cidr-block 10.0.1.0/24 \
--availability-zone us-east-1a \
--query 'Subnet.SubnetId' \
--output text)
2. Désactiver l’attribution d’IP publiques :
aws ec2 modify-subnet-attribute \
--subnet-id $SUBNET_ID \
--map-public-ip-on-launch
3. Récupérer les zones de disponibilité :
Pour chaque sous-réseau, obtenez sa zone de disponibilité afin de garantir leur répartition correcte dans votre cluster :
az_1=$(aws ec2 describe-subnets --subnet-ids $SUBNET_ID --query 'Subnets[*].AvailabilityZone' --output text)
### 4. Associer un CIDR additionnel au VPC :
Si vous manquez de plage IP dans votre VPC, vous pouvez associer un nouveau CIDR bloc :
vpc_id=$(aws eks describe-cluster --name my-custom-networking-cluster --query "cluster.resourcesVpcConfig.vpcId" --output text)
aws ec2 associate-vpc-cidr-block --vpc-id $vpc_id --cidr-block 192.168.1.0/24
5. Vérifier l’association du CIDR :
Assurez-vous que le CIDR est bien associé :
aws ec2 describe-vpcs --vpc-ids $vpc_id --query 'Vpcs[*].CidrBlockAssociationSet[*].{CIDRBlock: CidrBlock, State: CidrBlockState.State}' --out table
Exemple de sortie
----------------------------------
| DescribeVpcs |
+-----------------+--------------+
| CIDRBlock | State |
+-----------------+--------------+
| 192.168.0.0/24 | associated |
| 192.168.1.0/24 | associated |
+-----------------+--------------+
6. Créer des sous-réseaux dans le nouveau CIDR :
Ces sous-réseaux doivent être dans les mêmes zones de disponibilité que les sous-réseaux des nœuds, pour une distribution cohérente :
new_subnet_id_1=$(aws ec2 create-subnet --vpc-id $vpc_id --availability-zone $az_1 --cidr-block 192.168.1.0/27 \
--tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=eks-custom-pod-networking-vpc-PrivateSubnet01},{Key=kubernetes.io/role/internal-elb,Value=1}]' \
--query Subnet.SubnetId --output text)
new_subnet_id_2=$(aws ec2 create-subnet --vpc-id $vpc_id --availability-zone $az_2 --cidr-block 192.168.1.32/27 \
--tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=eks-custom-pod-networking-vpc-PrivateSubnet02},{Key=kubernetes.io/role/internal-elb,Value=1}]' \
--query Subnet.SubnetId --output text)
7. Vérifier les sous-réseaux présents dans votre VPC :
aws ec2 describe-subnets --filters "Name=vpc-id,Values=$vpc_id" \
--query 'Subnets[*].{SubnetId: SubnetId,AvailabilityZone: AvailabilityZone,CidrBlock: CidrBlock}' \
--output table
## Étape 2 : Activer le réseau personnalisé sur EKS
La configuration du vpc faite, nous pouvons configurer le cluster eks. Par défaut le daemonset du plugin amazon vpc cni assigne aux pods les IPs et mes groupes de sécurité de l’interface primaire des noeuds. La variable d’environnement AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG
permet de modifier ce comportement en la définissant à true
afin que l’ipamd
utilise des groupes de sécurité et des sous-réseaux provenant de l’allocation d’interface réseau élastique d’un ENIConfig
. Cette dernière est une ressource custom qui est déployé par sous-réseau spécifique pour les pods.
1. Activer le réseau personnalisé
Activez la variable AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG
pour permettre l’utilisation des sous-réseaux personnalisés :
kubectl set env daemonset aws-node -n kube-system AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG=true
2. Récupérer les groupes de sécurité du cluster
Obtenez l’ID du groupe de sécurité de votre cluster ou celui que vous souhaitez appliquer aux pods :
cluster_security_group_id=$(aws eks describe-cluster --name $cluster_name --query cluster.resourcesVpcConfig.clusterSecurityGroupId --output text)
3. Créer des ENIConfig
pour chaque sous-réseau
Créez un fichier ENIConfig
pour chaque sous-réseau utilisé par les pods. Utilisez les sous-réseaux précédemment configurés :
cat >$az_1.yaml <<EOF
apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata:
name: $az_1
spec:
securityGroups:
- $cluster_security_group_id
subnet: $new_subnet_id_1
EOF
cat >$az_2.yaml <<EOF
apiVersion: crd.k8s.amazonaws.com/v1alpha1
kind: ENIConfig
metadata:
name: $az_2
spec:
securityGroups:
- $cluster_security_group_id
subnet: $new_subnet_id_2
EOF
Appliquez ces configurations dans le cluster :
kubectl apply -f $az_1.yaml
kubectl apply -f $az_2.yaml
kubectl get ENIConfigs
4. Vérifier la configuration de l’annotation ENI
Vérifiez si la variable ENI_CONFIG_ANNOTATION_DEF
est déjà définie :
kubectl describe daemonset aws-node -n kube-system | grep ENI_CONFIG_ANNOTATION_DEF
- Si elle n’est pas définie, configurez-la :
kubectl set env daemonset aws-node -n kube-system ENI_CONFIG_LABEL_DEF=topology.kubernetes.io/zone
Note : Les annotations
k8s.amazonaws.com/eniConfig
ont priorité sur les labels. Vérifiez qu’aucune annotation contradictoire n’est présente sur vos nœuds.
Si aucune valeur n’est définie, cela signifie que l’annotation ENI_CONFIG_ANNOTATION_DEF
n’existe pas encore. Cette variable est essentielle, car elle détermine la clé du label des nœuds utilisée pour sélectionner l’ENIConfig
. Elle doit être configurée lorsque la variable AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG=true
.
La valeur de cette variable spécifie le nom de l’ENIConfig
à appliquer sur un nœud donné. Avant de la définir, assurez-vous que l’annotation k8s.amazonaws.com/eniConfig
n’est pas déjà présente sur vos nœuds. Note : Les annotations ont toujours priorité sur les labels dans ce contexte.
Pour garantir une sélection automatique de la ressource ENIConfig
en fonction des zones de disponibilité, configurez la variable avec la commande suivante :
kubectl set env daemonset aws-node -n kube-system ENI_CONFIG_LABEL_DEF=topology.kubernetes.io/zone
6. Recréer les groupes de nœuds (si nécessaire)
Pour que les nouveaux nœuds utilisent le réseau personnalisé, recréez les groupes de nœuds avec le label k8s.amazonaws.com/eniConfig
. Si vos ENIConfig
ont des noms personnalisés, vous pouvez annoter les nœuds directement :
kubectl annotate node ip-192-168-0-126.us-west-2.compute.internal k8s.amazonaws.com/eniConfig=EniConfigName1
7. Vérifier les IPs des pods
Assurez-vous que les pods utilisent les IPs des sous-réseaux secondaires configurés :
kubectl get pods -A -o wide
Exemple de sortie :
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
kube-system aws-node-twpz2 2/2 Running 0 5m19s 192.168.0.113 ip-192-168-0-113.eu-west-1.compute.internal <none> <none>
kube-system aws-node-z8cg4 2/2 Running 0 5m21s 192.168.0.91 ip-192-168-0-91.eu-west-1.compute.internal <none> <none>
kube-system coredns-844dbb9f6f-r6b4p 1/1 Running 0 72m 192.168.1.29 ip-192-168-0-91.eu-west-1.compute.internal <none> <none>
kube-system coredns-844dbb9f6f-r7vj8 1/1 Running 0 72m 192.168.1.30 ip-192-168-0-91.eu-west-1.compute.internal <none> <none>
kube-system kube-proxy-ggxlb 1/1 Running 0 5m21s 192.168.0.91 ip-192-168-0-91.eu-west-1.compute.internal <none> <none>
kube-system kube-proxy-ps4vc 1/1 Running 0 5m19s 192.168.0.113 ip-192-168-0-113.eu-west-1.compute.internal <none> <none>
Dans cet exemple, les pods utilisent des IPs du bloc CIDR 192.168.1.0
.
Bien joué ! Votre cluster est maintenant configuré pour utiliser un réseau personnalisé. 🚀