Aller au contenu
English

Registre et déploiement

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

Ce que vous saurez faire

Placez l’image là où un service infonuagique peut la récupérer, avec un numéro de version dont le sens ne change jamais. Puis lancez-la sur un service de conteneurs géré que vous pouvez supprimer en une étape.

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, Buildx 0.35.0) 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 n’ont pas été testées.

Ce module propose deux options. Choisissez-en une avant de commencer, et gardez-la pour les trois leçons.

Réelle Simulée
Où l’API s’exécute Azure Container Apps, avec une adresse HTTPS publique Un conteneur sur votre ordinateur, à partir de deploy/local-cloud.yaml
Registre Azure Container Registry Un conteneur de registre sur 127.0.0.1:5000
Coût Quelques cents, si vous supprimez tout le jour même Gratuit
Il vous faut Un abonnement Azure Seulement Docker

Chaque sortie de ces leçons porte une indication. Les sorties réelles viennent de l’exécution sur Azure. Les sorties simulées viennent de Docker sur un Mac, le même jour. Une sortie simulée ne prétend jamais qu’une exécution a eu lieu dans un nuage. Les deux options fournissent les preuves pour l’exercice du module et le travail final.

Amira commence par une petite expérience sur son ordinateur. Elle lance un registre : un serveur qui stocke des images pour que d’autres ordinateurs puissent les télécharger. L’image officielle registry de Docker en est un exemple. Elle s’exécute sur son ordinateur comme tout autre conteneur :

Terminal (simulated route)
docker run -d --name ticket-api-registry -p 127.0.0.1:5000:5000 -v ticket-api-registry-data:/var/lib/registry registry:3.1.2

Elle donne un deuxième nom à son image, qui commence par l’adresse du registre, puis l’envoie au registre :

Terminal (simulated route)
docker tag ticket-api:1.1.0 127.0.0.1:5000/ticket-api:1.1.0
docker push 127.0.0.1:5000/ticket-api:1.1.0

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

The push refers to repository [127.0.0.1:5000/ticket-api]
0b13ca62e0be: Pushed
4732e419703d: Pushed
...
bbeda6b4abb7: Pushed
1.1.0: digest: sha256:1ba724a2b1215f0d2225b7276fa6ab5f5226c1e10c46c98ee9845af3fec459ee size: 856

Puis elle demande au registre ce qu’il contient. Un registre répond aux requêtes HTTP, donc curl peut l’interroger :

Terminal (simulated route)
curl -s http://127.0.0.1:5000/v2/_catalog
curl -s http://127.0.0.1:5000/v2/ticket-api/tags/list

La sortie (simulée) :

{"repositories":["ticket-api"]}
{"name":"ticket-api","tags":["1.1.0"]}

Passons aux noms. Un nom d’image complet comporte trois parties : <registry>/<repository>:<tag>.

Partie Ici Option réelle
Registre : le serveur 127.0.0.1:5000 ticketapi4821.azurecr.io
Dépôt : les versions d’une image, réunies ticket-api ticket-api
Étiquette : une version 1.1.0 1.1.0

Un nom sans registre, comme ticket-api:1.1.0, désigne Docker Hub, ou seulement votre ordinateur si l’image n’a jamais été envoyée. L’empreinte (sha256:1ba7…) désigne le contenu exact. Une étiquette pointe vers une empreinte. Toute personne autorisée à envoyer des images peut la déplacer vers une autre empreinte. C’est pourquoi chaque changement reçoit un nouveau numéro de version : 1.1.0, puis 1.1.1. Ne déployez jamais seulement latest. Dans un mois, personne ne pourra dire quel code latest désignait.

Chaque ligne Pushed (envoyée) correspond à une couche. Le registre stocke des couches, pas des images entières. Un deuxième envoi d’une image semblable transmet donc seulement les couches modifiées. L’envoi transfère les couches compressées : la colonne content size (taille du contenu) de docker image ls (73 Mo pour ticket-api:1.1.0), et non l’espace disque utilisé (345 Mo).

Un déploiement comporte quatre actions : construire, envoyer, déployer, vérifier. Chacune peut échouer d’une façon visible, si vous savez où regarder.

