Aller au contenu
English

Vérifier et supprimer

  • Leçon 15
  • 50 min
  • Module 5 : Déployer et nettoyer

Ce que vous saurez faire

« Succeeded » (réussi) n’est pas une preuve. Envoyez les requêtes qui montrent que le déploiement fonctionne et échoue sans danger, puis lisez ses journaux. Supprimez ensuite tout, avec une liste qui prouve que vous n’avez rien oublié.

Avant de commencerCe qu’il faut savoir et avoir sous la mainEnviron 50 minutes

Ce que vous devez savoir

Ce qu’il vous faut sur votre ordinateur

Testé avec Docker Desktop 4.81.0 (Docker Engine 29.6.1) sur macOS, avec une puce Apple. Les étapes Azure ont été exécutées avec Azure CLI 2.88.0 et l’extension containerapp 1.3.0b5, dans la région canadacentral. Les étapes Windows et Linux ne sont pas testées.

Tests de bon fonctionnement : ce que ce déploiement doit prouver

Section intitulée « Tests de bon fonctionnement : ce que ce déploiement doit prouver »

Un test de bon fonctionnement est une courte série de requêtes envoyées juste après un déploiement. pytest a déjà testé le code. Le test de bon fonctionnement vérifie ce déploiement : cette image, ces paramètres, ce secret, cette adresse. Chaque vérification prouve une chose :

Requête Résultat attendu Ce qu’elle prouve
GET /health 200 {"status":"ok"} Le processus fonctionne et le point d’entrée l’atteint.
GET /ready 200 {"status":"ready"} Le classificateur peut fonctionner.
POST /v1/classify avec la clé 200 et une catégorie Le secret est parvenu à l’application.
POST /v1/classify sans la clé 401 L’API n’est pas ouverte à tous.
GET /docs 404 SHOW_DOCS=false est parvenu à l’application.
http://…/health (en ligne seulement) 301 vers https:// Aucun HTTP non chiffré.
GET /v1/history avec la clé 503 history_unavailable (historique indisponible) Résultat attendu : ce déploiement n’a pas de base de données.

Deux vérifications attendent un échec. Un déploiement qui répond 200 sans clé est défectueux, même si toutes les autres vérifications réussissent.

Amira définit l’adresse une seule fois. La première requête arrive après une période d’inactivité, alors elle mesure sa durée :

Terminal (live)
URL=https://ticket-api.nicewater-a307f95a.canadacentral.azurecontainerapps.io
time curl -s $URL/health

La sortie (en ligne, abrégée) :

{"status":"ok"}
real 18.4s

18 secondes pour une petite requête. L’application n’avait aucune réplique. La plateforme devait donc d’abord en démarrer une : c’est un démarrage à froid. Les requêtes suivantes ont pris moins d’une seconde. Réveillez l’application avec /health avant une vérification chronométrée. Ainsi, un démarrage à froid ne donnera pas l’impression d’une API lente.

Ensuite, les autres vérifications. $KEY est la clé de Registre et déploiement : étape 6 : créer l’application conteneurisée, encore dans le terminal :

Terminal (live)
curl -s $URL/ready
curl -s -X POST $URL/v1/classify -H 'Content-Type: application/json' -H "X-API-Key: $KEY" -d '{"subject":"Charged twice for March"}'
curl -s -o /dev/null -w "%{http_code}\n" -X POST $URL/v1/classify -H 'Content-Type: application/json' -d '{"subject":"x"}'
curl -s -o /dev/null -w "%{http_code}\n" $URL/docs
curl -s $URL/v1/history -H "X-API-Key: $KEY"

La sortie (en ligne) :

{"status":"ready"}
{"category":"billing","priority":1,"confidence":0.7,"model_version":"keywords-1.0"}
401
404
{"error":{"code":"history_unavailable","message":"The history is not available. Try again later.","request_id":"a6c8601cf7fb","fields":[]}}

Chaque réponse correspond au résultat attendu. La vérification http:// a donné 301, comme dans Configuration opérationnelle : point d’entrée. L’historique donne 503, car la conception infonuagique ne prévoit aucune base de données. Un serveur PostgreSQL géré coûte de l’argent chaque heure, et l’exercice n’en a pas besoin. L’API l’indique dans son format d’erreur standard, avec un identifiant de requête. DATABASE_URL est un paramètre facultatif : avec lui, la même image conserverait un historique.

