Introduction
Les Services fournissent aux clients une adresse stable pour un ensemble de Pods. Cela devient particulièrement utile lorsque la demande évolue : un Deployment peut ajouter ou supprimer des réplicas tandis que l’identité du Service reste inchangée.
Dans ce laboratoire, chaque backend renvoie le nom d’hôte de son propre Pod. Vous passerez de deux à quatre réplicas, enverrez des requêtes indépendantes via un seul Service et observerez les réponses de plusieurs Pods. Vous reviendrez ensuite à deux réplicas et suivrez la convergence du Deployment et de l’EndpointSlice vers ce nouvel état souhaité.
Il s’agit d’une mise à l’échelle horizontale manuelle. La mise à l’échelle automatique avec HPA dépend des demandes de ressources, des métriques et d’une politique de contrôle ; elle sera donc abordée après avoir bien compris le fonctionnement manuel des réplicas.
Construire une application répliquée observable
Démarrage de l’environnement : Ce lab démarre pour vous un cluster Kubernetes complet. La configuration du plan de contrôle, du nœud et des composants réseau prend généralement 2 à 3 minutes. Veuillez patienter jusqu’à la fin du chargement de l’environnement avant de commencer.
Dans cette étape, vous allez créer deux backends capables d’indiquer quel Pod a traité chaque requête. La répartition du trafic du Service devient ainsi visible et concrète.
La première commande utilise cd pour accéder à l’espace de travail préparé. La suivante utilise un document here : cat <<'EOF' > hostname-web.yaml écrit toutes les lignes suivantes, jusqu’au EOF de fermeture, dans le fichier YAML, en remplaçant son contenu précédent.
cd /home/labex/project/scale-lab
cat <<'EOF' > hostname-web.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: hostname-web
spec:
replicas: 2
selector:
matchLabels:
app: hostname-web
template:
metadata:
labels:
app: hostname-web
spec:
containers:
- name: web
image: busybox:1.36
imagePullPolicy: IfNotPresent
command: ["sh", "-c"]
args:
- mkdir -p /www; hostname > /www/index.html; exec httpd -f -p 8080 -h /www
ports:
- name: http
containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: hostname-web
spec:
selector:
app: hostname-web
ports:
- name: http
port: 80
targetPort: http
EOF
kubectl apply -f hostname-web.yaml
kubectl rollout status deployment/hostname-web --timeout=60s
kubectl get pods -l app=hostname-web
Après le EOF de fermeture, kubectl apply -f envoie tous les objets du fichier au serveur d’API. rollout status attend jusqu’à 60 secondes que les deux Pods souhaités soient disponibles, tandis que -l app=hostname-web ne liste que les Pods portant ce label.
Dans la commande du conteneur, les points-virgules exécutent les actions les unes à la suite des autres : créer /www, rediriger le nom d’hôte vers index.html, puis utiliser exec afin que le serveur web devienne le processus principal du conteneur. Les noms des deux Pods étant différents, chaque backend renvoie une valeur différente.
Établir les backends de référence
Dans cette étape, vous allez mettre en relation le nombre de réplicas du Deployment et le nombre de backends prêts du Service.
Examinez trois vues complémentaires. get deployment affiche le nombre de réplicas souhaités et prêts ; -l sélectionne les Pods de l’application et -o wide ajoute les colonnes d’adresse IP et de nœud ; le dernier sélecteur de labels recherche l’EndpointSlice créé pour ce Service :
kubectl get deployment hostname-web
kubectl get pods -l app=hostname-web -o wide
kubectl get endpointslices -l kubernetes.io/service-name=hostname-web
Le Deployment doit afficher 2/2, et l’EndpointSlice doit contenir deux adresses. Envoyez plusieurs requêtes au Service depuis un unique Pod client qui reste actif.
kubectl run crée un Pod autonome, car --restart=Never est défini. Le séparateur -- marque la fin des options de kubectl ; sleep 3600 est la commande du conteneur qui le maintient en fonctionnement. La boucle for utilise seq 1 6 pour générer six itérations, et kubectl exec POD -- COMMAND exécute wget dans le client à chaque fois :
kubectl run load-client --image=busybox:1.36 --image-pull-policy=IfNotPresent --restart=Never -- sleep 3600
kubectl wait --for=condition=Ready pod/load-client --timeout=30s
for i in $(seq 1 6); do kubectl exec load-client -- wget -qO- http://hostname-web; done
Chaque réponse correspond au nom d’un Pod. Sur un échantillon court, vous pouvez voir un seul nom ou les deux ; le Service ne garantit pas un ordre strict de type round-robin.
Effectuer une mise à l’échelle déclarative
Dans cette étape, vous allez modifier l’état souhaité enregistré, en passant de deux à quatre réplicas. La modification du manifeste permet de conserver le fichier et l’objet actif en cohérence.
sed -i 's/old/new/' file remplace directement le texte correspondant dans un fichier. grep -n recherche ensuite replicas: et affiche le numéro de ligne concerné, ce qui permet de vérifier rapidement la modification avant de l’appliquer :
cd /home/labex/project/scale-lab
sed -i 's/replicas: 2/replicas: 4/' hostname-web.yaml
grep -n 'replicas:' hostname-web.yaml
kubectl apply -f hostname-web.yaml
kubectl rollout status deployment/hostname-web --timeout=60s
kubectl get deployment hostname-web
Le Deployment doit afficher 4/4. Le contrôleur a créé deux Pods supplémentaires, car l’état réel comportait moins de Pods que le nouvel état souhaité.
Observer l’extension de l’ensemble des backends du Service
Dans cette étape, vous allez vérifier que le Service, resté inchangé, découvre automatiquement les nouveaux Pods.
La commande EndpointSlice utilise JSONPath, car le tableau standard peut abréger certains détails. range répète le modèle pour chaque endpoint ; chaque répétition affiche sa première adresse, le mot littéral ready, la valeur d’état correspondante et un retour à la ligne. La barre oblique inverse permet de poursuivre une même commande shell sur plusieurs lignes d’affichage :
kubectl get pods -l app=hostname-web -o wide
kubectl get endpointslices -l kubernetes.io/service-name=hostname-web \
-o jsonpath='{range .items[*].endpoints[*]}{.addresses[0]}{" ready="}{.conditions.ready}{"\n"}{end}'
Il y a maintenant quatre adresses prêtes. Vous n’avez pas modifié le Service : son sélecteur continue de correspondre à chaque Pod prêt portant le label app=hostname-web.
Comparez l’adresse IP stable du Service avec l’ensemble élargi des backends :
kubectl get service hostname-web -o wide
La ClusterIP reste stable, tandis que les membres de l’EndpointSlice évoluent.
Observer les requêtes atteindre plusieurs Pods
Dans cette étape, vous allez envoyer des requêtes HTTP indépendantes via un seul Service et récapituler les noms d’hôte des Pods qui répondent.
Tout d’abord, rm -f supprime un ancien fichier de résultats s’il existe ; -f rend également l’absence du fichier sans conséquence. La boucle envoie 20 requêtes. >> ajoute chaque nom d’hôte à la suite des précédents au lieu de les remplacer. Enfin, le tube transmet les lignes triées à uniq -c, qui regroupe les doublons adjacents et préfixe chaque nom d’hôte par son nombre d’occurrences :
rm -f /tmp/hostname-responses.txt
for i in $(seq 1 20); do
kubectl exec load-client -- wget -qO- http://hostname-web >> /tmp/hostname-responses.txt
done
sort /tmp/hostname-responses.txt | uniq -c
Vous devriez voir plusieurs noms d’hôte. Les décomptes peuvent être déséquilibrés, et une courte série de requêtes ne touchera pas nécessairement les quatre backends. Le routage des Services Kubernetes répartit les connexions, mais ne garantit ni une distribution parfaitement uniforme ni un ordre précis.
Vérifiez combien de backends distincts votre échantillon a atteints. sort -u conserve une seule occurrence de chaque nom d’hôte, le tube transmet ces lignes à wc -l, et wc -l compte les lignes :
sort -u /tmp/hostname-responses.txt | wc -l
Une valeur supérieure à un prouve directement que l’adresse stable du Service a acheminé les requêtes vers plusieurs Pods.
Effectuer une mise à l’échelle impérative
Dans cette étape, vous allez utiliser kubectl scale pour ajuster rapidement l’état actif, en passant de quatre réplicas à deux.
kubectl scale modifie immédiatement le nombre souhaité de réplicas du Deployment actif. --replicas=2 fournit le nouveau nombre ; cette commande ne modifie pas votre fichier YAML :
kubectl scale deployment/hostname-web --replicas=2
kubectl rollout status deployment/hostname-web --timeout=60s
kubectl get pods -l app=hostname-web
Kubernetes termine deux Pods et en conserve deux. Attendez que l’ensemble des backends du Service converge lui aussi.
Cette boucle d’interrogation limitée effectue au maximum 30 tentatives. À chaque passage, elle stocke dans count le nombre d’endpoints prêts ; jq filtre le JSON de l’EndpointSlice pour ne conserver que les endpoints prêts et renvoie la longueur du tableau. [ "$count" -eq 2 ] est un test numérique du shell, && break quitte la boucle lorsque le test réussit, et sleep 1 marque une pause avant la nouvelle tentative :
for i in $(seq 1 30); do
count=$(kubectl get endpointslices -l kubernetes.io/service-name=hostname-web -o json | jq '[.items[].endpoints[] | select(.conditions.ready == true)] | length')
[ "$count" -eq 2 ] && break
sleep 1
done
echo "Ready backends: $count"
Le Deployment actif demande désormais deux réplicas, mais le fichier en indique encore quatre. Cette différence est volontaire pour l’étape suivante.
Réconcilier le manifeste et consulter les traces du contrôleur
Dans cette étape, vous allez mettre le manifeste enregistré en accord avec l’état actif à deux réplicas et relier les actions de mise à l’échelle aux éléments de preuve fournis par le contrôleur.
Commencez par comparer les deux états souhaités. grep -n affiche la ligne enregistrée dans le fichier ; JSONPath extrait uniquement le champ actif .spec.replicas et ajoute un retour à la ligne :
grep -n 'replicas:' /home/labex/project/scale-lab/hostname-web.yaml
kubectl get deployment hostname-web -o jsonpath='Live replicas: {.spec.replicas}{"\n"}'
Modifiez le fichier pour revenir de quatre à deux réplicas, puis appliquez-le :
sed -i 's/replicas: 4/replicas: 2/' /home/labex/project/scale-lab/hostname-web.yaml
kubectl apply -f /home/labex/project/scale-lab/hostname-web.yaml
Comme l’état actif comporte déjà deux réplicas, cette application ne devrait pas créer de Pods supplémentaires. Consultez les événements du Deployment. Le tube transmet la sortie complète de describe à sed -n ; /Events:/,$p signifie « afficher depuis la ligne contenant Events: jusqu’à la fin » :
kubectl describe deployment hostname-web | sed -n '/Events:/,$p'
Recherchez les messages ScalingReplicaSet indiquant les décisions d’augmentation et de réduction du nombre de réplicas. Supprimez enfin le client temporaire. --ignore-not-found permet de réussir le nettoyage même si le Pod a déjà disparu :
kubectl delete pod load-client --ignore-not-found
La mise à l’échelle manuelle modifie le nombre souhaité de réplicas ; le contrôleur du Deployment crée ou termine les Pods, tandis que le Service suit automatiquement les membres prêts. Maintenir le manifeste synchronisé évite qu’un futur kubectl apply ne rétablisse inopinément une ancienne valeur.
Résumé
Vous avez fait passer manuellement un Deployment de deux réplicas à quatre, puis de nouveau à deux. Vous avez observé le contrôleur mettre les Pods en conformité, suivi l’évolution des membres de l’EndpointSlice au gré des backends prêts sans modifier le Service, et obtenu la preuve directe qu’une seule adresse de Service a acheminé des requêtes indépendantes vers plusieurs Pods.
Le modèle mental à retenir est le suivant : le nombre de réplicas représente l’état souhaité, le contrôleur du Deployment réconcilie les Pods réels et le Service suit les backends prêts portant les bons labels. Les fichiers déclaratifs doivent être réconciliés avec les modifications effectuées délibérément sur l’état actif afin que les futures applications restent prévisibles.