Sur votre ordinateur : 1, construisez avec docker buildx build --platform linux/amd64. 2, vérifiez avec imagetools inspect que l'image est linux/amd64; si elle est seulement arm64, reconstruisez-la. 3, envoyez ticketapi4821.azurecr.io/ticket-api:1.1.0. L'image est alors dans le registre. Sur Azure : 4, déployez avec az containerapp create ou update, ce qui crée une nouvelle révision. 5, la révision est-elle prête (image récupérée, sonde de démarrage réussie)? Sinon, l'ancienne révision garde le trafic; lisez les journaux système, corrigez et redéployez. Si oui, 6, vérifications de bon fonctionnement; si une vérification échoue, corrigez ou déployez la dernière étiquette fonctionnelle. Si tout réussit, 7, consignez l'adresse, la révision et l'image dans DEPLOY.md.
Construire, envoyer, déployer, vérifier. Les étapes 1 à 3 s'exécutent sur votre ordinateur. Les étapes 4 à 7 visent le nuage. Chaque branche d'échec revient à une étape précédente. L'ancienne version continue de servir les requêtes pendant vos corrections.
Description textuelle du diagramme

La construction produit une image pour linux/amd64, le type de processeur des serveurs du nuage. Vérifiez la plateforme avant l’envoi. L’envoi place l’image dans le registre sous une étiquette versionnée. Le déploiement crée une nouvelle révision : une copie fixe des paramètres et de l’image de l’application. Si la révision ne démarre pas, l’ancienne garde le trafic. Vous lisez les journaux (logs) système, corrigez la cause et redéployez. Si elle démarre, le trafic passe à cette révision, et vous lancez les vérifications de bon fonctionnement. Lorsqu’elles réussissent, vous consignez ce que vous avez déployé. Cette leçon couvre les étapes 1 à 4. Configuration opérationnelle couvre l’étape 5, et Vérifier et supprimer couvre les étapes 6 et 7.

Azure Container Apps exécute seulement des images linux/amd64. Un simple docker build sur un Mac à puce Apple produit une image linux/arm64. Amira vérifie ce que contient son image :

Terminal
docker buildx imagetools inspect 127.0.0.1:5000/ticket-api:1.1.0

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

Name: 127.0.0.1:5000/ticket-api:1.1.0
MediaType: application/vnd.oci.image.index.v1+json
Digest: sha256:1ba724a2b1215f0d2225b7276fa6ab5f5226c1e10c46c98ee9845af3fec459ee
Manifests:
Name: 127.0.0.1:5000/ticket-api:1.1.0@sha256:97dd1c69...
Platform: linux/arm64
Name: 127.0.0.1:5000/ticket-api:1.1.0@sha256:c66bcb26...
Platform: unknown/unknown

Seulement linux/arm64. L’entrée unknown/unknown (inconnu/inconnu) est l’attestation de construction : une trace de la façon dont l’image a été construite, pas une deuxième image. Sur un ordinateur Intel ou AMD, vous voyez linux/amd64 ici. La prochaine construction sera alors identique à la vôtre.

Prédisez : que se passe-t-il si un ordinateur avec un processeur amd64 demande cette image? Amira la demande comme le ferait un ordinateur amd64 :

Terminal
docker pull --platform linux/amd64 127.0.0.1:5000/ticket-api:1.1.0-arm64

La sortie (simulée; elle a d’abord envoyé la même image arm64 avec l’étiquette 1.1.0-arm64) :

Error response from daemon: no matching manifest for linux/amd64 in the manifest list entries: no match for platform in manifest: not found

Docker le dit clairement. Azure ne le fait pas, comme vous le verrez dans Configuration opérationnelle. Amira construit donc pour le nuage avec --platform :

Terminal (simulated route)
docker buildx build --platform linux/amd64 -t 127.0.0.1:5000/ticket-api:1.1.0 --push .

La sortie (simulée, la fin) :