La collection Postman du cours sur les API fonctionne aussi. Réglez baseUrl sur l’adresse dans l’environnement Deployed (déployé), comme dans Vérifier et nettoyer : exemple détaillé : l’environnement Deployed.

Les mêmes vérifications, sur http://127.0.0.1:8080. La clé vient du fichier de secrets, donc vous ne la tapez pas :

Terminal (simulated)
URL=http://127.0.0.1:8080
KEY=$(cat secrets/api_key.txt)
curl -s $URL/health
curl -s $URL/ready
curl -s -X POST $URL/v1/classify -H 'Content-Type: application/json' -H "X-API-Key: $KEY" -d @requests/billing.json
curl -s -o /dev/null -w "%{http_code}\n" -X POST $URL/v1/classify -H 'Content-Type: application/json' -d '{"subject":"x"}'
curl -s -o /dev/null -w "%{http_code}\n" $URL/docs
curl -s -o /dev/null -w "%{http_code}\n" $URL/v1/history -H "X-API-Key: $KEY"

La sortie (simulée) :

{"status":"ok"}
{"status":"ready"}
{"category":"billing","priority":1,"confidence":0.9,"model_version":"keywords-1.0"}
401
404
503

La simulation n’a aucun démarrage à froid (le conteneur fonctionne toujours) ni aucun 301 (il n’y a pas de HTTPS). Notez-le dans les preuves : ces deux vérifications concernent seulement le parcours en ligne.

En ligne : les lignes de l’application. L’application écrit les mêmes lignes de journal que sur votre ordinateur. Azure les recueille :

Terminal (live)
az containerapp logs show -g $RG -n ticket-api --tail 12 --format text

La sortie (en ligne, abrégée) :

2026-10-07T16:17:09.83371 Connecting to the container 'ticket-api'...
2026-10-07T16:17:09.93183 Successfully Connected to container: 'ticket-api' [Revision: 'ticket-api--0000001', Replica: 'ticket-api--0000001-84c5f7d4bb-9zszh']
2026-10-07T16:16:54.6157582Z stderr F INFO ticket_api: GET /health 200 1ms id=caf6c4a82e30
2026-10-07T16:16:54.6158236Z stdout F INFO: 127.0.0.1:52216 - "GET /health HTTP/1.1" 200 OK
2026-10-07T16:17:04.6139872Z stderr F INFO ticket_api: GET /ready 200 2ms id=81dbb27c35d7
2026-10-07T16:17:04.6140104Z stdout F INFO: 127.0.0.1:59104 - "GET /ready HTTP/1.1" 200 OK
2026-10-07T16:17:05.7192419Z stderr F INFO ticket_api: POST /v1/classify 200 2ms id=95f853debb5b
2026-10-07T16:17:05.7193523Z stdout F INFO: 100.100.0.60:49458 - "POST /v1/classify HTTP/1.1" 200 OK
2026-10-07T16:17:06.5050443Z stderr F INFO ticket_api: GET / 404 0ms id=71d34007b1a1
2026-10-07T16:17:06.5051432Z stdout F INFO: 100.100.0.60:49464 - "GET / HTTP/1.1" 404 Not Found

Lisez les adresses des clients. 127.0.0.1 correspond aux sondes : elles s’exécutent dans la réplique. 100.100.0.60 est le point d’entrée de la plateforme : chaque requête externe passe par lui. stderr F et stdout F indiquent le flux, et F signifie une ligne complète.

Regardez la dernière requête : GET / avec 404. Personne dans l’équipe ne l’a envoyée. Elle est arrivée quelques minutes après l’attribution de l’adresse publique, suivie d’autres à 16 h 19 et 16 h 27. Ce sont des requêtes que vous n’avez pas envoyées. Elles peuvent venir de programmes qui parcourent Internet à la recherche de nouvelles adresses. Chacune réveille l’application et lance l’attente de 300 secondes avant le retour à zéro instance. Une adresse publique l’est dès la première minute. C’est pourquoi la première révision exigeait déjà la clé.

