Aller au contenu
English

Séparer la configuration

  • Leçon 7
  • 40 min
  • Module 3 : Gérer les environnements et les secrets
Leçon 7 sur 15 · CI/CD, tests et mises en production sûresSéparer la configuration

Ce que vous saurez faire

Exécutez l’image testée par CI dans deux endroits, la préproduction et la production, avec des paramètres différents. Ainsi, personne ne peut dire « ça fonctionnait en préproduction » à propos d’une autre construction.

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

Ce que vous devez savoir

Ce qu’il vous faut sur votre ordinateur

Exécuté avec GitHub Actions (exécuteurs ubuntu-24.04) dans le dépôt public Nextia-Intelligence/ticket-api-ci, Docker Desktop 4.81.0 (Engine 29.6.1, Compose 5.2.0) sous macOS (Apple silicon) et Azure CLI 2.88.0 dans canadacentral. Les étapes pour Windows et Linux ne sont pas testées.

Ce module propose deux parcours, comme dans le cours sur Docker. Choisissez-en un et utilisez-le dans les trois leçons. Vous pouvez aussi faire les deux.

Réel Simulé
Où la préproduction et la production s’exécutent Deux applications conteneurisées Azure, ticket-api-staging et ticket-api-production Deux projets Compose sur votre ordinateur, ticket-api-staging et ticket-api-production
Qui déploie Le flux de travail Deploy (déployer) dans GitHub Actions Vous, avec scripts/promote-local.sh
Coût Pratiquement nul, si vous supprimez les ressources le jour même Gratuit
Ce qu’il vous faut Un abonnement Azure Seulement Docker

Chaque sortie porte une étiquette. Les sorties réelles proviennent des exécutions réelles dans Nextia-Intelligence/ticket-api-ci. Les sorties simulées proviennent de Docker sur un Mac, le même jour. Les ressources Azure de l’exécution de test n’existent plus. Leurs adresses ne répondent donc plus.

L’exécution CI d’Amira sur main a construit une image et l’a testée. Son empreinte est sha256:4eb3db8d…. Le service de soutien veut essayer l’API avant que les clients y aient accès. L’équipe veut y activer /docs, pour que les testeurs puissent envoyer des requêtes dans le navigateur. La production doit masquer /docs.

Sam demande : « Est-ce que CI peut construire une deuxième image pour la préproduction, avec la documentation activée? » Amira dit non. Une deuxième construction est un deuxième artefact. Personne ne l’a testé. Personne ne peut prouver qu’il contient le même code et les mêmes paquets. Elle conserve donc un seul artefact (le résultat construit et testé du pipeline, ici l’image) et change seulement ses paramètres.

Un environnement est un endroit où l’application s’exécute, avec ses propres paramètres, secrets, accès et données. Ce cours en utilise deux :

  • La préproduction est une copie de la production qui sert aux vérifications. L’équipe y essaie une nouvelle version avant que les utilisateurs la voient.
  • La production est l’environnement que les utilisateurs et les autres systèmes appellent.

L’image en préproduction est une version candidate : une construction qui peut devenir la version publiée si toutes les vérifications réussissent. Quand elle arrive en production, rien ne change à l’intérieur. Seul l’environnement autour d’elle est différent.

Doit être identique dans chaque environnement Peut différer et doit rester à l’extérieur de l’image
Le code Les paramètres : SHOW_DOCS, CLASSIFIER_VERSION, le nom de l’application, l’adresse
Les paquets (requirements-run.txt) Les secrets : chaque environnement a sa propre clé d’API
L’image de base et le Dockerfile L’identité qui la déploie et ce que cette identité peut modifier
L’empreinte de l’image Le magasin de données : chaque environnement a sa propre base de données, ou aucune

La règle est simple : si une différence figure dans la colonne de droite, placez-la dans un paramètre. Si quelqu’un veut une différence dans la colonne de gauche, c’est une nouvelle version. Elle passe de nouveau par CI.

