Lección 2 — GitOps avec Argo CD

Synchroniser, corriger la dérive, revenir en arrière

8 min de lectura

Este contenido aún no está traducido. Se muestra la versión original.

Synchroniser, corriger la dérive, revenir en arrière

Lundi de rentrée, le support informatique de Ferrand Médical reçoit trois fois plus de questions que d'habitude. L'astreinte veut passer de 3 à 4 pods. Sans GitOps, elle tape kubectl scale et oublie de le reporter ; avec GitOps, cette commande est annulée dans la seconde. Cette leçon montre les trois gestes quotidiens et leurs durées mesurées : déployer par commit, constater qu'une modification manuelle est effacée, revenir en arrière par git revert.

Le mécanisme

sequenceDiagram
  participant Dev as Astreinte
  participant Repo as gitops-repo
  participant Git as git-server
  participant ACD as Argo CD
  participant K8s as Cluster
  Dev->>Repo: "commit replicaCount: 4"
  Dev->>Git: "make gitops-push (+ annotation refresh)"
  ACD->>Git: "fetch main"
  ACD->>K8s: "apply : Rollout replicas 4"
  Note over K8s: "4 pods prêts après 29 s"
  Dev->>K8s: "kubectl scale --replicas=1 (dérive)"
  K8s-->>ACD: "événement : Rollout modifié"
  ACD->>K8s: "selfHeal : replicas 3 (après 1 s)"
  Dev->>Repo: "git revert HEAD"
  Dev->>Git: "push"
  ACD->>K8s: "apply : état du commit précédent"

Argo CD ne découvre pas la dérive en relisant le cluster toutes les trois minutes : il surveille les objets qu'il gère. Une modification déclenche une comparaison immédiate, et selfHeal réapplique Git. Le délai de trois minutes concerne l'autre sens, la lecture du dépôt Git, d'où l'annotation argocd.argoproj.io/refresh que pose make gitops-push.

La mise en œuvre

Déployer par commit

terminal
sed -i 's/^replicaCount: 3/replicaCount: 4/' gitops-repo/environments/kind/values.yaml
git -C gitops-repo commit -am "Pic de rentrée : 4 répliques"
make gitops-push
make status

make gitops-push ouvre un port-forward vers le serveur Git, pousse main, puis demande une relecture :

files/Makefile
gitops-push: ## Pousse gitops-repo/ vers le serveur Git du cluster et demande une synchronisation
	@$(K) -n git port-forward svc/git-server 19418:9418 >/dev/null 2>&1 & PF=$$!; sleep 2; \
	  git -C gitops-repo push -q git://127.0.0.1:19418/assistant.git main; RC=$$?; kill $$PF; exit $$RC
	@$(K) -n argocd annotate application assistant argocd.argoproj.io/refresh=normal --overwrite >/dev/null 2>&1 || true

Changer replicaCount ne modifie pas le gabarit des pods : Argo Rollouts ajoute un pod sans lancer de canary. Changer l'image ou la configuration déclenche le canary de la leçon 3.

Constater la dérive

terminal
kubectl --context kind-lab-k8s-gitops -n assistant scale rollout inference --replicas=1
kubectl --context kind-lab-k8s-gitops -n assistant get rollout inference -o jsonpath='{.spec.replicas}'

La valeur revient à 3 en une seconde. Mais regardez les pods : deux ont été supprimés puis recréés. selfHeal répare l'état, il n'annule pas l'effet de la commande pendant cette seconde. Une dérive destructrice (un kubectl delete, un scale à 0) coupe le service le temps que les nouveaux pods passent leur readiness.

Revenir en arrière

terminal
make gitops-revert       # git revert --no-edit HEAD, puis make gitops-push
git -C gitops-repo log --oneline

Le retour arrière est un commit comme un autre : il porte un auteur, une date, et il se relit.

Ce qui casse en production

SymptômeCauseParade
Le nombre de pods oscille entre la valeur de Git et celle de l'HPAreplicas déclaré dans le Rollout alors qu'un HPA le pilotele chart n'émet pas replicas quand autoscaling.enabled=true ; sinon ignoreDifferences sur /spec/replicas
Une correction manuelle « disparaît »selfHeal a réappliqué Git, comme prévucorriger par commit ; en urgence, commit immédiatement après
Application OutOfSync permanente sans changement réelun contrôleur ou un webhook modifie un champ après l'apply (valeurs par défaut, annotations)ignoreDifferences ciblé, ou ServerSideApply=true
Application bloquée en OutOfSync, sync Failed ... spec.ports[1].name: Duplicate value: "http" (retried 3 times)un kubectl patch a changé le port du Service ; l'apply d'Argo CD fusionne la liste des ports par numéro et ajoute 80 à côté de 8080 au lieu de le remplacer. ServerSideApply=true échoue de la même façon (reproduit)synchronisation ciblée avec Replace=true sur le Service ; et retirer le droit patch sur les Services en production
git revert en conflitle commit annulé a été suivi d'autres modifications des mêmes lignesrevert du plus récent au plus ancien, ou commit correctif explicite
Secret « perdu » après un pruneSecret créé à la main dans un namespace géré, puis ajouté par erreur au chart et retiréles Secrets viennent d'un mécanisme dédié (leçon 5), jamais du chart