En ligne : les journaux système. Les événements de la plateforme (récupérations d’images, démarrages, échecs des sondes) sont séparés. Vous les avez utilisés dans Configuration opérationnelle : az containerapp logs show … --type system, sans --format text.

En ligne : Log Analytics. L’espace de travail conserve les lignes, et vous pouvez les chercher avec une requête. Elles sont arrivées environ 2 minutes plus tard :

Terminal (live)
WS=$(az monitor log-analytics workspace list -g $RG --query "[0].customerId" -o tsv)
az monitor log-analytics query -w $WS --analytics-query "ContainerAppConsoleLogs_CL | where Log_s has 'classify' | project TimeGenerated, RevisionName_s, Log_s | take 5" -o table

La sortie (en ligne, abrégée) :

Log_s RevisionName_s TimeGenerated
------------------------------------------------------------------ ------------------- ---------------------------
INFO ticket_api: POST /v1/classify 200 2ms id=95f853debb5b ticket-api--0000001 2026-10-07T16:17:07.067693Z
INFO: 100.100.0.60:49458 - "POST /v1/classify HTTP/1.1" 200 OK ticket-api--0000001 2026-10-07T16:17:07.067693Z
...

Chaque ligne indique sa révision. Après un déploiement, cela vous indique quelle version a répondu à une requête. Pour examiner une erreur, cherchez son identifiant de requête : where Log_s has 'a6c8601cf7fb'.

Simulation : les journaux Compose. Un client envoie une requête sans clé et reçoit un identifiant de requête dans l’erreur :

Terminal (simulated)
curl -s -X POST http://127.0.0.1:8080/v1/classify -H 'Content-Type: application/json' -d '{"subject":"Parcel lost"}'
docker compose -f deploy/local-cloud.yaml logs api | grep 0008b89dda79

La sortie (simulée) :

{"error":{"code":"unauthorized","message":"A valid X-API-Key header is required.","request_id":"0008b89dda79","fields":[]}}
api-1 | INFO ticket_api: POST /v1/classify 401 7ms id=0008b89dda79

Dans PowerShell, utilisez Select-String 0008b89dda79 au lieu de grep. Les requêtes de la simulation viennent d’une adresse comme 172.21.0.1 (la passerelle du réseau Compose). Ses vérifications de santé viennent de 127.0.0.1, comme les sondes Azure.

Un déploiement d’exercice n’est terminé que lorsqu’il a disparu. La règle : d’abord lister, ensuite supprimer, puis vérifier. Seule une liste créée avant la suppression permet de savoir ensuite que rien n’a été oublié.

Supprimer dans Azure : 1, faire l'inventaire avec az resource list -g rg-ticket-api-practice. 2, supprimer le groupe avec az group delete --yes --no-wait. 3, a-t-il disparu? az group exists; si true, redemander plus tard. Quand la réponse est false, le groupe a disparu. Trouver ce qui reste dans Azure : 4, un coffre supprimé de façon réversible? az keyvault list-deleted; si oui, le purger avec az keyvault purge. 5, vérifier de nouveau avec az group list et az role assignment list. Quand il ne reste rien : sur votre ordinateur, 6, supprimer les copies locales avec docker image rm et docker logout. 7, consigner le nettoyage dans DEPLOY.md.
L'ordre du nettoyage, avec une vérification après chaque suppression. L'inventaire vient en premier. La suppression du groupe s'exécute en arrière-plan. Vous vérifiez son résultat au lieu d'attendre.
Description textuelle du diagramme

Listez d’abord toutes les ressources du groupe. Supprimez ensuite le groupe sans attendre la fin de la commande. Demandez plus tard à Azure si le groupe existe encore. Une fois le groupe disparu, cherchez ce que sa suppression laisse : un Key Vault supprimé de façon réversible, à purger. Vérifiez qu’il ne reste aucun groupe ni aucune attribution de rôle. Supprimez ensuite les copies sur votre ordinateur et consignez chaque résultat.

Terminal (live)
az resource list --resource-group $RG -o table

La sortie (en ligne, avec le Key Vault facultatif du module 4) :