En haut, une image construite et testée une seule fois par CI : ghcr.io/usmanahmed99/ticket-api-ci@sha256:4eb3db8d..., qui porte les étiquettes sha-92fff66 et 1.1.0. Une flèche mène à l'environnement GitHub staging (règle de branche main, aucun réviseur, donc démarrage immédiat; variables APP_NAME, APP_URL, AZURE_CLIENT_ID et RESOURCE_GROUP; secret SMOKE_API_KEY contenant la clé de préproduction). Une deuxième flèche mène à l'environnement GitHub production (règle de branche main, un réviseur obligatoire qui doit approuver; les mêmes noms de variables avec d'autres valeurs; secret SMOKE_API_KEY contenant la clé de production). Depuis chaque environnement GitHub, une flèche indique : se connecter avec OIDC, sans mot de passe. Elle mène au groupe de ressources Azure rg-ticket-api-ci, avec l'environnement Container Apps cae-ticket-api-ci dans canadacentral. Là, chaque environnement a sa propre identité managée, id-deploy-staging ou id-deploy-production, avec un identifiant fédéré et le rôle Container Apps Contributor sur sa propre application seulement. Chaque identité met à jour sa propre application conteneurisée. ticket-api-staging exécute l'image à sha256:4eb3db8d avec SHOW_DOCS=true, donc /docs répond 200, son propre secret api-key et REQUIRE_API_KEY=true. ticket-api-production exécute la même empreinte avec SHOW_DOCS=false, donc /docs répond 404, son propre secret api-key et REQUIRE_API_KEY=true. Aucune application n'a de base de données : l'historique est désactivé.
Les limites des environnements du parcours réel. L'empreinte est identique dans les deux colonnes. Tout le reste d'une colonne appartient uniquement à cet environnement : ses paramètres, sa clé, son identité et sa permission.
Description textuelle du diagramme

L’empreinte en haut est la seule chose que les deux environnements partagent. Chaque colonne représente une limite. Les paramètres, la clé et l’identité de préproduction ne peuvent pas atteindre l’application de production, et inversement. La production a une règle de plus que la préproduction : une personne doit approuver avant le démarrage de sa tâche. Cette leçon crée les paramètres. Identifiants et accès crée les identités et les environnements GitHub. Promouvoir en préproduction déplace l’empreinte de gauche à droite.

Les paramètres doivent se trouver ailleurs que dans l’image. Chaque parcours a son propre endroit pour les conserver.

Réel : l’application conteneurisée conserve ses paramètres et son secret. Vous les définissez à la création de l’application, et le pipeline change seulement l’image. Un déploiement avec az containerapp update --image conserve tous les autres paramètres de l’application.

Simulé : le projet contient un fichier de paramètres par environnement et un fichier de clé ignoré par Git par environnement :

deploy/local/staging.env
# Settings of the local staging environment. No secrets here.
ENVIRONMENT=staging
PORT=8081
SHOW_DOCS=true
CLASSIFIER_VERSION=1.1
deploy/local/production.env
# Settings of the local production environment. No secrets here.
ENVIRONMENT=production
PORT=8082
SHOW_DOCS=false
CLASSIFIER_VERSION=1.0

Les fichiers de paramètres sont dans Git : ils ne contiennent aucun secret, et un réviseur doit voir chaque modification. Les clés sont dans secrets/staging_api_key.txt et secrets/production_api_key.txt, et secrets/ figure dans .gitignore. Le mot de passe de la base de données est dans .env, que Git ignore aussi.

CLASSIFIER_VERSION est là pour le module 4. La version 1.1.0 de l’API ne le lit pas encore. Vous voyez ce que cela signifie dans l’exemple détaillé.

Un fichier Compose décrit un seul environnement. Le nom de l’environnement vient du fichier de paramètres :

deploy/local/compose.yaml
# One environment (staging or production) on your computer: the API and its
# own database. The image is given by digest, so every
# environment runs exactly the same build. Start it with scripts/promote-local.sh.
name: ticket-api-${ENVIRONMENT:?Set ENVIRONMENT}
services:
api:
image: ${IMAGE:?Set IMAGE to the image name with its digest}
ports:
- "127.0.0.1:${PORT:?Set PORT}:8000"
environment:
API_KEY_FILE: /run/secrets/api_key
REQUIRE_API_KEY: "true"
DATABASE_URL: postgresql://tickets:${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}@db:5432/tickets
SHOW_DOCS: ${SHOW_DOCS:-false}
CLASSIFIER_VERSION: ${CLASSIFIER_VERSION:-1.0}
secrets:
- api_key
healthcheck:
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=2)"]
interval: 5s
timeout: 3s
retries: 5
depends_on:
db:
condition: service_healthy
db:
image: postgres:18.6-trixie
environment:
POSTGRES_USER: tickets
POSTGRES_DB: tickets
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- pgdata:/var/lib/postgresql
healthcheck:
test: ["CMD", "pg_isready", "-U", "tickets", "-d", "tickets"]
interval: 2s
timeout: 3s
retries: 15
secrets:
api_key:
file: ../../secrets/${ENVIRONMENT}_api_key.txt
volumes:
pgdata:

