WIKI
SUPPORT-IA Support N2/N3 · plateformes IA Azure

05 · GitOps de bout en bout : Azure DevOps, ACR Premium, Argo CD

23 min de lecture Mis à jour le 23 octobre 2026
Sur cette page

Version : 1.0 · Date : 2026-10-23 · Parcours SUPPORT-IA (support N2/N3 de chatbots sur Azure)

En une phrase : le pipeline Azure DevOps construit l'image et la pousse dans un ACR Premium privé, puis écrit le nouveau tag dans le dépôt GitOps ; Argo CD, dans le cluster, voit ce commit et synchronise ; « rien ne change » veut donc toujours dire qu'un des huit maillons de cette chaîne est cassé, et Synced ne veut pas dire que l'application marche.

Du commit au pod : la chaîne Azure DevOps → ACR → Git → Argo CD → AKS

Le choix « push ou pull », Flux comparé à Argo CD et l'organisation de l'IaC sont traités côté architecture dans AKS/05-exploitation-gitops ; la chaîne de confiance des images (signature, admission) dans AKS/03-identite-securite. Ici, on suit un changement de bout en bout et on apprend à trouver le maillon qui casse. Les objets Kubernetes et les commandes kubectl sont dans 04-aks-pour-le-support.

Ce que tu dois savoir expliquer en entretien#

Question type Section
« Décris votre chaîne de déploiement, du commit au pod » 1
« Comment le pipeline s'authentifie-t-il à ACR ? Pourquoi un agent self-hosted ? » 2
« Pourquoi ACR Premium ? Que change le Private Endpoint ? » 3
« Synced, OutOfSync, Healthy, Degraded : que veulent-ils dire ? Self-heal, prune ? » 5
« J'ai poussé dans Git et rien ne change » / « le déploiement ne crée pas de nouveaux pods » 6, 7

1. La chaîne en huit maillons#

# Maillon Preuve que c'est passé Où regarder
① Merge sur la branche suivie par la CI Commit sur main du dépôt applicatif Azure Repos, historique
② Run du pipeline sur un agent Run démarré, job attribué à un agent Azure Pipelines : run, logs du job, pool d'agents
③ Build et push de l'image dans ACR Tag chat-api:4812 présent dans le registre Logs de Docker@2, az acr repository show-tags
④ Écriture du tag dans le dépôt GitOps Commit « chat-api 4812 » dans le bon fichier, la bonne branche Historique du dépôt GitOps
⑤ Argo CD détecte le commit Révision de l'Application = ce commit argocd app get, interface Argo CD
⑥ Sync appliquée Sync status Synced, opération Succeeded argocd app get, argocd app history
⑦ Rollout Kubernetes Nouveau ReplicaSet, pods recréés kubectl rollout status, kubectl get rs
⑧ Pull de l'image par le kubelet Pods Running, Ready, image au bon tag kubectl describe pod, Events

Phrase d'entretien : « Le pipeline ne parle jamais au cluster. Le seul contrat entre CI et CD, c'est le tag écrit dans le dépôt GitOps. Quand rien ne change, je remonte la chaîne : l'image existe-t-elle dans ACR ? le tag est-il dans Git ? Argo CD a-t-il vu ce commit ? la sync a-t-elle réussi ? le rollout a-t-il créé des pods ? »


2. Le pipeline Azure DevOps#

2.1 Les service connections#

Service connection Utilisée par Authentification recommandée Droits côté Azure
Docker Registry → type Azure Container Registry Docker@2 (login, buildAndPush) Workload Identity federation (aucun secret) ; service principal possible AcrPush sur le registre
Azure Resource Manager AzureCLI@2, AzureWebAppContainer@1, kubelogin -l azurepipelines Workload Identity federation, avec app registration ou managed identity Selon les commandes (ex. az acr build → droits sur le registre)

Docker@2 n'accepte que des service connections Docker Registry, pas Azure Resource Manager.

Erreurs d'authentification fréquentes d'une service connection en Workload Identity federation :