Name ResourceGroup Location Type Status
--------------------------------- ---------------------- ------------- ------------------------------------------------ ---------
ticketapi4821 rg-ticket-api-practice canadacentral Microsoft.ContainerRegistry/registries Succeeded
id-ticket-api rg-ticket-api-practice canadacentral Microsoft.ManagedIdentity/userAssignedIdentities Succeeded
workspace-rgticketapipracticeXXXX rg-ticket-api-practice canadacentral Microsoft.OperationalInsights/workspaces Succeeded
cae-ticket-api rg-ticket-api-practice canadacentral Microsoft.App/managedEnvironments Succeeded
ticket-api rg-ticket-api-practice canadacentral Microsoft.App/containerApps Succeeded
kv-ticket-api-4821 rg-ticket-api-practice canadacentral Microsoft.KeyVault/vaults Succeeded

Copiez ce tableau dans DEPLOY.md avant toute suppression. Comparez-le à la conception dans docs/cloud-design.md : l’espace de travail est la ressource que personne n’a demandée. Les attributions de rôles ne figurent pas dans cette liste. Elles sont liées aux ressources auxquelles elles s’appliquent.

Étape 2 : supprimer le groupe et vérifier plus tard

Section intitulée « Étape 2 : supprimer le groupe et vérifier plus tard »
Terminal (live)
az group delete --name $RG --yes --no-wait

La commande n’affiche rien et rend la main immédiatement. Sans --no-wait, elle attend la fin de la suppression. Dans le test, cela a pris environ 28 minutes, de 16 h 36 à 17 h 04. L’environnement Container Apps a été la dernière ressource supprimée. Pendant la suppression, az group show -n $RG --query properties.provisioningState -o tsv indique Deleting (suppression en cours). Plus tard, demandez :

Terminal (live)
az group exists --name $RG

true (vrai) signifie que la suppression n’est pas terminée : redemandez dans quelques minutes. La sortie à la fin (en ligne) :

false

Étape 3 : ce que la suppression d’un groupe laisse

Section intitulée « Étape 3 : ce que la suppression d’un groupe laisse »

Si vous avez créé le Key Vault, il n’a pas complètement disparu :

Terminal (live)
az keyvault list-deleted --query "[].{name:name, deleted:properties.deletionDate, purge:properties.scheduledPurgeDate}" -o table

La sortie (en ligne) :

Name Deleted Purge
------------------ ------------------------- -------------------------
kv-ticket-api-4821 2026-10-07T16:36:40+00:00 2027-01-05T16:36:40+00:00

Le coffre est supprimé de façon réversible. Azure le conserve avec ses secrets pendant 90 jours pour permettre d’annuler une erreur. Cela ne coûte rien. Mais le secret existe encore, et personne ne peut créer un nouveau coffre portant ce nom. Purgez-le :

Terminal (live)
az keyvault purge --name kv-ticket-api-4821
az keyvault list-deleted --query "length(@)"

La purge n’affiche rien (code de sortie 0). La sortie du décompte (en ligne) :

0
Terminal (live)
az group list --query "[?contains(name,'ticket-api')].name" -o tsv
az role assignment list --all --query "[?contains(scope,'rg-ticket-api-practice')].{role:roleDefinitionName,scope:scope}" -o table

Les deux commandes n’ont rien affiché (en ligne). Aucun groupe, et les attributions de rôles ont été supprimées avec le registre et le coffre.

Terminal (live)
docker image rm $ACR.azurecr.io/ticket-api:1.1.0 $ACR.azurecr.io/ticket-api:1.1.0-arm64
docker logout $ACR.azurecr.io

La sortie (en ligne) :

Untagged: ticketapi4821.azurecr.io/ticket-api:1.1.0
Untagged: ticketapi4821.azurecr.io/ticket-api:1.1.0-arm64
...
Removing login credentials for ticketapi4821.azurecr.io

Omettez l’étiquette 1.1.0-arm64 si vous ne l’avez pas créée. Ajoutez toute autre étiquette que vous avez envoyée au registre. docker logout supprime le jeton du registre du magasin d’identifiants de Docker. Conservez ticket-api:1.1.0 : c’est votre image, et le travail final l’utilise. Dans le test, les ressources ont existé pendant environ 54 minutes. Le coût prévu : une journée de registre Basic (0,17 $ US) et quelques cents ou moins de calcul, dans l’allocation gratuite.

La même règle : lister, supprimer, vérifier.