#12 naming to 127.0.0.1:5000/ticket-api:1.1.0 done
#12 pushing layers 0.0s done
#12 pushing manifest for 127.0.0.1:5000/ticket-api:1.1.0@sha256:204c4f72f635011840ac1cb898cbd2de5e1aa6c189905078971cfe8283f002f6 0.1s done
#12 DONE 0.2s

Les couches amd64 étaient dans le cache de construction depuis une construction précédente. Cela a donc pris moins d’une seconde. Sans le cache, la même construction a pris 23 secondes, et RUN pip install a pris 19,7 secondes plutôt que 11,8 secondes. Un Mac à puce Apple exécute les programmes amd64 par émulation : un programme traduit les instructions de l’autre processeur. --push envoie immédiatement le résultat au registre. Maintenant, imagetools inspect indique Platform: linux/amd64 (plateforme : linux/amd64).

Regardez l’empreinte : ce n’est plus 1ba724…. La même étiquette, 1.1.0, pointe maintenant vers un contenu différent. Gardez cela en tête pour l’erreur courante à la fin de la leçon.

Votre ordinateur exécute docker buildx build --platform linux/amd64 et, à l'étape 3, envoie ticket-api:1.1.0 au registre. Tout le reste se trouve dans le groupe de ressources rg-ticket-api-practice (étape 1, canadacentral, étiquettes purpose=practice et course=C18) : le registre ticketapi4821, Basic (étape 2); l'identité gérée id-ticket-api (étape 4), qui a le rôle AcrPull sur ce registre seulement et, facultativement, Secrets User sur le Key Vault kv-ticket-api-4821; l'environnement Container Apps cae-ticket-api (étape 5) contenant l'application conteneurisée ticket-api (étape 6), qui utilise id-ticket-api, a 0,25 processeur virtuel, 0,5 Gio et de 0 à 2 réplicas, et récupère l'image du registre; et l'espace de travail Log Analytics créé automatiquement à l'étape 5, qui reçoit les journaux. Les clients sur Internet, et les programmes qui le balayent, atteignent l'application par HTTPS grâce au trafic entrant externe sur le port cible 8000.
Ce que l'option réelle crée, dans l'ordre des étapes. Six ressources dans un groupe de ressources (cinq sans le Key Vault facultatif). L'étape 5 en crée deux.
Description textuelle du diagramme

Les numéros indiquent l’ordre des étapes ci-dessous. Le groupe de ressources contient tout; le supprimer supprime donc tout. Il y a une exception, le Key Vault, traitée dans Vérifier et supprimer. L’identité peut récupérer des images seulement de ce registre. L’environnement crée un espace de travail Log Analytics que vous n’avez pas demandé. Celui-ci peut facturer les données de journaux.

Amira suit la conception du module 4. Elle place d’abord les noms dans des variables de l’interpréteur de commandes. Chaque commande est ainsi plus courte, et elle ne peut pas mal saisir un nom. Choisissez votre propre nom de registre : il doit être unique dans tout Azure, avec 5 à 50 lettres et chiffres, sans traits d’union. Ajoutez vos propres chiffres à ticketapi.

Terminal
RG=rg-ticket-api-practice
LOCATION=canadacentral
ACR=ticketapi4821

Les variables existent seulement dans cette fenêtre de terminal. Si vous en ouvrez une nouvelle, définissez-les de nouveau. Les commandes ci-dessous utilisent $RG, $ACR et les autres, de la même façon dans les deux interpréteurs de commandes. Quand une commande diffère, des onglets sont proposés.

Avant l’étape 1 : se connecter et préparer l’abonnement

Section intitulée « Avant l’étape 1 : se connecter et préparer l’abonnement »
Terminal
az login
az extension add --name containerapp --upgrade
az provider register --namespace Microsoft.App
az provider register --namespace Microsoft.OperationalInsights
az provider register --namespace Microsoft.ContainerRegistry

az login ouvre le navigateur pour votre connexion à Azure. L’extension ajoute les commandes az containerapp. Un fournisseur de ressources est la partie d’Azure qui crée un type de ressource. Un nouvel abonnement doit inscrire chaque fournisseur une fois. Cela peut prendre quelques minutes. Vérifiez avec az provider show -n Microsoft.App --query registrationState -o tsv : la réponse doit être Registered (inscrit). Dans l’abonnement de test, les trois étaient déjà inscrits.