Message Cause Correction
AADSTS70021 … Assertion Issuer … Subject: sc://<org>/<projet>/<connexion> Issuer ou subject du federated credential ne correspond plus (organisation, projet ou connexion renommés) Comparer avec l'Issuer et le Subject identifier affichés dans la service connection, corriger le credential
AADSTS700211 / AADSTS700213 Issuer / subject inconnus Idem
AADSTS700016: Application … wasn't found Identité supprimée ou mauvais client ID Recréer ou corriger l'identité
AADSTS7000215: Invalid client secret Ancienne connexion à secret expirée Convertir en Workload Identity federation
AADSTS700223 Workload identity federation restreinte dans le tenant Utiliser une managed identity pour la fédération

2.2 Un pipeline type : build, push, mise à jour du dépôt GitOps#

# azure-pipelines.yml du dépôt applicatif chat-api
trigger:
  branches: { include: [ main ] }

variables:
  imageRepository: chat-api
  acrServiceConnection: sc-acr-chat-prd          # Docker Registry, Workload Identity federation
  # Tag unique : numéro de build (traçable vers le run) ; le SHA court est ajouté en second tag
  imageTag: $(Build.BuildId)

pool: pool-mdp-chat                              # Managed DevOps Pools ou agents self-hosted DANS le VNet (ACR privé)

stages:
- stage: Build
  displayName: Build et push de l'image
  jobs:
  - job: docker
    displayName: Docker build and push
    steps:
    - task: Docker@2
      displayName: Build et push vers ACR
      inputs:
        command: buildAndPush
        containerRegistry: $(acrServiceConnection)
        repository: $(imageRepository)
        Dockerfile: src/Dockerfile
        tags: |
          $(imageTag)
          sha-$(Build.SourceVersion)

- stage: UpdateGitOps
  displayName: Écriture du tag dans le dépôt GitOps
  dependsOn: Build
  jobs:
  - job: bump
    displayName: Mise à jour de values-prd.yaml
    steps:
    - checkout: gitops                            # dépôt déclaré dans resources.repositories
      persistCredentials: true                    # le script peut pousser avec le jeton du pipeline
    - script: |
        set -euo pipefail
        sed -i "s/^\(\s*tag:\s*\).*/\1\"$(imageTag)\"/" apps/chat-api/values-prd.yaml
        git config user.email "[email protected]"
        git config user.name "Azure Pipelines"
        git commit -am "chat-api $(imageTag) [skip ci]"
        git push origin HEAD:main
      displayName: Commit du nouveau tag

resources:
  repositories:
  - repository: gitops
    type: git
    name: Chatbot/gitops-chatbot                 # projet/dépôt Azure Repos

Points à connaître :

  • Docker@2 a pour tag par défaut $(Build.BuildId) ; avec buildAndPush, l'input arguments est ignoré (séparer build et push pour passer des --build-arg). La tâche ajoute des labels de traçabilité (com.azure.dev.image.build.sourceversion…).
  • Pour pousser dans un dépôt Azure Repos, l'identité <projet> Build Service (<organisation>) doit avoir Contribute sur le dépôt GitOps (par défaut elle ne peut que lire), et le checkout doit avoir persistCredentials: true. Sinon : refus de permission au git push.
  • [skip ci] dans le message de commit évite de déclencher la CI du dépôt GitOps.
  • KubernetesManifest@1 ou HelmDeploy@1 déploieraient directement dans le cluster (modèle push) : à éviter quand Argo CD pilote le cluster, sinon deux sources de vérité se battent.

2.3 Stratégie de tag#

Tag Avantage Risque en production Verdict
latest (ou tout tag réutilisé) Simple Template de pod inchangé → aucun rollout ; nodes avec des versions différentes ; retour arrière impossible À proscrire pour déployer
$(Build.BuildId) Unique, relie l'image au run et à ses logs Peu lisible Recommandé
SHA du commit Relie au code Même SHA si on reconstruit pour une nouvelle image de base Bon en second tag
Version sémantique 1.4.2 Lisible Doit rester unique (jamais réécrite) Bon pour les releases
Digest @sha256:… Immuable par construction Illisible Pour verrouiller