Quatre lignes assurent la séparation :

Ligne Ce qu’elle fait
name: ticket-api-${ENVIRONMENT…} Chaque environnement est un projet Compose distinct. Les noms de ses conteneurs, de son réseau et de ses volumes commencent par ticket-api-staging ou ticket-api-production.
image: ${IMAGE…} L’image vient de l’extérieur, désignée par son empreinte. Le fichier n’a pas sa propre image. Il ne peut donc pas exécuter une autre construction par accident.
file: ../../secrets/${ENVIRONMENT}_api_key.txt Chaque environnement lit sa propre clé.
pgdata: Chaque projet obtient son propre volume. Chaque environnement a donc sa propre base de données.

Avec :?, une valeur manquante devient une erreur, pas une chaîne vide. Si vous oubliez le fichier de paramètres, Compose s’arrête avec Set ENVIRONMENT (définir ENVIRONMENT), et rien ne démarre.

C’est le fichier de la demande de tirage nº 1 du dépôt de référence. Il a une lacune sur Apple silicon, que Promouvoir en préproduction montre et corrige.

La préproduction et la production ne partagent jamais une base de données. Les billets de soutien d’un testeur en préproduction ne doivent pas apparaître dans l’historique de production. Une migration qui échoue en préproduction ne doit pas toucher les lignes de production. Pour cette raison, dans le module 4, chaque environnement exécute les migrations sur sa propre base de données.

  • Simulé : chaque projet Compose a son propre conteneur PostgreSQL et son propre volume, ticket-api-staging_pgdata et ticket-api-production_pgdata.
  • Réel : le cours n’utilise aucune base de données dans le nuage, pour garder le coût à zéro. Les deux applications s’exécutent sans DATABASE_URL. L’historique est donc désactivé, et /v1/history répond 503 comme prévu. Si vous ajoutez une base de données plus tard, donnez à chaque environnement son propre serveur ou sa propre base de données. Chacun doit aussi avoir son propre mot de passe.
En haut, la même image que dans le nuage, récupérée de GHCR par son empreinte : ghcr.io/usmanahmed99/ticket-api-ci@sha256:4eb3db8d.... Elle mène à deux commandes. scripts/promote-local.sh staging, que vous exécutez en premier, lit deploy/local/staging.env (PORT=8081, SHOW_DOCS=true, CLASSIFIER_VERSION=1.1), le secret secrets/staging_api_key.txt ignoré par Git et le mot de passe dans .env, aussi ignoré par Git. scripts/promote-local.sh production, que vous exécutez après la réussite de la préproduction en guise d'approbation, lit deploy/local/production.env (PORT=8082, SHOW_DOCS=false, CLASSIFIER_VERSION=1.0), secrets/production_api_key.txt et .env. Chaque commande exécute docker compose up -d --wait, puis smoke.sh, et crée un projet Compose. Le projet ticket-api-staging contient le conteneur api avec la même empreinte sur 127.0.0.1:8081, où /docs répond 200, avec la plateforme linux/amd64, émulée sur arm64, et la clé à /run/secrets/api_key; un conteneur db, postgres:18.6-trixie, avec sa propre base de données; et le volume ticket-api-staging_pgdata, que stop-local.sh --volumes supprime. Le projet ticket-api-production contient les mêmes éléments sur 127.0.0.1:8082, où /docs répond 404, avec le volume ticket-api-production_pgdata. Les deux projets ne partagent aucun conteneur, réseau, volume ou clé.
Le parcours local : le même schéma que dans le nuage, avec deux projets Compose. Votre propre commande pour la production remplace l'approbation du réviseur.
Description textuelle du diagramme