L’extension affiche WARNING: The behavior of this command has been altered by the following extension: containerapp (avertissement : cette extension a modifié le comportement de la commande) pour chaque commande az containerapp. Cet avertissement est sans conséquence. Les sorties ci-dessous l’omettent.

Étape 1 : le groupe de ressources, avec des étiquettes

Section intitulée « Étape 1 : le groupe de ressources, avec des étiquettes »
Terminal
az group create --name $RG --location $LOCATION --tags purpose=practice course=C18 -o table

La sortie (réelle) :

Location Name
------------- ----------------------
canadacentral rg-ticket-api-practice

Les étiquettes indiquent pourquoi le groupe existe. Elles aident la personne qui consulte plus tard la liste de l’abonnement. Elles n’aident pas à rechercher ses ressources, comme le montre Vérifier et supprimer.

Terminal
az acr create --resource-group $RG --name $ACR --sku Basic -o table

La sortie (réelle) :

NAME RESOURCE GROUP LOCATION SKU LOGIN SERVER CREATION DATE ADMIN ENABLED
------------- ---------------------- ------------- ----- ------------------------ -------------------- ---------------
ticketapi4821 rg-ticket-api-practice canadacentral Basic ticketapi4821.azurecr.io 2026-10-07T16:10:57Z False

LOGIN SERVER (serveur de connexion) est la partie registre du nom de l’image. ADMIN ENABLED False (administrateur désactivé) : le compte administrateur du registre, qui utilise un mot de passe partagé, est désactivé. Gardez-le désactivé. L’application récupère les images avec son identité; elle n’a donc pas besoin de mot de passe.

Terminal
az acr login --name $ACR
docker buildx build --platform linux/amd64 -t $ACR.azurecr.io/ticket-api:1.1.0 --push .

Lancez la construction dans le dossier du projet : le . final est le contexte de construction. La sortie (réelle, abrégée) :

Login Succeeded
...
#13 exporting to image
#13 pushing layers 11.8s done
#13 pushing manifest for ticketapi4821.azurecr.io/ticket-api:1.1.0@sha256:cfd04194eb1be66f49a40575f75a0b2105a74e172f953df26a355291a5191afd 1.0s done
#13 DONE 14.7s

az acr login donne à Docker un jeton (token) pour ce registre. Le jeton expire après quelques heures. Si un envoi ultérieur indique unauthorized (non autorisé), relancez az acr login. La construction et l’envoi ont pris 27 secondes au total. Vérifiez l’étiquette et la plateforme :

Terminal
az acr repository show-tags -n $ACR --repository ticket-api -o table
docker buildx imagetools inspect $ACR.azurecr.io/ticket-api:1.1.0

La sortie (réelle, abrégée) :

Result
--------
1.1.0
Name: ticketapi4821.azurecr.io/ticket-api:1.1.0
MediaType: application/vnd.oci.image.index.v1+json
Digest: sha256:cfd04194eb1be66f49a40575f75a0b2105a74e172f953df26a355291a5191afd
Manifests:
Name: ticketapi4821.azurecr.io/ticket-api:1.1.0@sha256:b08764e2...
Platform: linux/amd64
Name: ticketapi4821.azurecr.io/ticket-api:1.1.0@sha256:eaa1e2c6...
Platform: unknown/unknown

linux/amd64 : le nuage peut l’exécuter.

Terminal
az identity create --resource-group $RG --name id-ticket-api -o table
IDENTITY_ID=$(az identity show -g $RG -n id-ticket-api --query id -o tsv)
PRINCIPAL_ID=$(az identity show -g $RG -n id-ticket-api --query principalId -o tsv)
REGISTRY_ID=$(az acr show -n $ACR --query id -o tsv)
az role assignment create --assignee-object-id $PRINCIPAL_ID --assignee-principal-type ServicePrincipal --role AcrPull --scope $REGISTRY_ID -o table

La sortie (réelle, colonnes abrégées) :