Terminal (simulated)
docker ps -a --filter name=ticket-api --format "table {{.Names}}\t{{.Image}}\t{{.Status}}"
docker volume ls --filter name=ticket-api-registry

La sortie (simulée) :

NAMES IMAGE STATUS
ticket-api-registry registry:3.1.2 Up 16 seconds
ticket-api-cloud-sim-api-1 ticket-api:1.1.0 Up 3 minutes (healthy)
DRIVER VOLUME NAME
local ticket-api-registry-data

Si votre base de données du module 3 fonctionne, ses conteneurs figurent aussi dans la liste. Conservez-les. Supprimez ensuite seulement la simulation et le registre :

Terminal (simulated)
docker compose -f deploy/local-cloud.yaml down
docker rm -f ticket-api-registry
docker volume rm ticket-api-registry-data
docker image rm 127.0.0.1:5000/ticket-api:1.1.0 127.0.0.1:5000/ticket-api:1.1.0-arm64 registry:3.1.2

Ajoutez toute autre étiquette que vous avez envoyée au registre, comme 1.1.0-native.

La sortie (simulée, abrégée) :

Container ticket-api-cloud-sim-api-1 Removed
Network ticket-api-cloud-sim_default Removed
ticket-api-registry
ticket-api-registry-data
Untagged: 127.0.0.1:5000/ticket-api:1.1.0
...
Untagged: registry:3.1.2

Le registre conserve ses images dans le volume ticket-api-registry-data : 71,24 Mo dans le test. C’est la taille comprimée de l’image amd64 (docker system df -v l’affiche). Sans -v ticket-api-registry-data:… dans la commande docker run, Docker crée un volume avec un nom aléatoire. docker rm -f le laisse alors en place. Un volume nommé rend l’inventaire clair. Vérifiez que les commandes de liste du début n’affichent plus aucune ligne de simulation.

  1. Parcours en ligne : réveillez l’application avec /health et notez la durée de la première requête.
  2. Exécutez les tests de bon fonctionnement de votre parcours. Comparez chaque réponse au tableau dans Tests de bon fonctionnement.
  3. Retrouvez votre requête de classification dans les journaux. En ligne : az containerapp logs show --format text. Simulation : docker compose … logs api | grep <request ID>.
  4. Parcours en ligne : cherchez une requête que vous n’avez pas envoyée, comme GET /.
  5. Faites l’inventaire : az resource list -g $RG -o table, ou les listes docker ps -a et docker volume ls. Copiez-le dans DEPLOY.md.
  6. Supprimez. En ligne : az group delete --name $RG --yes --no-wait. Simulation : les quatre commandes du nettoyage de la simulation.
  7. Vérifiez. En ligne : az group exists jusqu’à false (faux), puis az keyvault list-deleted (purgez au besoin), az group list et az role assignment list. Simulation : les deux commandes de liste de nouveau.
  8. Supprimez les copies locales et déconnectez-vous du registre (en ligne).
  9. Consignez chaque vérification et son résultat dans DEPLOY.md.
Afficher le résultat attendu

Chaque test de bon fonctionnement donne le statut attendu : 200, 200, 200, 401, 404 et (en ligne) 301, avec 503 history_unavailable pour l’historique. az group exists indique false, az keyvault list-deleted --query "length(@)" indique 0, et les listes de groupes et de rôles sont vides. Simulation : il ne reste aucune ligne ticket-api-cloud-sim ou ticket-api-registry. DEPLOY.md contient l’inventaire d’avant la suppression et le résultat de chaque vérification, comme dans le corrigé de Exercices du module.

À vous de jouer : une vérification rapide que vous pouvez répéter

Section intitulée « À vous de jouer : une vérification rapide que vous pouvez répéter »

Écrivez smoke-check.sh (ou smoke-check.ps1) pour vérifier /health, /ready, classify avec et sans clé, et /docs. Le script prend l’adresse dans URL et la clé dans TICKET_API_KEY, jamais dans le fichier. Il affiche PASS (réussite) ou FAIL (échec) pour chaque vérification. Il termine avec le code de sortie 1 si une vérification échoue. Que doit-il faire quand TICKET_API_KEY n’est pas définie?