Microsoft recommande les tags uniques pour les déploiements (et les tags stables uniquement pour les images de base), ainsi que le verrouillage des tags déployés (az acr repository update --write-enabled false).

2.4 Où tourne le build quand ACR est privé#

Option Fonctionne avec ACR sans accès public ? À savoir
Microsoft-hosted agent Non (il sort par Internet) Utile seulement si le registre accepte des IP publiques
Agent self-hosted (VM, VMSS) dans le VNet Oui À maintenir (OS, Docker, mises à jour)
Managed DevOps Pools avec injection dans un subnet Oui Subnet délégué à Microsoft.DevOpsInfrastructure/pools, même région que le pool ; ne pas utiliser la plage 172.17.0.0/16
az acr build (ACR Tasks) Seulement avec un dedicated agent pool dans le VNet (préversion, régions limitées) ou des règles réseau explicites Depuis le 1er juin 2025, les tasks en managed identity système ne contournent plus le pare-feu sans networkRuleBypassAllowedForTasks

3. ACR Premium privé#

ACR Premium privé : qui pousse, qui tire, et par où

3.1 Pourquoi Premium#

Besoin Disponible en Commentaire
Private Link (private endpoints) Premium La raison principale dans un SI fermé
Geo-replication Premium Pull dans la région, résilience régionale ; chaque réplica ajoute ses enregistrements DNS
Customer-managed keys Premium À configurer à la création du registre
Retention policy des manifestes non tagués Premium, préversion 0 à 365 jours (7 par défaut) ; ne couvre pas les manifestes OCI
Dedicated agent pool pour ACR Tasks Premium, préversion Seule façon simple de faire az acr build sur un registre fermé
Débit et opérations concurrentes Plus élevés en Premium Utile quand des dizaines de nodes tirent en même temps
Zone redundancy Tous les tiers désormais, dans les régions qui ont des zones La propriété zoneRedundancy affichée peut être trompeuse (« Disabled »)
Docker Content Trust Premium, en retrait Impossible à activer sur un nouveau registre depuis le 31/05/2026, suppression le 31/03/2028 : utiliser Notation

3.2 Le Private Endpoint et son DNS#

Un Private Endpoint ACR porte deux noms à résoudre en IP privée : le registre (acrchatprd.azurecr.io) et le data endpoint régional (acrchatprd.<région>.data.azurecr.io), d'où viennent les couches. Zone privée : privatelink.azurecr.io, liée à chaque VNet client (agents, AKS, intégration de la Web App). Oublier le data endpoint donne une authentification qui réussit puis des couches qui échouent.

# Lecture seule : état du registre, réseau, contenu
az acr show -n acrchatprd --query "{sku:sku.name, public:publicNetworkAccess, bypass:networkRuleBypassOptions}" -o table
az acr private-endpoint-connection list -r acrchatprd -o table
az acr repository show-tags -n acrchatprd --repository chat-api --orderby time_desc --top 5 -o table
az acr manifest list-metadata -r acrchatprd -n chat-api -o table
az acr check-health -n acrchatprd --ignore-errors --yes       # depuis une machine du VNet
nslookup acrchatprd.azurecr.io                                 # doit répondre une IP privée

Piège : une fois l'accès public coupé, az acr build et les ACR Tasks échouent (denied: client with IP … is not allowed access ou 403) tant qu'on n'utilise pas un dedicated agent pool ou une règle explicite. Ce n'est pas une panne du registre.


4. Comment le nouveau tag arrive dans le cluster#

Méthode Principe Pour Contre
Le pipeline écrit le tag dans le dépôt GitOps (section 2.2) Commit sur values-prd.yaml ou kustomization.yaml Traçable, revue possible par pull request, retour arrière par git revert Une étape de plus dans le pipeline
Argo CD Image Updater Surveille le registre et met à jour les Applications (paramètres Argo CD ou write-back Git) selon une stratégie (semver, newest-build, digest…) Automatique Projet qui se déclare « en développement actif » ; seulement Helm, Kustomize ou plugin ; secrets de registre dans le cluster
kubectl set image ou HelmDeploy@1 depuis le pipeline Push direct Rapide Contourne Git : Argo CD le défait (selfHeal) ou affiche OutOfSync

