Skip to content

Architecture de bout en bout

Ce guide raconte l'architecture complète du projet : comment le code arrive en prod, comment une requête atteint l'app, comment les secrets circulent, comment on observe. Pour chaque brique : son rôle, et surtout le pourquoi du choix (c'est le « pourquoi » qui se défend en entretien, pas la liste des outils).

Le schéma d'ensemble : Architecture DevSecOps EKS.

ADR liés : GitOps ArgoCD, Exposition ownership, NLB vs CLB, ESO + IRSA, Observabilité.


La clé : deux flux qui se croisent sur le schéma

Le piège d'un schéma d'archi, c'est de vouloir tout lire d'un coup. En réalité, il y a deux récits distincts qui ne se rencontrent qu'au niveau du pod :

  • Le flux de livraison : comment ton code passe d'un commit à un pod qui tourne (CI/CD puis GitOps).
  • Le flux de trafic : comment la requête d'un utilisateur atteint ton app (DNS → load balancer → Gateway → pod).

En entretien, commence toujours par cette séparation. Elle montre une vision d'architecte (des flux, des responsabilités) plutôt qu'un empilement d'outils.

LIVRAISON :  commit ─► CI ─► ECR + Git ─► ArgoCD ─► cluster
                                                      │
                                                  pod FastAPI
                                                      ▲
TRAFIC :     utilisateur ─► DNS ─► NLB ─► Envoy Gateway ─► Service ─┘

Récit 1 : comment le code arrive en prod (livraison)

commit ─► GitLab CI ─► build (kaniko) ─► scan (Trivy) ─► promote ECR (par digest)
                                                              │
                                       write-back du tag dans Git (kustomization.yaml)
                                                              │
                                       ArgoCD voit le commit ─► reconcile ─► cluster

Les concepts à maîtriser

Concept Ce que c'est Le pourquoi
Promote par digest l'image est identifiée par son SHA256, pas un tag mutable l'image scannée est exactement l'image déployée ; un tag comme latest peut bouger sous tes pieds (cf. INC-050)
GitOps pull-based (#72) la CI n'applique plus rien sur le cluster ; elle écrit le tag dans Git, ArgoCD tire (pull) depuis Git Git = source de vérité unique ; pas de credentials cluster dans la CI ; reconciliation continue (anti-dérive)
App-of-apps une Application racine ArgoCD découvre les autres Applications dans un dossier pour ajouter une brique, on dépose un fichier ; ArgoCD le déploie seul
Découplage CI / ArgoCD ArgoCD ne regarde ni le pipeline ni les MR, seulement la branche develop un fix peut partir en live par simple merge, même pipeline app à l'arrêt (vécu : fix Grafana #88)

Question d'entretien classique : « comment garantis-tu que ce qui tourne en prod est ce que tu as testé ? » → promote par digest + Git comme source de vérité. La réponse tient en deux maillons.

Voir le détail dans Comprendre ArgoCD.


Récit 2 : comment une requête atteint l'app (trafic)

Utilisateur
   │ https://api.devopsyouss.com
   ▼
Cloudflare DNS ─► NLB ─► Envoy Gateway ─► HTTPRoute ─► Service (ClusterIP) ─► Pod FastAPI
                          (TLS terminé ici : cert wildcard)

Les concepts à maîtriser

Brique Rôle Le pourquoi du choix
Gateway API (pas Ingress) Gateway = point d'entrée + listeners 80/443 ; HTTPRoute = quelle URL va vers quel service standard plus expressif et portable que l'Ingress historique ; sépare le « point d'entrée » (plateforme) de « la route » (app), cf. ADR 010
NLB (#70) load balancer L4 devant Envoy Envoy fait déjà tout le L7 (routing, TLS) ; un ALB serait redondant, le CLB est déprécié AWS
cert-manager + wildcard (#76) certificat *.devopsyouss.com (Let's Encrypt, challenge DNS-01 Cloudflare) un seul cert couvre api + grafana + doc et tout futur sous-domaine ; DNS-01 obligatoire pour un wildcard
ExternalDNS (#66) crée le CNAME automatiquement depuis le hostname de la HTTPRoute zéro DNS à la main ; la route est la source de vérité du nom

Le Gateway est un ingress partagé (#76) : allowedRoutes: from: All autorise des routes d'autres namespaces (Grafana en ns monitoring) à s'y attacher. Un seul point d'entrée, plusieurs apps.

Voir La démarche d'exposition.


Récit 3 : comment l'app obtient ses secrets (rien en clair dans Git)

AWS Secrets Manager ─► External Secrets Operator (auth IRSA) ─► Secret K8s ─► Pod

Les concepts à maîtriser

  • ESO (External Secrets Operator) : va chercher le secret dans AWS Secrets Manager et le matérialise en Secret Kubernetes. L'app lit un Secret K8s normal, jamais un secret versionné dans Git.
  • IRSA (IAM Roles for Service Accounts) : le ServiceAccount du contrôleur ESO assume un rôle IAM via le provider OIDC du cluster. Aucune clé d'accès AWS n'est stockée nulle part. C'est la réponse propre à « comment t'authentifies-tu à AWS depuis un pod ? ».
  • Moindre privilège : le rôle IAM est restreint aux ARN précis des secrets utilisés (base de données, Grafana, webhook Slack), pas un accès large.

Même pattern pour tous les secrets du projet : mot de passe DB, mot de passe admin Grafana (#76), webhook Slack de l'alerting (#77). Une seule mécanique à expliquer.

Voir ESO + IRSA.


Récit 4 : comment on observe (#74 / #75 / #77)

Pod FastAPI ─/metrics─► Prometheus ─┐
        │                            ├─► Grafana (lit les deux) ─► toi
        └─stdout─► Alloy ─► Loki ────┘
                                     Prometheus ─► PrometheusRule ─► Alertmanager ─► Slack

Les concepts à maîtriser

Pilier Comment ça circule Le pourquoi
Métriques Prometheus va chercher (pull) /metrics en interne via le ClusterIP /metrics n'est pas public (#81, ADR 018) : il fuiterait routes/latences ; le scrape est interne
Logs Alloy (DaemonSet) ramasse les logs des pods et les envoie (push) à Loki Alloy remplace Promtail (déprécié) ; labels low-cardinality pour ne pas exploser la mémoire
Visualisation Grafana lit Prometheus + Loki via des datasources la vitrine, c'est Grafana, pas /metrics brut
Alerting une PrometheusRule passe Pending puis Firing, Alertmanager route vers Slack Alertmanager groupe / route / inhibe ; une alerte se déclenche dans Prometheus, Alertmanager décide quoi en faire

Le sens des flèches est un vrai concept : Prometheus tire les métriques (pull), Alloy pousse les logs (push). C'est une différence de conception entre métriques et logs, pas un détail.

Voir Observabilité et Alerting.


Transverse : l'infra (Terraform) et la sécurité

Terraform : persistent vs ephemeral

Couche Contient Durée de vie
persistent RDS PostgreSQL, ECR, secrets (Secrets Manager) dure dans le temps
ephemeral le cluster EKS et son réseau monté/détruit chaque jour (coût)

C'est pour ça que « l'infra est éteinte » n'empêche pas de livrer : on écrit la recette dans Git, ArgoCD l'applique au prochain démarrage du cluster. Le séparé persistent/ephemeral est un choix de coût (un cluster allumé H24 coûte cher, une base et un registre, non).

La sécurité en couches (defense in depth)

  • Réseau : NetworkPolicy default-deny + règles ciblées (#55), enforced par le VPC CNI.
  • Namespace : Pod Security Admission en mode restricted.
  • Image : multi-stage Python 3.12-slim, scannée Trivy (0 HIGH), pinnée par digest (ADR 011).
  • IaC : tfsec sur le Terraform (0 HIGH en CI).
  • Accès : RBAC least-privilege pour le user CI (il ne peut pas patcher un objet cluster-scoped), IRSA scopé aux bons ARN.

« Defense in depth » : aucune couche n'est censée tout arrêter seule. Si une cède, la suivante limite la casse. C'est l'angle à donner, pas une liste d'outils.


Refaire le schéma (cahier des charges du drawio)

Quand tu reprendras le drawio (docs/architecture.drawio, encore au snapshot Sprint 3), voici ce qu'il doit représenter pour être à jour. À cocher :

Flux de livraison (à corriger) :

  • [ ] Retirer le kubectl apply -k k8s/base/ (push-based, périmé depuis #72).
  • [ ] Ajouter le nœud ArgoCD dans le cluster.
  • [ ] Tracer : CI ─(write-back tag)─► Git ─(watch/sync)─► ArgoCD ─(reconcile)─► pod. Plus aucune flèche CI ─► cluster directe.
  • [ ] Garder : build (kaniko) ─► scan (Trivy) ─► push image vers ECR.

Observabilité (à ajouter en nœuds réels, plus en encart « planned ») :

  • [ ] Prometheus ◄─(scrape /metrics interne)─ FastAPI.
  • [ ] Alloy (DaemonSet) ◄─ stdout FastAPI, ─(push)─► Loki.
  • [ ] Grafana ─(datasource)─► Prometheus + Loki, exposé via le Gateway.
  • [ ] (optionnel) Alertmanager ─► Slack.

Trafic (déjà globalement bon, à vérifier) :

  • [ ] NLB (pas Classic ELB) devant Envoy Gateway.
  • [ ] Cert wildcard *.devopsyouss.com au listener HTTPS.

Forme :

  • [ ] Titre « DevSecOps EKS — Sprint 4 ».
  • [ ] Export PNG via la skill diagram-export une fois le .drawio à jour.

Le diagram-as-code (docs/diagrams/architecture.py) est déjà à jour avec tout ça : tu peux t'en servir de référence visuelle pour repositionner les nœuds du drawio.