Afficher une réponse pour macOS et Linux
smoke-check.sh
#!/bin/sh
# Smoke checks for the deployed ticket API.
# Set URL and TICKET_API_KEY first. The key never goes in this file.
if [ -z "$URL" ] || [ -z "$TICKET_API_KEY" ]; then
echo "Set URL and TICKET_API_KEY first." >&2
exit 2
fi
fail=0
check() {
name=$1; want=$2; shift 2
got=$(curl -s -o /dev/null -w "%{http_code}" "$@")
if [ "$got" = "$want" ]; then
echo "PASS $name $got"
else
echo "FAIL $name: got $got, expected $want"
fail=1
fi
}
check health 200 "$URL/health"
check ready 200 "$URL/ready"
check classify 200 -X POST "$URL/v1/classify" -H "Content-Type: application/json" \
-H "X-API-Key: $TICKET_API_KEY" -d '{"subject":"Charged twice for March"}'
check no-key 401 -X POST "$URL/v1/classify" -H "Content-Type: application/json" -d '{"subject":"x"}'
check docs-hidden 404 "$URL/docs"
exit $fail

La sortie (simulée), d’abord avec la bonne clé, puis avec une mauvaise :

$ TICKET_API_KEY=$(cat secrets/api_key.txt) URL=http://127.0.0.1:8080 sh smoke-check.sh
PASS health 200
PASS ready 200
PASS classify 200
PASS no-key 401
PASS docs-hidden 404
$ TICKET_API_KEY=wrong URL=http://127.0.0.1:8080 sh smoke-check.sh
PASS health 200
PASS ready 200
FAIL classify: got 401, expected 200
PASS no-key 401
PASS docs-hidden 404

Les codes de sortie étaient 0 et 1. Sans clé, le script s’arrête immédiatement avec le code de sortie 2 et un message clair. Il n’envoie pas de requêtes vouées à l’échec. La fonction de vérification envoie une requête et compare seulement le code d’état. Cela suffit pour une vérification rapide : pytest a vérifié les corps des réponses avant le déploiement. Le même script fonctionne pour les deux parcours. Seule URL change.

Erreur courante

La recherche par étiquette ne trouve rien, mais les ressources sont là

Symptôme (réel) : Amira a ajouté l’étiquette purpose=practice au groupe. Pour trouver toutes les ressources d’exercice, elle fait une recherche par étiquette :

Terminal (live)
az resource list --tag purpose=practice --query "[].{name:name, type:type}" -o table

La commande n’affiche rien. Mais az resource list -g rg-ticket-api-practice affiche six ressources. Un nettoyage fondé sur cette recherche indiquerait « rien à supprimer », alors que le registre entraîne des frais chaque jour.

Cause : les étiquettes d’un groupe de ressources ne sont pas transmises aux ressources qu’il contient. Le groupe a l’étiquette. Le registre, l’application et les autres ressources ne l’ont pas. --tag recherche les étiquettes propres aux ressources.

Solution :

  1. Faites l’inventaire à partir du groupe de ressources : az resource list -g $RG -o table. Le groupe délimite ce que vous supprimez. Il doit donc aussi délimiter ce que vous listez.
  2. Si vous avez besoin d’étiquettes sur les ressources, ajoutez-les à chacune, par exemple avec --tags dans chaque commande create (créer). Azure Policy peut aussi imposer ou copier des étiquettes, mais cela dépasse le cadre de ce cours.
  3. Après le nettoyage, vérifiez avec des commandes qui ne peuvent manquer aucune ressource : az group exists et az group list.

Pour un vrai service d’IA : les serveurs GPU et le stockage des modèles coûtent beaucoup plus cher que ce registre. Une équipe qui nettoie « tout ce qui porte l’étiquette experiment » peut laisser un serveur GPU fonctionner pendant des semaines. Un inventaire dont vous pouvez prouver l’exhaustivité protège mieux le budget qu’une recherche. Utilisez un groupe par expérience et listez son contenu avant la suppression.

Vérifiez votre compréhension

Pourquoi une vérification rapide inclut-elle des requêtes qui doivent échouer, comme classify sans clé et /docs?

Afficher la réponse