Le parcours simulé conserve toutes les limites possibles sur un seul ordinateur. Chaque environnement a son propre projet, port, fichier de paramètres, clé et base de données. L’image a la même empreinte que dans le nuage. Ce qu’il ne peut pas simuler : les identités, l’adresse HTTPS et l’approbation par une autre personne. Dans la simulation, vous êtes le réviseur, et votre deuxième commande est l’approbation.

Exemple détaillé (réel) : deux applications, une image

Section intitulée « Exemple détaillé (réel) : deux applications, une image »

Amira crée le groupe de ressources et l’environnement, comme dans le cours sur Docker, avec les noms du cours :

Terminal (live route)
az group create --name rg-ticket-api-ci --location canadacentral --tags purpose=practice course=C19 -o table
az containerapp env create --resource-group rg-ticket-api-ci --name cae-ticket-api-ci --location canadacentral -o table

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

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

Ensuite, elle crée les deux applications à partir de la même image. Seuls --name, la clé et SHOW_DOCS diffèrent. L’image est désignée par l’empreinte de la première exécution CI réussie sur main (commit, modification enregistrée, c862935). Il n’y a pas de registre dans Azure : l’image est dans GitHub Container Registry. Le paquet est public, donc Azure le récupère sans mot de passe.

Terminal (live route)
IMAGE=ghcr.io/usmanahmed99/ticket-api-ci@sha256:6c9bb4ed7c7cffc27f0c5489ba867d4d5db16def1c59c8bcbaeb3d26c45ce2e1
STAGING_KEY=$(python3 -c "import secrets; print(secrets.token_urlsafe(24))")
az containerapp create --resource-group rg-ticket-api-ci --name ticket-api-staging --environment cae-ticket-api-ci \
--image "$IMAGE" --ingress external --target-port 8000 \
--cpu 0.25 --memory 0.5Gi --min-replicas 0 --max-replicas 2 \
--secrets api-key="$STAGING_KEY" \
--env-vars API_KEY=secretref:api-key REQUIRE_API_KEY=true SHOW_DOCS=true

Utilisez votre propre nom d’image et votre propre empreinte. La sortie (réelle, abrégée) :

Container app created. Access your app at https://ticket-api-staging.blackhill-8c0e6b69.canadacentral.azurecontainerapps.io/
Fqdn Revision
------------------------------------------------------------------------- ---------------------------
ticket-api-staging.blackhill-8c0e6b69.canadacentral.azurecontainerapps.io ticket-api-staging--cbaey1q

Pour la production, elle exécute la même commande avec trois changements : --name ticket-api-production, une nouvelle clé dans PRODUCTION_KEY et SHOW_DOCS=false. La sortie (réelle, abrégée) :

Container app created. Access your app at https://ticket-api-production.blackhill-8c0e6b69.canadacentral.azurecontainerapps.io/
Fqdn Revision
---------------------------------------------------------------------------- ------------------------------
ticket-api-production.blackhill-8c0e6b69.canadacentral.azurecontainerapps.io ticket-api-production--hx6e7q9

Conservez les deux clés dans le terminal (ou dans un gestionnaire de mots de passe) jusqu’à Identifiants et accès. Là, chaque clé va dans son environnement GitHub sous le nom SMOKE_API_KEY. Ainsi, le test de bon fonctionnement du pipeline peut appeler l’application.

La preuve est arrivée plus tard dans la journée. Après la mise en production de la version 1.1.0, les deux applications exécutaient l’image ghcr.io/usmanahmed99/ticket-api-ci@sha256:4eb3db8d…. Le journal de déploiement de l’exécution 37665743749 montre la même ligne d’image dans les deux tâches (réel) :