Deux formats fréquents dans le dépôt GitOps :

# Helm : apps/chat-api/values-prd.yaml
image:
  repository: acrchatprd.azurecr.io/chat-api
  tag: "4812"
---
# Kustomize : apps/chat-api/overlays/prd/kustomization.yaml
images:
- name: chat-api
  newName: acrchatprd.azurecr.io/chat-api
  newTag: "4812"

5. Argo CD pour le support#

5.1 Le vocabulaire#

Terme Sens Ce que le support en tire
Application (CRD) Une source Git (repo, révision, chemin) + une destination (cluster, namespace) + une politique de sync L'objet à inspecter en premier
AppProject Garde-fous : dépôts sources, destinations et types de ressources autorisés ; default est permissif Une Application qui ne se synchronise pas peut violer son projet
Target state / Live state Ce que dit Git / ce qui tourne La différence = le diff
Refresh Comparer Git et le cluster (sans rien appliquer) --refresh, ou hard refresh qui vide aussi le cache des manifestes
Sync Appliquer la cible au cluster Peut être automatique ou manuelle
Sync status Synced ou OutOfSync « Git est-il appliqué ? »
Health status Healthy, Progressing, Degraded, Suspended, Missing, Unknown « Est-ce que ça marche ? »

5.2 Une Application commentée#

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: chat-api-prd
  namespace: argocd                       # namespace d'installation de l'extension (argocd par défaut)
spec:
  project: chatbot                        # AppProject : sources et destinations autorisées
  source:
    repoURL: https://dev.azure.com/contoso/Chatbot/_git/gitops-chatbot
    targetRevision: main                  # branche suivie : un commit sur une autre branche ne sera jamais vu
    path: apps/chat-api                   # chemin : un fichier modifié ailleurs ne sera jamais vu
    helm:
      valueFiles: [ values-prd.yaml ]     # le fichier que le pipeline modifie
  destination:
    server: https://kubernetes.default.svc
    namespace: chatbot
  syncPolicy:
    automated:
      prune: true                         # supprime ce qui a disparu de Git (désactivé par défaut)
      selfHeal: true                      # annule les modifications manuelles (désactivé par défaut)
    syncOptions:
    - CreateNamespace=true
    retry:
      limit: 5
      backoff: { duration: 10s, factor: 2, maxDuration: 3m }
  ignoreDifferences:
  - group: apps
    kind: Deployment
    jsonPointers: [ /spec/replicas ]      # le HPA gère les replicas : pas de faux OutOfSync

5.3 Lire ensemble sync status et health#

Argo CD : lire ensemble le sync status et le health status

Règles de santé intégrées utiles :

  • Deployment, ReplicaSet, StatefulSet, DaemonSet : sain quand la génération observée égale la génération voulue et que le nombre de replicas à jour égale le nombre voulu (un rollout bloqué reste Progressing puis Degraded).
  • Service de type LoadBalancer : sain quand status.loadBalancer.ingress contient une IP ou un nom.
  • Ingress : même règle. Un controller qui ne publie pas d'adresse laisse l'Ingress en Progressing pour toujours.
  • PersistentVolumeClaim : sain quand il est Bound.
  • La santé de l'Application est la pire de ses ressources directes (ordre : Healthy, Suspended, Progressing, Missing, Degraded, Unknown).

5.4 La politique de sync, précisément#

