Exclure les cibles défaillantes du trafic

AWSBeginner
Pratiquer maintenant

Introduction

Votre application possède deux serveurs derrière un Application Load Balancer. Une application peut tomber en panne alors que son instance EC2 fonctionne toujours. Vous configurerez les contrôles, provoquerez une panne réelle et vérifierez que le serveur sain continue à répondre. Vous rétablirez ensuite l'application et supprimerez les ressources d'équilibrage.

Vous devez connaître les listeners ALB, les groupes cibles et SSH sur EC2. Cette nouvelle machine fournit le réseau, deux serveurs actifs, leurs inscriptions et un listener ALB. Elle est indépendante du laboratoire précédent, avec AWS CLI configuré et les fichiers de connexion fournis.

Liens avec les certifications

Ce laboratoire propose une première pratique des sujets d'examen suivants.

Configurer les contrôles des cibles

Vous allez inspecter le service fourni et configurer la manière dont ALB vérifie la disponibilité de l'application.

Entrez dans le répertoire préparé et chargez les variables réseau :

cd /home/labex/project
source launch.env

Recherchez l'équilibreur et le groupe fournis par nom. Enregistrez leurs ARN pour les commandes suivantes et le nom DNS pour HTTP :

LB_ARN=$(aws elbv2 \
  describe-load-balancers \
  --names application-alb \
  --query 'LoadBalancers[0].LoadBalancerArn' \
  --output text)

TG_ARN=$(aws elbv2 \
  describe-target-groups \
  --names application-targets \
  --query 'TargetGroups[0].TargetGroupArn' \
  --output text)

LB_DNS=$(aws elbv2 \
  describe-load-balancers \
  --load-balancer-arns "$LB_ARN" \
  --query 'LoadBalancers[0].DNSName' \
  --output text)

Un contrôle de santé interroge chaque cible indépendamment des requêtes clientes. Le chemin doit signaler si l'application peut servir le trafic. Inspectez les paramètres actuels :

aws elbv2 \
  describe-target-groups \
  --target-group-arns "$TG_ARN" \
  --query 'TargetGroups[].{Path:HealthCheckPath,Interval:HealthCheckIntervalSeconds,Timeout:HealthCheckTimeoutSeconds,Healthy:HealthyThresholdCount,Unhealthy:UnhealthyThresholdCount,Matcher:Matcher}'

Le groupe fourni interroge /health toutes les 30 secondes. Pour cet exercice, configurez un intervalle de cinq secondes et un délai de deux secondes. Exigez deux échecs consécutifs pour exclure une cible et deux réussites pour la réintégrer. Le matcher accepte HTTP 200 comme réussite :

aws elbv2 \
  modify-target-group \
  --target-group-arn "$TG_ARN" \
  --health-check-protocol HTTP \
  --health-check-path /health \
  --health-check-interval-seconds 5 \
  --health-check-timeout-seconds 2 \
  --healthy-threshold-count 2 \
  --unhealthy-threshold-count 2 \
  --matcher HttpCode=200 \
  --query 'TargetGroups[].{Path:HealthCheckPath,Interval:HealthCheckIntervalSeconds,Healthy:HealthyThresholdCount,Unhealthy:UnhealthyThresholdCount}'

L'intervalle détermine la fréquence, le délai limite l'attente de chaque sonde. Les seuils évitent de réagir à une panne brève. En production, adaptez ces valeurs au démarrage et aux pannes de l'application ; ici elles sont courtes pour faciliter l'observation.

Attendez que les deux cibles soient saines, puis inspectez leurs états réels :

aws elbv2 \
  wait target-in-service \
  --target-group-arn "$TG_ARN"

aws elbv2 \
  describe-target-health \
  --target-group-arn "$TG_ARN" \
  --query 'TargetHealthDescriptions[].{Instance:Target.Id,Port:Target.Port,Health:TargetHealth.State}' \
  --output table

Ouvrez AWS View. Confirmez deux cibles healthy, puis cliquez sur Send request pour obtenir HTTP 200 réel. Les états et la réponse établissent la situation initiale.

Observer une panne applicative réelle

Vous allez faire échouer l'endpoint de santé de app-a en laissant son instance EC2 active.

Récupérez les IDs par les tags de nom fournis et l'adresse nécessaire pour SSH :

APP_A=$(aws ec2 \
  describe-instances \
  --filters Name=tag:Name,Values=app-a \
  --query 'Reservations[0].Instances[0].InstanceId' \
  --output text)

APP_B=$(aws ec2 \
  describe-instances \
  --filters Name=tag:Name,Values=app-b \
  --query 'Reservations[0].Instances[0].InstanceId' \
  --output text)

APP_A_IP=$(aws ec2 \
  describe-instances \
  --instance-ids "$APP_A" \
  --query 'Reservations[0].Instances[0].PublicIpAddress' \
  --output text)

L'application lit /etc/report-app/config.json à chaque requête. healthy détermine si /health renvoie 200 ou 503. Utilisez SSH avec la clé et les paramètres fournis. jq modifie ce seul champ ; un fichier temporaire évite d'écraser pendant la lecture, puis install remplace le fichier avec des permissions lisibles :

ssh -F ssh_config "ubuntu@$APP_A_IP" \
  'sudo jq ".healthy = false" /etc/report-app/config.json > /tmp/report-config.json && sudo install -m 644 /tmp/report-config.json /etc/report-app/config.json'