staging / Deploy to staging | IMAGE: ghcr.io/usmanahmed99/ticket-api-ci@sha256:4eb3db8d4ea249fb9b44b27d96deb68aba6da3e3fbc9cf32311a9cbadf4d857a
production / Deploy to production | IMAGE: ghcr.io/usmanahmed99/ticket-api-ci@sha256:4eb3db8d4ea249fb9b44b27d96deb68aba6da3e3fbc9cf32311a9cbadf4d857a

Et /docs répondait 200 en préproduction et 404 en production (réel). Les mêmes octets, un comportement différent, à cause d’un seul paramètre.

Exemple détaillé (simulé) : comparer les deux environnements

Section intitulée « Exemple détaillé (simulé) : comparer les deux environnements »

Avant de démarrer quoi que ce soit, Amira demande à Compose ce que chaque environnement exécuterait. docker compose config lit le fichier Compose et les fichiers de paramètres, puis affiche le résultat avec chaque variable remplacée. Il ne démarre rien.

Terminal (simulated route)
export IMAGE=ghcr.io/usmanahmed99/ticket-api-ci@sha256:4eb3db8d4ea249fb9b44b27d96deb68aba6da3e3fbc9cf32311a9cbadf4d857a
docker compose -f deploy/local/compose.yaml --env-file deploy/local/staging.env --env-file .env config > reports/staging-config.yaml
docker compose -f deploy/local/compose.yaml --env-file deploy/local/production.env --env-file .env config > reports/production-config.yaml
diff reports/staging-config.yaml reports/production-config.yaml

Faites d’abord une prédiction : quelles lignes diff affichera-t-il? La ligne image: en fera-t-elle partie?

La sortie (simulée; chemins des fichiers de secrets abrégés) :

1c1
< name: ticket-api-staging
---
> name: ticket-api-production
10c10
< CLASSIFIER_VERSION: "1.1"
---
> CLASSIFIER_VERSION: "1.0"
13c13
< SHOW_DOCS: "true"
---
> SHOW_DOCS: "false"
30c30
< published: "8081"
---
> published: "8082"
61c61
< name: ticket-api-staging_default
---
> name: ticket-api-production_default
64c64
< name: ticket-api-staging_pgdata
---
> name: ticket-api-production_pgdata
67,68c67,68
< name: ticket-api-staging_api_key
< file: .../ticket-api-ci/secrets/staging_api_key.txt
---
> name: ticket-api-production_api_key
> file: .../ticket-api-ci/secrets/production_api_key.txt

Chaque différence figure dans la colonne de droite du tableau : le nom, deux paramètres, le port, le réseau, le volume et la clé. La ligne image: n’est pas dans la liste, car elle est identique dans les deux fichiers :

image: ghcr.io/usmanahmed99/ticket-api-ci@sha256:4eb3db8d4ea249fb9b44b27d96deb68aba6da3e3fbc9cf32311a9cbadf4d857a

Vous pouvez répéter cette vérification avant chaque déploiement : comparez ce qui s’exécutera et cherchez une différence dans la colonne de gauche.

Plus tard, dans Promouvoir en préproduction, Amira démarre les deux projets et les appelle. Deux résultats comptent ici (simulé) :

  • /docs répondait 200 sur le port 8081 et 404 sur le port 8082, comme dans le nuage.
  • POST /v1/classify avec « Package never arrived » (le colis n’est jamais arrivé) donnait {"category":"other","priority":3,"confidence":0.2,"model_version":"keywords-1.0"} dans les deux environnements, même si la préproduction a CLASSIFIER_VERSION=1.1.

Le deuxième résultat n’est pas une erreur de configuration. La version 1.1.0 du code ne lit pas CLASSIFIER_VERSION. Un paramètre que le code ignore ne change rien, et aucune erreur ne vous le signale. C’est pourquoi vous vérifiez un paramètre par son effet (ici /docs), et non par sa présence dans un fichier. Le module 4 ajoute le code qui lit ce paramètre. Les mêmes fichiers donnent alors keywords-1.1 en préproduction.

