GitOps en 2 minutes 01
Git est la source de vérité
Plus personne ne fait kubectl apply à la main. On commit dans Git, ArgoCD voit le commit, compare avec le cluster et applique la différence. Rollback = revert git.
- Déclaratif : le repo contient l'état désiré (YAML, Helm, Kustomize).
- Versionné : qui a changé quoi, quand, pourquoi —
git logtient lieu d'audit. - Pulled, not pushed : ArgoCD dans le cluster tire depuis Git — pas de credentials kube dans la CI.
- Observable : une UI, une API, un CLI pour voir l'écart en temps réel.
Architecture ArgoCD 02
Quatre composants spécialisés
ArgoCD tourne dans le cluster — namespace argocd. Chaque composant a une responsabilité bien délimitée.
Le cycle de sync 03
Refresh → compare → sync
Toutes les 3 min (par défaut) — ou sur webhook Git, ou sur demande — ArgoCD refait une passe.
- Refresh : le repo-server tire le dernier commit et rend les manifests (helm template, kustomize build…).
- Compare : le controller compare le rendu au live state (ce qui tourne dans le cluster).
- Sync : si automatisé, il applique. Sinon, on voit OutOfSync et on clique ⟳.
L'objet Application 04
Le contrat
Une Application est un CRD posé dans le namespace argocd. Elle dit quoi déployer, d'où, et où.
apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: laravel-pr730 namespace: argocd spec: project: default source: # d'où repoURL: https://git/org/app.git targetRevision: main path: charts/laravel helm: values: | replicaCount: 3 destination: # où server: https://kubernetes.default.svc namespace: laravel-pr730 syncPolicy: # comment automated: prune: true selfHeal: true syncOptions: - CreateNamespace=true - ServerSideApply=true
- source : repoURL + path + targetRevision (branche, tag ou SHA).
- destination : cluster + namespace cible.
- syncPolicy : manuel (par défaut) ou automated ± prune ± selfHeal.
Sync status 05
Git = cluster ?
Compare les manifests rendus depuis Git avec l'état live. Trois valeurs.
- Synced — le rendu Git correspond au live, tout va bien.
- OutOfSync — un diff existe. Soit Git a avancé, soit un humain a touché le cluster.
- Unknown — ArgoCD n'a pas réussi à lire Git ou le cluster. Cherche les logs du controller.
Dans l'UI, l'icône est un cercle bleu-ciel avec ⟳ pour OutOfSync. Dans la capture, le laravel-pr730 affiche à la fois Sync et Health — les deux axes sont indépendants.
Health status 06
Ça tourne ?
Jugement sur ce qui est en vie dans le cluster — distinct de la sync.
- Healthy ♥ vert — tout est UP (pods running, Deployment au bon nb de replicas…).
- Progressing — changement en cours (rolling update, pods en Init). Cas normal < quelques minutes.
- Suspended — ex. CronJob pausé, rollout paused.
- Degraded — un pod CrashLoop, un rollout qui timeout → il faut regarder.
- Missing — la ressource existe en Git mais pas dans le cluster.
L'arbre de ressources — décodé 07
Ce que tu vois dans l'UI
Au centre-gauche, l'Application. À droite, tous les objets déployés — arborescence par ownerReference : qui possède qui. C'est la vue Argo la plus utile pour diagnostiquer.
- La 1ʳᵉ colonne = ressources directement dans Git (ce qu'ArgoCD a appliqué).
- La 2ᵉ colonne = ressources créées par celles de la 1ʳᵉ via leur contrôleur k8s (un Deployment crée un RS, un Service expose des Endpoints, une ExternalSecret matérialise un Secret).
- La 3ᵉ colonne = pods (créés par les ReplicaSets ou directement par un StatefulSet).
- Les flèches suivent les ownerReferences Kubernetes — ArgoCD ne fait que lire ce graphe, il ne l'invente pas.
- Le « 7 hours » sous chaque objet = âge depuis la dernière modification observée.
Icônes · abréviations 08
Lire les petits badges
⚠ ES apparaît deux fois avec deux sens : cercle pointillé = EndpointSlice (natif k8s, enfant d'un Service) ; cercle plein = ExternalSecret (CRD externe qui crée un Secret depuis Vault/AWS SM/etc.).
Deployment → RS → Pod 09
Pourquoi plusieurs RS ?
Un Deployment ne crée pas les Pods directement. Il fabrique un ReplicaSet par révision. À chaque image/env qui change, un nouveau RS naît — l'ancien reste pour pouvoir rollback.
- Par défaut, 10 RS précédents sont gardés (
revisionHistoryLimit). - Un seul RS est actif à un instant — c'est celui qui matche le
templatecourant. - Les pods héritent du hash du template dans leur nom (web-6f9b846949-xyz).
- Rollback =
kubectl rollout undo— il suffit de re-scaler un ancien RS.
# Les révisions visibles dans ton screenshot laravel-pr730-64cd89f578 rev:1 # 0 replicas (ancienne) laravel-pr730-6c8c8f4f7 rev:3 # 2/2 running (stable) laravel-pr730-7ddb846949 rev:29 # 0/1 (nouveau, en train de monter) laravel-pr730-866ccc7b74 rev:28 # 0/2 terminating (ancien) laravel-pr730-d46787577 rev:2 # 0 replicas (ancienne)
Lire un rolling update 10
Ce qui se passe sous tes yeux
Dans ta capture, la colonne des ReplicaSets et la colonne des Pods racontent la même histoire : un rolling update en cours. Voilà la séquence.
- Le nouveau RS monte ; l'ancien descend. À chaque pod ready côté v29, un pod v28 est terminating.
- Les rectangles rose « terminating » sont normaux — c'est la phase de grace period.
- Le RS rev:29 peut aussi montrer un pod terminating si un pod v29 a mis trop de temps à devenir Ready et que le scheduler a remplacé.
- Health Progressing pendant tout ce temps, puis Healthy.
- Si ça bloque en Progressing > 10 min → regarder les logs du pod v29 et les probes.
Sync waves & hooks 11
Ordre d'application
Par défaut, ArgoCD applique tout en parallèle. Mais parfois il faut un ordre (CRD avant CR qui l'utilise, migration avant app…).
# Pousser une ressource dans une wave plus tardive metadata: annotations: argocd.argoproj.io/sync-wave: "2" # Hook : exécuté à un moment du sync annotations: argocd.argoproj.io/hook: PreSync # avant argocd.argoproj.io/hook: Sync # pendant argocd.argoproj.io/hook: PostSync # après argocd.argoproj.io/hook: SyncFail # si échec argocd.argoproj.io/hook-delete-policy: HookSucceeded
- Waves négatives (−1, −2) : appliquées en premier (ex : Namespace, CRD, Secret).
- Usage typique du PreSync : migration DB en Job avant de restarter les pods.
Auto-sync · prune · self-heal 12
Les trois cases à cocher
- automated — applique dès que Git change, sans clic.
- prune — supprime du cluster ce qui a été retiré de Git. Sans ça, ArgoCD ne supprime jamais.
- selfHeal — si un humain a modifié en direct (
kubectl edit), Argo réécrase avec Git au refresh suivant.
syncPolicy: automated: prune: true selfHeal: true syncOptions: - CreateNamespace=true - PrunePropagationPolicy=foreground - ApplyOutOfSyncOnly=true retry: limit: 5 backoff: { duration: 5s, factor: 2, maxDuration: 3m }
⚠ Sans prune, un fichier supprimé de Git laisse la ressource orpheline en cluster — dette garantie.
AppProject & ApplicationSet 13
Isoler · multiplier
- AppProject — boîte autour de N Applications. Restreint les sources (repos autorisés) et les destinations (clusters/ns autorisés). Utile en multi-tenant.
- ApplicationSet — controller qui génère des Applications depuis un template + un générateur (Git, List, Cluster, Matrix, PR). Le cas typique : une App par PR GitHub.
# ApplicationSet : une App par PR kind: ApplicationSet spec: generators: - pullRequest: github: { owner: acme, repo: laravel } template: metadata: name: 'laravel-pr{{number}}' spec: source: repoURL: https://git/acme/laravel.git targetRevision: '{{head_sha}}' path: charts/laravel destination: server: https://kubernetes.default.svc namespace: 'laravel-pr{{number}}'
💡 Le préfixe laravel-pr730 dans ta capture vient très probablement d'un ApplicationSet PR generator — chaque PR GitHub a son Application et son namespace.
CLI argocd 14
L'essentiel au terminal
# Login argocd login argocd.example.com --sso argocd login --core # talk to k8s directly # Apps argocd app list argocd app get laravel-pr730 argocd app diff laravel-pr730 # git vs live argocd app sync laravel-pr730 argocd app sync laravel-pr730 --prune argocd app rollback laravel-pr730 29 argocd app logs laravel-pr730 -f --tail 100 # History · refresh argocd app history laravel-pr730 argocd app refresh laravel-pr730 --hard argocd app wait laravel-pr730 --health argocd app terminate-op laravel-pr730 # Clusters · repos argocd cluster list argocd repo list
Troubleshooting — patterns 15
Ce que l'UI te dit vraiment
- OutOfSync qui colle — clique « App Diff ». Souvent une annotation
last-applied-configurationou un champ managed by un autre controller (HPA modifiereplicas…). Fix :ignoreDifferencesdans la spec. - Degraded sur un Deployment — ouvre le RS courant → Pods → Events. Probe qui échoue, image tag introuvable, OOMKill, ImagePullBackOff.
- Missing — le manifest existe en Git, pas en cluster. Souvent un hook en échec ou une erreur RBAC côté controller.
- Prune réticent — Argo exige
prune: trueet que la ressource ait été un jour gérée par lui (annotationargocd.argoproj.io/tracking-id). - Hook failed — visible en bleu-ciel avec statut d'échec dans l'arbre.
argocd app logs <app>+kubectl logssur le Job hook. - Sync bloquée sur une ressource « pending » — un finalizer retient la suppression. Regarde
kubectl get <res> <n> -o yaml | grep finalizers. - App entière orpheline — l'ApplicationSet parent a été retiré mais l'App reste — active
preservedFieldsou la policy create-only avec précaution.
# Ignorer un champ qui varie en runtime (HPA, operator…) spec: ignoreDifferences: - group: apps kind: Deployment jsonPointers: - /spec/replicas