Vérifiez l'application depuis le serveur. -o /dev/null ignore le corps et -w affiche le statut HTTP :

ssh -F ssh_config "ubuntu@$APP_A_IP" \
  'curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8081/health'

Attendez 503. C'est une panne applicative, pas un arrêt EC2. Laissez passer deux contrôles, puis inspectez la cause :

sleep 12

aws elbv2 \
  describe-target-health \
  --target-group-arn "$TG_ARN" \
  --query 'TargetHealthDescriptions[].{Instance:Target.Id,Health:TargetHealth.State,Reason:TargetHealth.Reason}' \
  --output table

APP_A doit être unhealthy avec Target.ResponseCodeMismatch, car 503 ne correspond pas à 200. APP_B doit rester healthy. Les contrôles sont asynchrones ; si la transition est en cours, attendez puis répétez la requête.

Vérifiez que les instances EC2 sont toujours actives :

aws ec2 \
  describe-instances \
  --instance-ids "$APP_A" "$APP_B" \
  --query 'Reservations[].Instances[].{Instance:InstanceId,State:State.Name}' \
  --output table

Envoyez six requêtes distinctes via l'ALB :

for request in 1 2 3 4 5 6; do
  curl --config client.conf -sS "http://$LB_DNS/health"
  echo
done

Chaque réponse doit identifier APP_B. Dans AWS View, confirmez une cible défaillante et une saine. Cliquez plusieurs fois sur Send request ; les réponses réussies doivent identifier le serveur sain. ALB exclut la cible défaillante tant qu'une cible saine existe.

Une cible défaillante exclue pendant que le serveur sain répond

L'exemple montre HTTP 200 réel depuis la cible saine, alors que l'autre indique Target.ResponseCodeMismatch. Vos IDs diffèrent ; comparez la réponse à votre propre cible saine.

Si toutes les cibles sont défaillantes, ALB peut utiliser fail open et acheminer vers ces cibles. Garder app-b sain est essentiel ; un groupe entièrement défaillant ne prouve pas qu'ALB cesse toute transmission.

Rétablir et réintégrer la cible

Vous allez rétablir app-a et observer son retour au trafic après les contrôles réussis.

Restaurez seulement healthy avec le même remplacement sûr du fichier :

ssh -F ssh_config "ubuntu@$APP_A_IP" \
  'sudo jq ".healthy = true" /etc/report-app/config.json > /tmp/report-config.json && sudo install -m 644 /tmp/report-config.json /etc/report-app/config.json'

Confirmez que l'endpoint direct renvoie maintenant 200 :

ssh -F ssh_config "ubuntu@$APP_A_IP" \
  'curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8081/health'

L'application est rétablie, mais ALB doit encore observer les réussites consécutives configurées. Attendez l'état sain et inspectez les deux cibles :

aws elbv2 \
  wait target-in-service \
  --target-group-arn "$TG_ARN"

aws elbv2 \
  describe-target-health \
  --target-group-arn "$TG_ARN" \
  --query 'TargetHealthDescriptions[].{Instance:Target.Id,Health:TargetHealth.State}' \
  --output table

Les deux doivent être healthy. Envoyez de nouveau six requêtes :

for request in 1 2 3 4 5 6; do
  curl --config client.conf -sS "http://$LB_DNS/health"
  echo
done

Recherchez les deux IDs. Dans AWS View, confirmez les deux cartes saines et utilisez Send request pour observer les deux serveurs. Vous avez réparé l'application et laissé réussir les contrôles ; vous n'avez ni remplacé ni désinscrit l'instance.

Supprimer les ressources d'équilibrage

Vous allez supprimer la configuration d'équilibrage fournie tout en conservant les serveurs rétablis et le réseau.

Récupérez l'ARN du listener, supprimez d'abord celui-ci, puis l'ALB et son groupe :

LISTENER_ARN=$(aws elbv2 \
  describe-listeners \
  --load-balancer-arn "$LB_ARN" \
  --query 'Listeners[0].ListenerArn' \
  --output text)

aws elbv2 \
  delete-listener \
  --listener-arn "$LISTENER_ARN"

aws elbv2 \
  delete-load-balancer \
  --load-balancer-arn "$LB_ARN"

aws elbv2 \
  delete-target-group \
  --target-group-arn "$TG_ARN"

Confirmez que les deux listes sont vides :

aws elbv2 \
  describe-load-balancers \
  --query 'LoadBalancers[].LoadBalancerName'

aws elbv2 \
  describe-target-groups \
  --query 'TargetGroups[].TargetGroupName'

Attendez [] pour les deux requêtes et des zones d'équilibrage vides dans AWS View. Conservez les serveurs EC2 et le réseau fournis.

Résumé

Vous avez configuré les contrôles ALB, provoqué une panne réelle et distingué celle-ci d'un arrêt EC2. Vous avez observé le trafic sur le serveur sain, rétabli l'application et confirmé que les deux serveurs répondaient. Enfin, vous avez supprimé l'équilibrage et conservé les serveurs et le réseau.

Le prochain laboratoire utilise un groupe Auto Scaling pour remplacer les instances défaillantes au lieu de réparer manuellement un serveur.