Réglage Comportement documenté
Détection des changements Interrogation de Git toutes les 3 minutes par défaut (timeout.reconciliation 120 s + jusqu'à 60 s de jitter) ; un webhook (Azure DevOps est pris en charge) rend la détection immédiate
automated Synchronise seulement si l'Application est OutOfSync ; une seule tentative par commit (SHA + paramètres) ; ne retente pas un commit dont la sync a échoué, sauf retry configuré
prune Désactivé par défaut : une ressource retirée de Git reste dans le cluster (OutOfSync)
selfHeal Désactivé par défaut : une modification manuelle du cluster ne déclenche pas de sync ; activé, la sync est relancée après 5 s par défaut
allowEmpty Protection : sans lui, une sync automatique avec prune refuse de tout supprimer quand la source devient vide
Retour arrière argocd app rollback est impossible quand la sync automatique est active : le retour arrière passe par Git

5.5 Sync options, différences ignorées, ordre#

  • Sync options utiles : CreateNamespace=true (sinon la sync échoue si le namespace n'existe pas), ServerSideApply=true, PruneLast=true, ApplyOutOfSyncOnly=true ; annotation argocd.argoproj.io/sync-options: Prune=false pour protéger une ressource.
  • ignoreDifferences : pour les champs gérés par un autre acteur (replicas du HPA, champs mutés par un webhook). Mal utilisé, il masque un vrai écart : un champ ignoré ne rendra jamais l'Application OutOfSync.
  • Faux OutOfSync connus : quantités normalisées par Kubernetes (1000m contre 1), outils qui posent aussi le label app.kubernetes.io/instance (Kustomize commonLabels).
  • Sync waves : annotation argocd.argoproj.io/sync-wave (entier, 0 par défaut, négatif autorisé), du plus petit au plus grand, avec 2 s entre deux vagues.
  • Hooks : PreSync (ex. migration de schéma), Sync, PostSync (tests de fumée), SyncFail (nettoyage) ; un hook en échec fait échouer la sync ; hook-delete-policy décide quand le Job est supprimé. Les hooks ne tournent pas en sync sélective.
  • App of apps / ApplicationSet : une Application qui crée d'autres Applications ; réservé aux administrateurs (on peut y choisir n'importe quel projet).

5.6 Argo CD sur AKS : l'extension Microsoft#

Argo CD (extension Microsoft.ArgoCD) Flux v2 (extension microsoft.flux)
Statut Disponible en général pour AKS, préversion pour Azure Arc ; l'activation depuis le portail (GitOps > Enable Argo CD) est marquée Preview Disponible en général
Objets Application, ApplicationSet, interface web, CLI argocd GitRepository, Kustomization, HelmRelease ; ressource Azure fluxConfigurations
Identité Workload Identity (lecture ACR, Azure DevOps sans secret) et SSO Microsoft Entra ID Workload identity pour la source
Points d'attention Mode haute disponibilité par défaut : au moins 4 nodes (redis-ha.enabled=false sinon) ; depuis 1.0.0-preview, chart communautaire avec des clés de configuration différentes Multi-tenancy appliquée par défaut
az k8s-extension show --resource-group rg-chat-prd --cluster-name aks-chat-prd --cluster-type managedClusters \
  --name argocd --query provisioningState --output tsv
kubectl get pods -n argocd                                   # application-controller, repo-server, server, redis
kubectl get applications -n argocd                           # SYNC STATUS et HEALTH STATUS de chaque Application
kubectl get events -n argocd --sort-by=.lastTimestamp

5.7 Boîte à outils Argo CD (lecture d'abord)#

Besoin Commande
État, révision, ressources, dernière opération argocd app get chat-api-prd
Forcer la relecture de Git / vider le cache argocd app get chat-api-prd --refresh / --hard-refresh
Ce qui diffère entre Git et le cluster argocd app diff chat-api-prd
Historique des syncs (révision Git de chacune) argocd app history chat-api-prd
Manifestes rendus (ce qu'Argo CD appliquerait) argocd app manifests chat-api-prd
Sans CLI Argo CD kubectl get application chat-api-prd -n argocd -o yaml (bloc status)
Erreur de génération des manifestes Journaux du argocd-repo-server (Helm, Kustomize)
Erreur d'application, sync bloquée Journaux de argocd-application-controller
Action (après accord) : synchroniser argocd app sync chat-api-prd (--dry-run pour prévisualiser)

Manifest generation error (cached) : l'erreur de rendu est mise en cache ; un hard refresh suffit si elle était passagère, sinon la cause est dans les journaux du repo-server (values Helm invalides, chemin inexistant, chart introuvable).


6. J'ai poussé dans Git et rien ne change#

flowchart TD
    A["Commit poussé, rien ne change"] --> B{"Le commit est-il sur la branche<br/>et le chemin suivis par l'Application ?"}
    B -- Non --> B1["targetRevision, path, valueFiles, repoURL<br/>autre dépôt ou autre overlay"]
    B -- Oui --> C{"argocd app get : la révision<br/>affichée est-elle ce commit ?"}
    C -- Non --> C1["Attendre 3 min ou refresh<br/>webhook, accès au dépôt, repo-server"]
    C -- Oui --> D{"Sync status ?"}
    D -- OutOfSync --> D1{"Auto-sync activé ?"}
    D1 -- Non --> D2["Sync manuelle attendue"]
    D1 -- Oui --> D3["Opération en échec : message<br/>hook, admission, quota, CRD"]
    D -- Synced --> E{"Le template de pod a-t-il changé ?"}
    E -- Non --> E1["Même tag réutilisé ou champ ignoré<br/>ignoreDifferences"]
    E -- Oui --> F{"Health ?"}
    F -- Progressing --> F1["Rollout en cours ou bloqué<br/>kubectl rollout status"]
    F -- Degraded --> F2["ImagePullBackOff, CrashLoopBackOff<br/>diagnostic du chapitre 04"]
    F -- Healthy --> F3["Bonne version en place : vérifier le cache<br/>navigateur, l'Ingress, la bonne URL"]
Symptôme Cause Vérifier Corriger
Argo CD affiche une ancienne révision Branche (targetRevision) ou chemin (path) différent de celui modifié argocd app get : Repo, Target, Path Modifier le bon fichier, ou corriger l'Application
Le pipeline a modifié values-dev.yaml L'Application PRD lit values-prd.yaml spec.source.helm.valueFiles Corriger le pipeline
L'Application pointe vers un autre dépôt (fork, ancien dépôt) repoURL argocd app get Corriger repoURL (via Git de l'app of apps)
Révision à jour mais OutOfSync stable Auto-sync désactivé, ou sync automatique déjà tentée et échouée sur ce commit spec.syncPolicy, argocd app history Sync manuelle après accord ; corriger la cause ; retry
Sync en échec Manifeste invalide, refus d'admission (Azure Policy, PSA), quota, namespace absent, hook PreSync en échec Message de l'opération, Events Corriger dans Git
Synced + Healthy, mais ancienne image Tag réutilisé (latest) : rien n'a changé dans le template Image et digest dans describe pod Tag unique ; imagePullPolicy n'est pas la solution
Synced + Degraded Git appliqué, application KO (ImagePullBackOff…) Chapitre 04 Selon la panne
Modification manuelle dans le cluster « qui revient » selfHeal actif : comportement voulu syncPolicy.automated.selfHeal Passer par Git
Modification manuelle « qui reste » selfHeal inactif : dérive affichée OutOfSync argocd app diff Resynchroniser ou reporter dans Git
Ressource supprimée de Git toujours présente prune désactivé argocd app get (ressource OutOfSync, à supprimer) Prune manuel après accord, ou activer prune
Un champ modifié dans Git n'apparaît jamais Champ dans ignoreDifferences spec.ignoreDifferences Restreindre l'ignore
Manifest generation error (cached) Erreur Helm ou Kustomize Hard refresh, journaux du repo-server Corriger les values ou le chemin
Ingress Progressing sans fin Le controller ne remplit pas status.loadBalancer.ingress kubectl get ingress (ADDRESS vide) Controller, classe, Service du controller
Argo CD ne lit plus le dépôt Identifiants ou Workload Identity expirés, réseau Journaux du repo-server, kubectl get secret -n argocd -l argocd.argoproj.io/secret-type=repository Rétablir l'accès

7. Le déploiement ne crée pas de nouveaux pods#

Symptôme Cause Vérifier Corriger
Aucun nouveau ReplicaSet Template de pod identique (même tag, changement hors du template) kubectl rollout history, image du Deployment Tag unique, changement dans le template
Rollout en pause spec.paused: true kubectl get deploy -o yaml kubectl rollout resume (après accord) ou corriger Git
Nouveau ReplicaSet à 0 pod, ReplicaFailure ResourceQuota, LimitRange, refus d'admission kubectl describe rs <nouveau-rs> (Events FailedCreate) Quota, policy, valeurs
Nouveaux pods Pending Capacité, taints, affinité kubectl describe pod Capacité ou placement
Nouveaux pods jamais Ready, anciens toujours là Readiness en échec : le rollout attend (maxUnavailable) kubectl rollout status, Events Corriger l'application ou la probe
ProgressDeadlineExceeded Rollout bloqué au-delà de 600 s kubectl describe deploy (Conditions) Cause ci-dessus, puis nouveau commit
replicas revient toujours à la même valeur HPA, ou Argo CD qui réapplique la valeur de Git kubectl get hpa, ignoreDifferences Laisser le HPA décider, ignorer /spec/replicas
Pipeline vert mais pas de commit GitOps Push refusé (droits Build Service), étape conditionnelle sautée Logs de l'étape git push Droit Contribute, persistCredentials

8. Lab : casser et réparer une Application Argo CD (60 minutes)#

Sur un cluster de test avec l'extension Argo CD (quickstart Microsoft : redis-ha.enabled=false pour un petit cluster), et un dépôt Git de test contenant un Deployment nginx.

az k8s-extension create --resource-group rg-lab --cluster-name aks-lab --cluster-type managedClusters \
  --name argocd --extension-type Microsoft.ArgoCD \
  --config "redis-ha.enabled=false" --config "configs.params.application\.namespaces=argocd"
kubectl get pods -n argocd
  1. Créer une Application sans automated ; modifier le tag dans Git : observer OutOfSync, argocd app diff, puis synchroniser.
  2. Activer automated sans selfHeal ; faire kubectl scale deploy nginx --replicas=5 : l'Application passe OutOfSync et reste ainsi. Activer selfHeal : la valeur de Git revient.
  3. Mettre un tag inexistant dans Git : Synced + Degraded ; lire ImagePullBackOff dans les Events.
  4. Modifier un fichier hors du path suivi : rien ne se passe ; le prouver avec argocd app get.
  5. Réutiliser le même tag pour une nouvelle image : aucun rollout ; le prouver avec kubectl rollout history.
  6. Nettoyage : supprimer le resource group de test.

9. Questions d'entretien#

1. Décris la chaîne, du commit au pod.

Merge sur main, le pipeline Azure DevOps construit l'image avec Docker@2 sur un agent dans le VNet et la pousse dans l'ACR Premium privé avec un tag unique (Build.BuildId), puis commite ce tag dans le dépôt GitOps. Argo CD voit le commit (3 minutes ou webhook), synchronise, le Deployment fait son rollout et le kubelet tire l'image par le Private Endpoint.

2. Pourquoi ACR Premium ?

Pour le Private Link (le registre n'est joignable que depuis le réseau), la geo-replication, les customer-managed keys, les dedicated agent pools pour ACR Tasks, et plus de débit. La zone redundancy, elle, est désormais disponible sur tous les tiers.

3. Le registre est privé : qu'est-ce que ça change pour la CI ?

Les Microsoft-hosted agents ne l'atteignent plus : agents self-hosted ou Managed DevOps Pools injectés dans le VNet, avec la zone privatelink.azurecr.io (registre et data endpoint). az acr build ne marche plus sans dedicated agent pool ou règle explicite.

4. Synced et Healthy, quelle différence ?

Synced dit que le cluster correspond à Git ; Healthy dit que les ressources fonctionnent. Synced + Degraded est fréquent : Git est bien appliqué mais le pod est en ImagePullBackOff ou CrashLoopBackOff, c'est un diagnostic Kubernetes.

5. Self-heal et prune ?

Les deux sont désactivés par défaut. Prune supprime du cluster ce qui a disparu de Git ; self-heal réapplique Git quand quelqu'un modifie le cluster à la main. Sans self-heal, la dérive est seulement affichée OutOfSync.

6. J'ai poussé dans Git et rien ne change. Ta démarche ?

Je vérifie que le commit est sur la branche, le chemin et le fichier de values suivis par l'Application ; que la révision affichée par Argo CD est ce commit (sinon refresh, accès au dépôt) ; l'état de la sync (auto-sync, échec, message) ; que le template de pod a réellement changé (tag réutilisé ?) ; puis la santé et le rollout.

7. Pourquoi ne jamais déployer latest ?

Le template de pod ne change pas, donc aucun rollout ; les nodes peuvent tirer des versions différentes ; on ne sait pas ce qui tourne et on ne peut pas revenir en arrière. Microsoft recommande des tags uniques et le verrouillage des tags déployés.

8. Comment fais-tu un retour arrière ?

Par git revert du commit de tag : Argo CD resynchronise. argocd app rollback est refusé quand l'auto-sync est actif, et un kubectl rollout undo serait annulé par self-heal. En urgence absolue, désactiver l'auto-sync puis rollback, en le signalant.

9. Pourquoi une Application peut-elle rester OutOfSync juste après une sync réussie ?

Un acteur modifie un champ après Argo CD (HPA sur replicas, webhook de mutation), ou une normalisation (1000m contre 1), ou un conflit sur le label app.kubernetes.io/instance. On le traite avec ignoreDifferences ciblé, pas en ignorant tout.

10. Flux ou Argo CD sur AKS ?

Les deux existent en cluster extension. Argo CD est disponible en général sur AKS (préversion sur Arc), avec interface web, ApplicationSet, Workload Identity et SSO Entra ID, et demande 4 nodes en mode HA. Flux est plus léger et piloté par la ressource Azure fluxConfigurations. Ici le client a choisi Argo CD : je dois savoir le lire et le diagnostiquer.

11. Le pipeline est vert mais Git n'a pas reçu le tag.

Regarder l'étape git push : droit Contribute de l'identité « Build Service » du projet sur le dépôt GitOps, persistCredentials sur le checkout, branche protégée par une policy (il faut alors une pull request).


10. Fiche à retenir#

  • Huit maillons : merge → run → push ACR → commit GitOps → détection Argo CD → sync → rollout → pull.
  • Docker@2 : service connection Docker Registry (Workload Identity federation), tag par défaut $(Build.BuildId), arguments ignoré en buildAndPush.
  • Pousser dans Git depuis un pipeline : Build Service avec Contribute, persistCredentials: true, [skip ci].
  • Tags uniques pour déployer, verrouiller les tags déployés ; jamais latest.
  • ACR Premium : Private Link, geo-replication, CMK, retention (préversion), agent pool (préversion) ; zone redundancy tous tiers ; DCT en retrait (Notation).
  • Private Endpoint ACR : registre et data endpoint dans privatelink.azurecr.io ; agents dans le VNet ; az acr build bloqué sans agent pool.
  • Argo CD : Application (source + destination + syncPolicy), AppProject, refresh / hard refresh, sync.
  • Sync status (Synced / OutOfSync) ≠ health (Healthy, Progressing, Degraded, Suspended, Missing, Unknown) ; santé de l'app = la pire.
  • Détection toutes les 3 min (120 s + 60 s), webhook Azure DevOps possible ; auto-sync une fois par commit.
  • prune et selfHeal désactivés par défaut ; rollback CLI impossible en auto-sync → git revert.
  • Sync waves (0 par défaut, 2 s entre vagues), hooks PreSync / Sync / PostSync / SyncFail.
  • Extension Microsoft.ArgoCD : GA sur AKS, préversion sur Arc et dans le portail, HA = 4 nodes.

Références#

Relevé du 23/10/2026.

Microsoft Learn :

Argo CD (argo-cd.readthedocs.io, version stable) :

Kubernetes : Deployments

Sur cette page
Échap

Tape au moins 2 lettres. Plusieurs mots : tous doivent apparaître.