Exercice guidé : les fichiers d’environnement local

Section intitulée « Exercice guidé : les fichiers d’environnement local »

Travaillez dans le dossier de votre projet, sur une nouvelle branche : git switch -c feature/deploy. Vous fusionnerez cette branche dans main par une demande de tirage (pull request) dans Promouvoir en préproduction : exercice guidé : promouvoir votre propre empreinte.

  1. Créez le dossier deploy/local, puis écrivez deploy/local/compose.yaml, staging.env et production.env comme ci-dessus.

  2. Si .env n’existe pas, copiez .env.example dans .env, puis changez le mot de passe qu’il contient.

  3. Créez les deux clés. Chacune est nouvelle et réservée à son environnement :

    Terminal
    mkdir -p secrets reports
    python3 -c "import secrets; print(secrets.token_urlsafe(24), end='')" > secrets/staging_api_key.txt
    python3 -c "import secrets; print(secrets.token_urlsafe(24), end='')" > secrets/production_api_key.txt
  4. Vérifiez que Git ne voit pas les clés : git status --short. Résultat attendu : Git affiche deploy/, mais pas secrets/, reports/ ni .env.

  5. Réglez IMAGE sur votre propre image avec l’empreinte de build-info.json, comme dans l’exemple détaillé.

  6. Écrivez les deux configurations dans reports/, puis comparez-les avec diff (ou Compare-Object).

  7. Trouvez la ligne image: dans les deux fichiers. Résultat attendu : la même empreinte, caractère pour caractère.

  8. Créez un commit (enregistrement des changements) des trois fichiers dans deploy/local/ : git add deploy/local et git commit -m "Local staging and production environments".

Afficher le résultat attendu

diff indique seulement le nom du projet, CLASSIFIER_VERSION, SHOW_DOCS, le port (8081 et 8082), le réseau, le volume et le fichier de clé, comme dans l’exemple détaillé. Les deux fichiers ont la même ligne image: avec votre empreinte. git status --short affiche ?? deploy/ avant le commit, et rien sur secrets/, reports/ ou .env. Après l’étape 8, git log --oneline -1 affiche votre commit sur feature/deploy.

Le responsable du centre de soutien demande un environnement de formation, training, où le nouveau personnel peut essayer l’API avec la documentation activée. Écrivez deploy/local/training.env avec PORT=8083. Ne changez pas compose.yaml.

Avant d’exécuter docker compose config avec le nouveau fichier, prédisez :

  1. le nom du projet,
  2. le nom de son volume,
  3. le fichier de clé dont il a besoin.

Exécutez ensuite la commande et vérifiez vos réponses. Que devez-vous créer d’autre avant que cet environnement puisse démarrer?

Afficher la réponse

ENVIRONMENT=training donne le projet ticket-api-training, le volume ticket-api-training_pgdata et le fichier de clé secrets/training_api_key.txt. Un test avec un troisième fichier a affiché les noms correspondants et published: "8083". docker compose config ne vérifie pas que le fichier de clé existe. Vous devez donc créer vous-même secrets/training_api_key.txt avec une nouvelle clé. Le nouvel environnement n’a exigé aucun changement au code, à l’image ou au fichier Compose : seulement un fichier de paramètres et une clé. C’est le signe d’une bonne séparation de la configuration.

Erreur courante

L'étiquette qui a lancé une nouvelle construction

Symptôme : la première version de ci.yml dans le dépôt de référence s’exécutait aussi pour les étiquettes de version. Pousser l’étiquette v1.1.0 relançait tout le flux CI, et la tâche d’image construisait une nouvelle image pour l’étiquette. La préproduction avait vérifié l’image de l’exécution sur main, pas celle-ci. Rien dans le pipeline ne pouvait prouver que les deux constructions étaient identiques. Une image de base ou un paquet peut changer entre deux constructions.

Cause : le pipeline traitait « faire une mise en production » comme « construire ». C’est l’erreur la plus courante dans les pipelines de livraison : un nouvel artefact pour chaque environnement ou chaque étape.