Elles prouvent que les paramètres de sécurité sont appliqués au déploiement. Un mauvais déploiement peut réussir toutes les vérifications des cas normaux. Si le secret ou REQUIRE_API_KEY manque, classify sans clé pourrait répondre 200. L’API serait alors accessible à tout le monde sur Internet. Si SHOW_DOCS est mal configuré, /docs expose toute l’API à des inconnus. Seule une requête qui doit échouer permet de le détecter. Un déploiement qui répond 200 à ces requêtes est défectueux, même si toutes les autres vérifications réussissent.

Vérifiez votre compréhension

Dans les journaux réels, certaines requêtes viennent de 127.0.0.1 et d'autres de 100.100.0.60. Lesquelles, et pourquoi un GET / que vous n'avez jamais envoyé compte-t-il?

Afficher la réponse

127.0.0.1 correspond aux sondes : la plateforme les exécute dans la réplique, donc elles proviennent de la réplique elle-même. 100.100.0.60 est le point d’entrée de la plateforme. Toutes les requêtes externes passent par lui, y compris les vôtres. Un GET / que personne dans l’équipe n’a envoyé montre que des inconnus trouvent et appellent une adresse publique en quelques minutes. Des programmes qui scrutent Internet font cela. Cette requête réveille l’application et relance l’attente de 300 secondes avant le retour à zéro réplique. Elle atteindrait aussi une API sans clé. C’est pourquoi la première révision exigeait déjà la clé.

Exercice guidé → tâche autonome. Vous avez vu chaque étape avec Amira dans les trois leçons. Refaites maintenant tout le module par vous-même. Faites un déploiement réel si vous avez un abonnement Azure, ou la simulation locale avec les mêmes concepts de configuration. Votre preuve est un fichier, DEPLOY.md, dans le projet. Il comporte trois parties :

  1. Liste de vérification du déploiement : chaque étape avec la commande exécutée et le résultat observé. Le nom de l’image avec son empreinte et sa plateforme.
  2. Inventaire des ressources : toutes les ressources, recensées avant la suppression, avec leurs coûts possibles et la façon de les supprimer.
  3. Registre du nettoyage : chaque suppression et chaque vérification qui suit, avec son résultat.

Indiquez réel ou simulé pour chaque résultat. Ne copiez pas les sorties de la leçon : utilisez les vôtres.

Afficher une réponse modèle (abrégée)
DEPLOY.md (live route, shortened)
# Deployment record: ticket-api 1.1.0
Route: live (Azure Container Apps, canadacentral).
## Checklist
- [x] Image built for linux/amd64 and pushed:
ticketapi4821.azurecr.io/ticket-api:1.1.0@sha256:cfd04194eb1b...
imagetools inspect: linux/amd64 (+ attestation)
- [x] App created: https://ticket-api.nicewater-a307f95a.canadacentral.azurecontainerapps.io
- [x] deploy/containerapp.yaml applied: revision ticket-api--0000001, Healthy, traffic 100
- [x] Smoke checks (live): /health 200 (18 s cold start), /ready 200,
classify 200, no key 401, /docs 404, http 301, history 503 (no database, expected)
## Inventory (before deletion)
| Resource | Type | Can it charge? | How to stop it |
|---|---|---|---|
| ticketapi4821 | Container registry, Basic | Yes, US$0.17 per day | Delete the group |
| ... | ... | ... | ... |
## Clean-up record (live)
| Step | Command | Result |
|---|---|---|
| Delete the group | az group delete --name rg-ticket-api-practice --yes --no-wait | started 16:36 |
| Group gone | az group exists --name rg-ticket-api-practice | false (17:04) |
| ... | ... | ... |

L’exemple complet, avec la variante simulée, est le fichier DEPLOY.md de l’instantané end-of-m05. La personne qui le révise l’évalue comme démontré quand trois conditions sont remplies. Les vérifications rapides incluent les cas d’échec. L’inventaire comprend l’espace de travail automatique. Chaque ligne de nettoyage comprend une vérification avec son résultat, pas seulement la commande de suppression.

Vérifiez votre compréhension

Rappel : nommez les trois types de sondes d'Azure Container Apps, le point de terminaison utilisé par l'API de billets pour chacun, et l'action de la plateforme en cas d'échec.

Afficher la réponse