La règle de décision

  • Toute modification durable passe par un commit ; kubectl sert à lire et à diagnostiquer.
  • Rollback = git revert, jamais le bouton d'Argo CD avec une synchronisation automatique.
  • Un pic temporaire se traite par l'HPA, pas par replicaCount : un commit pour un pic d'une heure, c'est un second commit à ne pas oublier.
  • À surveiller : les applications OutOfSync depuis plus de quelques minutes et le compteur de self-heal (argocd_app_sync_total côté métriques d'Argo CD).

Pratique

Pendant un incident, un collègue désactive la synchronisation automatique et fait un rollback depuis l'interface d'Argo CD. Le service revient. Que faut-il faire avant de réactiver automated ?

Vous mesurez que selfHeal annule un kubectl scale en une seconde. Un développeur en conclut que la dérive n'a plus d'effet. Qu'objectez-vous ?

Exercice

Modifiez directement le port du Service : kubectl -n assistant patch svc inference --type=json -p '[{"op":"replace","path":"/spec/ports/0/port","value":8080}]'. Selon la mesure du scale, Argo CD devrait le remettre à 80 en une seconde. Vérifiez, et si ce n'est pas le cas, trouvez pourquoi et réparez.

Voir la solution

Le port reste à 8080. L'application passe OutOfSync, puis la synchronisation échoue trois fois :

Failed | one or more objects failed to apply, reason: error when patching "/dev/shm/1623828138":
Service "inference" is invalid: spec.ports[1].name: Duplicate value: "http" (retried 3 times).

L'apply fusionne la liste ports en utilisant le numéro de port comme clé : pour lui, le port 80 de Git est une entrée nouvelle, à ajouter à côté de 8080, et les deux portent le nom http. L'API refuse. Le même essai avec ServerSideApply=true donne la même erreur. Après trois échecs, Argo CD ne relance plus la synchronisation automatique de ce commit : la dérive reste en place jusqu'à une intervention.

Réparation : une synchronisation limitée au Service, en mode remplacement (équivalent de argocd app sync assistant --resource :Service:inference --replace) :

terminal
kubectl --context kind-lab-k8s-gitops -n argocd patch application assistant --type merge -p \
  '{"operation":{"initiatedBy":{"username":"astreinte"},"sync":{"syncOptions":["Replace=true"],
    "resources":[{"kind":"Service","name":"inference","namespace":"assistant"}]}}}'

Le port revient à 80, l'application repasse Synced/Healthy, le clusterIP est conservé. Pendant la dérive, l'Ingress a continué de répondre 200 dans ce lab ; ne comptez pas dessus, un autre contrôleur d'entrée pourrait perdre son backend. Le selfHeal ne couvre donc pas toutes les dérives : il réapplique, et certains champs ne se réappliquent pas par fusion.

Résultat obtenu

Exécution du 2026-10-16 :

$ git -C gitops-repo commit -qam "Pic de rentrée : 4 répliques" && make gitops-push
Poussé : 6dbf4ea Pic de rentrée : 4 répliques
4 pods prêts après 29 s
APP         SYNC     SANTE     REVISION
assistant   Synced   Healthy   6dbf4ea12b8a9364103c516efd75133ccdf404bb

$ make gitops-revert
Poussé : ae9d624 Revert "Pic de rentrée : 4 répliques"
3 répliques après 6 s
ae9d624 Revert "Pic de rentrée : 4 répliques"
6dbf4ea Pic de rentrée : 4 répliques
68185e5 Déploiement initial : assistant 0.2.0

$ kubectl -n assistant scale rollout inference --replicas=1
rollout.argoproj.io/inference scaled
spec.replicas revenu à 3 après 1 s

$ kubectl -n assistant patch svc inference --type=json -p '[{"op":"replace","path":"/spec/ports/0/port","value":8080}]'
service/inference patched
OutOfSync Failed ... Service "inference" is invalid: spec.ports[1].name: Duplicate value: "http" (retried 3 times).
$ # synchronisation ciblée Replace=true
80
assistant   Synced   Healthy   a05419910dd63b6b9329484970ebe84114c76a02

Les 29 s du déploiement comprennent le push, la relecture du dépôt, le rendu du chart, le démarrage du pod et sa readiness. Le revert est plus rapide parce qu'il retire un pod au lieu d'en démarrer un. Une première mesure de dérive, faite sur un ConfigMap avec la version 0.2.0 du chart, donnait le même délai d'une seconde.

Historique des synchronisations vu par Argo CD sur toute la session (extrait) :

1 68185e5... 2026-10-16T14:52:53Z
2 6dbf4ea... 2026-10-16T14:55:03Z
3 ae9d624... 2026-10-16T14:55:35Z

Je sais faire

  • Déployer par commit et mesurer le délai jusqu'aux pods prêts
  • Expliquer pourquoi selfHeal répare l'état sans annuler l'effet d'une dérive
  • Revenir en arrière par make gitops-revert et relire l'historique
  • Dire pourquoi le rollback de l'interface d'Argo CD est refusé avec automated
  • Débloquer une dérive que selfHeal ne sait pas réparer, par une synchronisation ciblée Replace=true
Siguiente