Correction : une étiquette ne doit pas lancer de construction. La demande de tirage no 2 a supprimé le déclencheur d’étiquette de ci.yml :

.github/workflows/ci.yml (pull request #2, part)
push:
branches: [main, "hotfix/**"]
tags: ["v*"]

et ajouté release.yml, qui attribue l’étiquette de version à l’image existante. L’exécution de test a mesuré le résultat : les étiquettes 1.1.0 et sha-92fff66 ont la même empreinte, sha256:4eb3db8d…. Promouvoir en préproduction présente le flux de travail.

Pour un vrai service d’IA : une image contient souvent un fichier de modèle ou en télécharge un pendant la construction. Une deuxième construction peut récupérer un modèle différent. Ses prédictions diffèrent alors de celles que la préproduction a vérifiées. Promouvez un seul artefact par son empreinte, et les prédictions en production seront celles que vous avez testées.

Vérifiez votre compréhension

Sam veut /docs en préproduction et demande au pipeline CI de construire une image de préproduction avec SHOW_DOCS réglé sur true à l'intérieur. Que répondez-vous, et que faites-vous plutôt?

Afficher la réponse

Une deuxième image est un deuxième artefact. Personne ne l’a testé, et personne ne peut prouver qu’il contient le même code et les mêmes paquets. Gardez une seule image et placez la différence dans un paramètre à l’extérieur de l’image : SHOW_DOCS=true en préproduction (la variable d’environnement de l’application conteneurisée, ou deploy/local/staging.env) et false en production. Les deux environnements exécutent alors la même empreinte. La vérification en préproduction porte donc sur la construction destinée à la production.

Vérifiez votre compréhension

Prédisez : vous réglez CLASSIFIER_VERSION=1.1 dans staging.env et démarrez la version 1.1.0 de l'API. Quelle valeur de model_version la préproduction indique-t-elle, et pourquoi?

Afficher la réponse

keywords-1.0, comme en production. La version 1.1.0 du code ne lit pas CLASSIFIER_VERSION. Le paramètre n’a donc aucun effet, et rien ne signale d’erreur. Vérifiez un paramètre par son effet, par exemple /docs (200 en préproduction, 404 en production), pas par sa présence dans un fichier. Ce paramètre fonctionne à partir de la version qui le lit (module 4).

Vérifiez votre compréhension

Nommez deux éléments qui doivent être identiques en préproduction et en production, et deux qui doivent différer. Pourquoi le stockage des données doit-il différer?

Afficher la réponse

Identiques : l’empreinte de l’image et le code (ainsi que les paquets et le Dockerfile, qui sont dans l’image). Différents : les paramètres (comme SHOW_DOCS) et les secrets (la clé propre à chaque environnement), ainsi que l’identité et le stockage des données. Le stockage des données doit différer pour que les données de test de préproduction n’apparaissent jamais en production. De plus, une migration ou une erreur en préproduction ne peut alors pas modifier les enregistrements de production.

Récapitulatif

  • Un artefact, plusieurs environnements : la préproduction et la production exécutent la même empreinte d’image. Seuls les paramètres, les secrets, les identités et le stockage des données diffèrent.
  • En service : chaque application conteneurisée contient ses propres paramètres et son secret. En simulation : deploy/local/<environment>.env et secrets/<environment>_api_key.txt, que Git ignore.
  • Un seul fichier Compose avec name: ticket-api-${ENVIRONMENT} donne à chaque environnement son propre projet, port, clé et base de données.
  • docker compose config et diff montrent les différences avant toute exécution. La ligne image: doit être identique.
  • Vérifiez un paramètre par son effet. La version 1.1.0 ignore CLASSIFIER_VERSION.
  • Une mise en production ne doit pas relancer la construction : une étiquette qui déclenche une deuxième construction crée un artefact que personne n’a testé.

Les applications existent, mais personne ne peut encore y déployer sans votre propre connexion à Azure. La prochaine leçon donne à chaque environnement une identité sans mot de passe qui peut modifier seulement sa propre application.

Leçon suivante : Identifiants et accès