ClientId Location Name PrincipalId ResourceGroup
-------------- ------------- ------------- -------------- ----------------------
faf6b35b-... canadacentral id-ticket-api d2066809-... rg-ticket-api-practice
CreatedOn PrincipalType Scope
-------------------------------- ---------------- ---------------------------------------------------------------------------------------
2026-10-07T16:12:09.352851+00:00 ServicePrincipal /subscriptions/.../resourceGroups/rg-ticket-api-practice/providers/Microsoft.ContainerRegistry/registries/ticketapi4821

La portée est le registre, pas le groupe ni l’abonnement. L’identité peut récupérer des images de ce registre seulement, et ne peut rien faire d’autre. C’est le principe du moindre privilège, comme au module 4. --assignee-principal-type ServicePrincipal évite une erreur lorsque le service de rôles ne connaît pas encore la nouvelle identité.

Terminal
az containerapp env create --resource-group $RG --name cae-ticket-api --location $LOCATION -o table

La sortie (réelle, abrégée) :

WARNING: No Log Analytics workspace provided.
WARNING: Generating a Log Analytics workspace with name "workspace-rgticketapipracticeXXXX"
...
Container Apps environment created. To deploy a container app, use: az containerapp create --help
Location Name ResourceGroup
-------------- -------------- ----------------------
Canada Central cae-ticket-api rg-ticket-api-practice

L’environnement est l’espace partagé où s’exécutent les applications conteneurisées : un réseau et un endroit pour les journaux. Cela a pris environ 2 à 3 minutes. Lisez les deux avertissements : Azure a créé un espace de travail Log Analytics pour les journaux. Vous ne l’avez pas demandé, et il peut facturer les données de journaux. Vos caractères aléatoires diffèrent de XXXX. Ajoutez-le maintenant à votre inventaire :

Terminal
az resource list -g $RG -o table

La sortie (réelle) :

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

Quatre ressources, alors que vous en avez demandé trois. L’attribution de rôle de l’étape 4 n’apparaît pas dans la liste : az resource list n’affiche pas les attributions de rôles.

Terminal
KEY=$(python3 -c "import secrets; print(secrets.token_urlsafe(24))")
az containerapp create --resource-group $RG --name ticket-api --environment cae-ticket-api \
--image $ACR.azurecr.io/ticket-api:1.1.0 \
--user-assigned $IDENTITY_ID --registry-server $ACR.azurecr.io --registry-identity $IDENTITY_ID \
--ingress external --target-port 8000 \
--cpu 0.25 --memory 0.5Gi --min-replicas 0 --max-replicas 2 \
--secrets api-key="$KEY" \
--env-vars API_KEY=secretref:api-key REQUIRE_API_KEY=true SHOW_DOCS=false

L’historique de l’interpréteur de commandes garde $KEY, le nom de la variable, pas la clé. Les options, une par une :

Option Ce qu’elle fait
--environment cae-ticket-api Exécute l’application dans l’environnement de l’étape 5.
--image …/ticket-api:1.1.0 La version exacte à exécuter.
--user-assigned $IDENTITY_ID Donne à l’application l’identité de l’étape 4.
--registry-server, --registry-identity Récupère l’image du registre avec cette identité : aucun mot de passe.
--ingress external --target-port 8000 Donne à l’application une adresse HTTPS publique et envoie les requêtes au port 8000 du conteneur.
--cpu 0.25 --memory 0.5Gi La taille de chaque réplica. La plus petite taille.
--min-replicas 0 --max-replicas 2 Aucun réplica quand personne ne fait d’appel; au plus deux.
--secrets api-key="$KEY" Stocke la clé comme secret api-key de l’application.
--env-vars API_KEY=secretref:api-key … Définit API_KEY à partir du secret, et deux paramètres ordinaires.

La sortie (réelle) :

WARNING: User identity /subscriptions/.../userassignedidentities/id-ticket-api is already assigned to containerapp
Container app created. Access your app at https://ticket-api.nicewater-a307f95a.canadacentral.azurecontainerapps.io/

23 secondes. L’avertissement est sans conséquence : --user-assigned et --registry-identity désignent la même identité. Votre adresse a une partie centrale différente. Vérifiez l’état :