Démarrage sur /health : la plateforme attend jusqu’à 30 échecs, soit 60 secondes, puis redémarre la copie. Les autres sondes attendent celle-ci. Vitalité sur /health : après 3 échecs, la plateforme redémarre la copie. Disponibilité sur /ready : après 3 échecs, la plateforme n’envoie plus de requêtes à la copie, mais ne la redémarre pas. Une nouvelle révision reçoit le trafic seulement quand elle est prête.

Vérifiez votre compréhension

Prédiction : vous exécutez az group delete --name rg-ticket-api-practice --yes et la commande se termine sans erreur. Quels coûts et risques peuvent subsister, et comment les vérifier?

Afficher la réponse

Si la commande est terminée, les ressources du groupe ont disparu. Le registre, l’application et l’espace de travail n’entraînent donc plus de frais. Mais un Key Vault en suppression réversible reste présent pendant 90 jours. Il ne coûte rien, mais ses secrets existent encore et son nom reste réservé. Vérifiez avec az keyvault list-deleted et purgez-le. Les ressources des autres groupes n’ont jamais figuré dans l’inventaire. Vérifiez donc az group list pour repérer un groupe d’exercice oublié. Sur votre ordinateur, le jeton du registre et les étiquettes envoyées restent présents jusqu’à docker logout et docker image rm. Avec --no-wait, la commande se termine immédiatement. Vérifiez donc az group exists jusqu’à ce qu’elle indique false (faux).

Vérifiez votre compréhension

Vérification finale : montrez votre DEPLOY.md. Documente-t-il un accès fonctionnel, l'inventaire des ressources et des étapes de nettoyage vérifiées?

Afficher la réponse

Un fichier DEPLOY.md complet contient : l’adresse (réelle) ou http://127.0.0.1:8080 (simulée), et l’image avec son empreinte et sa plateforme; les vérifications rapides avec leurs résultats, dont 401 sans clé et 404 pour /docs; l’inventaire fait avant la suppression, avec l’espace de travail Log Analytics automatique (réel) ou le volume du registre (simulé), et les coûts possibles de chaque élément; pour chaque suppression, une vérification avec son résultat : az group exists → false, az keyvault list-deleted → 0, listes de groupes et de rôles vides, docker logout (réel), ou listes docker ps -a et docker volume ls vides (simulé). Chaque résultat porte la mention réel ou simulé. Si une vérification manque, le nettoyage est présumé, pas vérifié.

Récapitulatif

  • Une vérification rapide valide ce déploiement et inclut les requêtes qui doivent échouer : sans clé → 401, /docs → 404.
  • Réveillez une application à zéro réplique avant une vérification chronométrée : la première requête a entraîné un démarrage à froid de 18 secondes.
  • Les journaux de l’application montrent vos requêtes, les sondes (127.0.0.1) et les requêtes que vous n’avez pas envoyées. Recherchez par identifiant de requête.
  • Nettoyez à partir d’un inventaire explicite : listez le groupe, supprimez-le avec --no-wait, vérifiez az group exists, purgez un Key Vault en suppression réversible, vérifiez les groupes et les rôles, supprimez les copies locales. Consignez chaque résultat dans DEPLOY.md.
  • Les étiquettes d’un groupe ne sont pas transmises à ses ressources. Faites l’inventaire à partir du groupe.

Réinitialisation. Pour recommencer ce module : en mode réel, le groupe de ressources doit avoir disparu (az group exists → false). En mode simulé, exécutez le nettoyage simulé ci-dessus. Votre projet et ticket-api:1.1.0 restent en place. Pour réinitialiser les fichiers du projet, copiez l’instantané end-of-m04. Pour voir ce que Docker stocke encore, exécutez docker system df.

Le cours. Vous avez commencé par « ça fonctionne sur mon ordinateur ». Maintenant, vous pouvez intégrer une API dans une image, avec son système d’exploitation, Python et ses paquets. Vous pouvez la construire rapidement et sans secrets, puis l’exécuter avec ses paramètres et une base de données. Vous pouvez l’associer aux services de base du nuage et à leurs coûts. Vous pouvez la déployer avec des vérifications et des limites, puis la supprimer avec des preuves. Le travail final vous demande de recommencer, par vous-même, dans un nouvel environnement.

Leçon suivante : Travail final