Terminal
az containerapp show -g $RG -n ticket-api --query "{rev:properties.latestRevisionName, status:properties.runningStatus, prov:properties.provisioningState}" -o table

La sortie (réelle) :

Rev Status Prov
------------------- -------- ---------
ticket-api--nz14cir Running Succeeded

La première révision est ticket-api--nz14cir. Succeeded (réussi) signifie qu’Azure a accepté les paramètres. Cela ne prouve pas que l’API répond : les deux prochaines leçons le vérifieront.

Le parcours simulé : les mêmes étapes sur votre ordinateur

Section intitulée « Le parcours simulé : les mêmes étapes sur votre ordinateur »

Le parcours simulé garde les idées, sans nécessiter de compte. Le tableau associe chaque élément réel à sa version locale :

Réel (Azure) Simulé (votre ordinateur)
Registre ticketapi4821.azurecr.io Le conteneur registry sur 127.0.0.1:5000
az acr login Inutile : seul votre ordinateur peut accéder à ce registre
L’image pour linux/amd64 La même construction, envoyée au registre local
Application conteneurisée ticket-api Le service api dans deploy/local-cloud.yaml
Le secret api-key, secretref: Un secret Compose provenant de secrets/api_key.txt, lu avec API_KEY_FILE
--cpu 0.25 --memory 0.5Gi cpus: 0.25 et mem_limit: 512m
Adresse HTTPS, accès entrant externe http://127.0.0.1:8080 : sans HTTPS
Révisions, mise à l’échelle, récupération depuis le registre Non simulées

La simulation exécute l’image que vous avez construite pour votre ordinateur, ticket-api:1.1.0. Elle ne peut pas exécuter rapidement l’image amd64 sur une puce Apple : l’émulation fonctionne, mais elle est lente. deploy/local-cloud.yaml se trouve dans le projet :

deploy/local-cloud.yaml
name: ticket-api-cloud-sim
services:
api:
image: ticket-api:1.1.0
ports:
- "127.0.0.1:8080:8000"
environment:
API_KEY_FILE: /run/secrets/api_key
REQUIRE_API_KEY: "true"
SHOW_DOCS: "false"
secrets:
- api_key
cpus: 0.25
mem_limit: 512m
restart: on-failure
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=2)"]
interval: 10s
timeout: 3s
retries: 3
start_period: 5s
secrets:
api_key:
file: ../secrets/api_key.txt

Le chemin du secret est ../secrets/api_key.txt, car Compose lit les chemins à partir du dossier du fichier Compose, deploy/. Configuration opérationnelle explique la vérification de l’état de santé et la politique de redémarrage. Démarrez le service depuis le dossier du projet :

Terminal (simulated route)
docker compose -f deploy/local-cloud.yaml up -d
docker compose -f deploy/local-cloud.yaml ps

La sortie (simulée) :

Network ticket-api-cloud-sim_default Creating
Network ticket-api-cloud-sim_default Created
Container ticket-api-cloud-sim-api-1 Creating
Container ticket-api-cloud-sim-api-1 Created
Container ticket-api-cloud-sim-api-1 Starting
Container ticket-api-cloud-sim-api-1 Started
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
ticket-api-cloud-sim-api-1 ticket-api:1.1.0 "fastapi run --host …" api 13 seconds ago Up 12 seconds (healthy) 127.0.0.1:8080->8000/tcp

-f indique le fichier Compose, car ce n’est pas compose.yaml. Le nom ticket-api-cloud-sim le distingue du projet de base de données du module 3. Les deux peuvent donc coexister. L’état passe de health: starting (vérification en cours) à healthy (en bon état) après la première vérification. Cela prend environ 10 secondes après le démarrage.

Exercice guidé : envoyer une version et la déployer

Section intitulée « Exercice guidé : envoyer une version et la déployer »

Suivez votre parcours. Travaillez dans le dossier du projet.

  1. Écrivez dans docs/cloud-design.md quel parcours vous utilisez.
  2. Parcours simulé : démarrez le registre local avec la commande docker run … registry:3.1.2 de Registre, dépôt et étiquette. Parcours réel : connectez-vous, puis suivez les étapes 1 et 2 du parcours réel.
  3. Construisez pour linux/amd64 avec --push, vers votre registre, avec l’étiquette 1.1.0.
  4. Vérifiez la plateforme avec docker buildx imagetools inspect. Résultat attendu : Platform: linux/amd64 (plateforme : linux/amd64), et une entrée unknown/unknown (inconnu/inconnu).
  5. Vérifiez la liste des étiquettes. Simulé : curl -s http://127.0.0.1:5000/v2/ticket-api/tags/list affiche "tags":["1.1.0"] (étiquettes : 1.1.0). Réel : az acr repository show-tags affiche 1.1.0.
  6. Parcours simulé : démarrez deploy/local-cloud.yaml et attendez (healthy) (en bon état). Parcours réel : suivez les étapes 4 à 6 et attendez Running (en cours d’exécution) et Succeeded (réussi).
  7. Notez le nom de l’image avec son empreinte et, pour le parcours réel, l’adresse et le nom de la première révision. Vous en aurez besoin dans les deux prochaines leçons.
Afficher le résultat attendu

Simulé : docker compose -f deploy/local-cloud.yaml ps affiche ticket-api-cloud-sim-api-1 avec Up … (healthy) (en cours d’exécution, en bon état) sur 127.0.0.1:8080->8000/tcp. Le registre local contient aussi ticket-api avec l’étiquette 1.1.0 pour linux/amd64.

Réel : az resource list -g rg-ticket-api-practice -o table liste cinq ressources : le registre, l’identité, l’espace de travail, l’environnement et l’application conteneurisée. az containerapp show indique Running et Succeeded. Vos notes ressemblent à ceci :

Image: ticketapi4821.azurecr.io/ticket-api:1.1.0@sha256:cfd04194eb1b...
Address: https://ticket-api.nicewater-a307f95a.canadacentral.azurecontainerapps.io
Revision: ticket-api--nz14cir

Construisez l’image à nouveau, mais omettez --platform, puis envoyez-la avec l’étiquette 1.1.0-native :

Terminal (simulated route)
docker buildx build -t 127.0.0.1:5000/ticket-api:1.1.0-native --push .

Avant d’exécuter imagetools inspect sur cette image, prédisez la plateforme. Répondez ensuite : sur quels ordinateurs cette étiquette peut-elle fonctionner? Azure Container Apps pourrait-il l’exécuter?

Afficher la réponse

Sans --platform, Buildx construit pour l’ordinateur qui effectue la construction. Sur une puce Apple, imagetools inspect affiche Platform: linux/arm64 (plateforme : linux/arm64). Sur un ordinateur Intel ou AMD, il affiche linux/amd64. Une image uniquement arm64 fonctionne sur les ordinateurs arm64, et un ordinateur amd64 ne peut pas la récupérer. docker pull --platform linux/amd64 donne no matching manifest for linux/amd64 (aucun manifeste correspondant pour linux/amd64). Azure Container Apps exécute uniquement amd64. Il ne pourrait donc pas exécuter cette étiquette construite sur un Mac avec une puce Apple. Écrivez toujours --platform linux/amd64 pour une construction destinée au nuage, même sur un ordinateur où c’est la valeur par défaut. La commande fait alors la même chose sur chaque ordinateur.

Erreur courante

La même étiquette, un contenu différent

Symptôme : Amira a envoyé 127.0.0.1:5000/ticket-api:1.1.0 deux fois : d’abord la construction arm64, puis la construction amd64. La liste des étiquettes affiche toujours seulement "tags":["1.1.0"], et aucun avertissement ne l’a prévenue. Mais l’empreinte est passée de sha256:1ba724a2… à sha256:204c4f72…. Un déploiement qui indique 1.1.0 exécute maintenant un contenu différent du déploiement d’hier portant le même nom.

Cause : une étiquette pointe vers une empreinte. Un envoi avec une étiquette existante déplace l’étiquette. La plupart des registres le permettent par défaut, y compris Azure Container Registry.

Solution :

  1. Donnez une nouvelle version à chaque changement : 1.1.1 pour une correction, 1.2.0 pour une nouvelle fonctionnalité. N’envoyez jamais une construction différente sous une version déjà déployée.
  2. Notez l’empreinte avec l’étiquette dans DEPLOY.md. L’empreinte prouve ce qui a été exécuté.
  3. Pour fixer la version le plus strictement possible, déployez par empreinte : ticketapi4821.azurecr.io/ticket-api@sha256:cfd04194…. Personne ne peut déplacer une empreinte.

Pour un vrai service d’IA : une image contient souvent un modèle entraîné. Si quelqu’un déplace l’étiquette 2.0.0 vers un nouveau modèle, les prédictions du service changent. Le registre des déploiements indique pourtant toujours 2.0.0. Personne ne peut alors expliquer pourquoi les résultats ont changé. Une version doit correspondre à un seul modèle et à un seul code.

Vérifiez votre compréhension

Nommez les trois parties de ticketapi4821.azurecr.io/ticket-api:1.1.0 et indiquez quelle partie un envoi peut changer sans avertissement.

Afficher la réponse

ticketapi4821.azurecr.io est le registre, le serveur qui stocke les images. ticket-api est le dépôt, qui regroupe les versions d’une image. 1.1.0 est l’étiquette, une version. Un envoi avec le même nom déplace l’étiquette vers un nouveau contenu sans avertissement. Seule l’empreinte (sha256:…) correspond toujours au même contenu. C’est pourquoi chaque changement reçoit un nouveau numéro de version et pourquoi DEPLOY.md consigne aussi l’empreinte.

Vérifiez votre compréhension

Prédisez : sur un Mac avec une puce Apple, vous exécutez docker build -t ticket-api:1.1.0 . et envoyez l'image au registre Azure. Azure Container Apps pourra-t-il l'exécuter? Que changez-vous?

Afficher la réponse

Non. Une construction ordinaire sur une puce Apple produit une image linux/arm64, et Azure Container Apps exécute uniquement linux/amd64. Construisez avec docker buildx build --platform linux/amd64 -t ticketapi4821.azurecr.io/ticket-api:1.1.0 --push .. Vérifiez ensuite avec docker buildx imagetools inspect que la plateforme est linux/amd64 avant de déployer.

Vérifiez votre compréhension

L'application conteneurisée a besoin d'images du registre. Pourquoi le cours lui donne-t-il une identité avec AcrPull sur le registre, plutôt que le compte administrateur du registre?

Afficher la réponse

Le compte administrateur utilise un seul mot de passe partagé qui donne tous les droits sur le registre. Quiconque le voit peut envoyer et supprimer des images. Il faut aussi le stocker et le changer manuellement. L’identité n’a pas besoin de mot de passe : Azure donne ses jetons à l’application. Son rôle, AcrPull, permet seulement de récupérer des images, et sa portée se limite à ce registre. Si quelqu’un détourne l’application, cette personne ne peut pas envoyer une image modifiée ni accéder à autre chose. C’est le principe du moindre privilège.

Récapitulatif

  • Un registre stocke des images. Un nom complet est <registry>/<repository>:<tag>. Une étiquette peut se déplacer; une empreinte ne le peut pas.
  • Donnez une nouvelle version à chaque changement, et ne déployez jamais uniquement latest.
  • Construisez pour le nuage avec --platform linux/amd64, et vérifiez avec docker buildx imagetools inspect avant de déployer.
  • Réel : un groupe de ressources avec des étiquettes, un registre (avec le compte administrateur désactivé), un environnement (qui crée un espace de travail Log Analytics), une identité avec AcrPull sur le registre et l’application conteneurisée avec une nouvelle clé comme secret.
  • Simulé : un registre local sur 127.0.0.1:5000, et deploy/local-cloud.yaml avec les mêmes paramètres et limites.

L’application fonctionne, mais la plateforme sait seulement que quelque chose écoute sur le port 8000. La prochaine leçon lui indique comment vérifier l’application et jusqu’où elle peut grandir. Elle indique aussi ce qui doit se passer lorsqu’une nouvelle version ne peut pas démarrer.

Leçon suivante : Configuration opérationnelle