La plateforme Socles DevOps
Une Internal Developer Platform GitOps : tu pushes du code,
la plateforme construit, scanne, versionne, promeut et déploie — jusqu'en production —
sans kubectl apply manuel. Cette page explique comment tout s'articule et
comment brancher un nouveau projet dessus.
1 Vue d'ensemble
Le dossier socles-devops/ n'est pas un mono-repo : c'est un agrégat de
11 dépôts Git indépendants hébergés sur GitLab, rangés en quatre sous-groupes.
La plateforme fait circuler un artefact (image + chart Helm) depuis le code applicatif
jusqu'au cluster, en passant par une chaîne d'outils bien précise.
2 Les briques & les dépôts
Quatre sous-groupes GitLab sous gitlab.com/socles-devops :
Components/ CI réutilisable
Templates GitLab CI/CD versionnés, consommés via include: - component:.
code— code-ruff, code-semgrepsecurity— gitleaks, trivy-fs, trivy-imageinfrastructure— terraform-plan/apply/validate/destroydeployments— deploy-argocd/helm/kube/traefik, update-gitops
infra/ socle
terraform— serveurs, réseau, firewall Hetzner (dev/prod)ansible— k3s, argocd, traefik, wireguardargocd— desired-state GitOps (ApplicationSets, Kargo)
projects/ apps métier
personal-site— référence GitOps complète (front + back + Kargo)emma-website— CI-only, hors GitOps (voir §7)map-platform— cette page 👋
templates/ scaffolds
fast-api-project— squelette backend FastAPI + frontendsample_gitlab— squelette de config GitLab
BUILD_TAG = <CI_PIPELINE_IID>.<short_sha> (ex. 142.87a5038e).
L'IID est un entier strictement croissant par projet : il garantit que le tri
semver du chart et la stratégie NewestBuild de Kargo sur les images donnent
toujours le même ordre. Un SHA seul n'a aucun ordre fiable.
3 Du commit au déploiement en prod
Le parcours réel, avec les vrais noms (exemple personal-site) :
-
Commit sur
mainUn merge dans
projects/personal-sitedéclenche le pipeline GitLab CI. -
CI — security → lint → test → build
Les stages consomment les
Components/:security-gitleaks,security-trivy-fs,code-ruff,code-semgrep, testspytest,helm lint. -
Build & push vers Harbor
Images poussées vers
harbor-dev.zephyr-gestion.fr/library/personal-site-{frontend,backend}:<IID>.<sha>, chart Helm empaqueté et poussé en OCI versoci://harbor-dev.../library/personal-site:<major.minor.IID>. Puissecurity-trivy-imagescanne les images (bloquant sur CRITICAL). -
Kargo Warehouse détecte le freight
Le
Warehousepersonal-site s'abonne au chart OCI et aux deux images (NewestBuild, en excluantlatest). Un nouveau freight apparaît. -
Stage
dev— auto-promotionautoPromotionEnabled: true. Kargo met à jour laversiondansenvironments/dev/applicationsets/projects-helm.yaml(repoinfra/argocd) et ouvre une MR. Aucun merge automatique. -
Stage
prod— manuelautoPromotionEnabled: false. Sur promotion, Kargo réplique le chart et les images deharbor-devversharbor(prod), puis ouvre une MR surenvironments/prod/applicationsets/projects-helm.yaml. -
ArgoCD synchronise
Une fois la MR mergée, la
root-app→ l'ApplicationSetprojects-helmresync et déploie la nouvelle version du chart sur le cluster. Fin du voyage.
personal-site utilise
Kargo. Mais le Component deployments/update-gitops (promotion GitOps
par MR directement depuis la CI) existe aussi et n'est pas branché ici. À standardiser pour
éviter la confusion « lequel fait foi ? ».
4 ArgoCD & ApplicationSets
Pattern App-of-Apps : bootstrap/<env>/root-app.yaml pointe vers
environments/<env>/applicationsets/. Chaque ApplicationSet est une
liste statique d'éléments avec un syncWave.
| ApplicationSet | Applications (syncWave) | Source |
|---|---|---|
infra-helm | cert-manager (0), traefik (2), headlamp (3), harbor (11), kargo (12) | charts Helm publics + values du repo |
infra-manifests | ClusterIssuer, config ArgoCD, ingress | manifests Git |
observability-helm | monitoring, loki, tempo, otel-collector/operator | charts Helm |
security-helm | sealed-secrets | chart Helm |
projects-manifests | kargo-personal-site (13) | manifests Git (config Kargo) |
projects-helm | personal-site (20) | chart OCI Harbor + values (multi-source $values) |
Convention : dev et prod ont chacun leurs ApplicationSets et peuvent porter
des versions différentes. Jamais de latest : on promeut des versions explicites.
5 Promotion Kargo
Kargo orchestre la remontée d'un freight à travers des Stages :
Warehouse
S'abonne au chart OCI + images. Stratégie NewestBuild, exclut ^latest$.
Stage dev
auto Met à jour la version dans l'ApplicationSet dev, ouvre une MR.
Stage prod
manuel Réplique dev→prod Harbor, met à jour l'ApplicationSet prod, ouvre une MR.
Les credentials Kargo (git + Harbor) sont des *.sealed.yaml (Sealed Secrets),
chiffrés pour le contrôleur du cluster. Ils ne vivent jamais en clair dans Git.
6 Ajouter un nouveau projet
Modèle : personal-site. Voici le chemin complet pour brancher un projet
my-app de bout en bout. (Ce dépôt map-platform a suivi exactement ces étapes.)
6.1 — Structure du dépôt applicatif
projects/my-app/
├── frontend/ # + backend/ si API (voir personal-site)
│ ├── index.html
│ ├── Dockerfile # nginx non-root, EXPOSE 8080
│ └── nginx.conf
├── helm/my-app/
│ ├── Chart.yaml # name: my-app, version: 0.1.0
│ ├── values.yaml
│ └── templates/ # deployment, service, ingress, _helpers.tpl
├── .gitlab-ci.yml # include des Components/
├── .gitlab/ # templates issue/MR
├── CONTRIBUTING.md · README.md · .gitleaks.toml · .gitignore
6.2 — Brancher la CI sur les Components
include:
- component: $CI_SERVER_FQDN/socles-devops/Components/security/security-gitleaks@1
- component: $CI_SERVER_FQDN/socles-devops/Components/security/security-trivy-fs@1
- component: $CI_SERVER_FQDN/socles-devops/Components/code/code-ruff@1
# + build/push image, helm package/push, trivy-image
variables:
HARBOR_REGISTRY: "harbor-dev.zephyr-gestion.fr"
HARBOR_PROJECT: "library"
BUILD_TAG: "${CI_PIPELINE_IID}.${CI_COMMIT_SHORT_SHA}"
Utilise la ligne majeure @1 (comme personal-site), pas des tags figés anciens.
6.3 — Déclarer l'app dans ArgoCD (repo infra/argocd)
Créer les values environments/dev/apps/values/my-app.yaml puis ajouter un élément dans environments/dev/applicationsets/projects-helm.yaml :
- name: my-app
namespace: my-app
syncWave: "21"
chart: my-app
version: 0.1.0-<short-sha> # Kargo la mettra à jour ensuite
valuesFile: environments/dev/apps/values/my-app.yaml
6.4 — Config Kargo (optionnel mais recommandé)
Créer environments/dev/manifests/kargo/my-app/ (project, project-config, warehouse, stage-dev, stage-prod, namespace) et référencer le dossier dans projects-manifests.yaml. Calquer sur kargo/personal-site/.
6.5 — Secrets applicatifs
task du repo infra/argocd
(Sealed Secrets), et on référence le Secret via valueFrom.secretKeyRef dans les values.
- Dépôt créé sous
projects/my-app, structure conforme .gitlab-ci.ymlbranché sur les Components@1- Images + chart poussés vers Harbor au merge sur
main - Values + élément d'ApplicationSet ajoutés (dev, puis prod)
- Kargo warehouse + stages configurés
- Secrets scellés, jamais en clair
- Tout passe par MR — jamais de push direct sur
main
7 Cas emma-website : CI-only, hors GitOps
emma-website illustre un mode alternatif assumé : le projet est
couvert par la CI mais n'est pas onboardé sur la chaîne GitOps. C'est un choix
délibéré, utile à connaître pour ne pas croire qu'il est déployé comme personal-site.
| Aspect | personal-site (onboardé) | emma-website (CI-only) |
|---|---|---|
| Structure | backend/ + frontend/ | app/ (layout template fast-api) + frontend/ |
| Components CI | ligne majeure @1 | tags figés @v1.3.0, @v1.5.0 |
| Harbor | dev puis réplication vers prod | pousse directement sur Harbor prod |
| ArgoCD | dans projects-helm | absent de tout ApplicationSet |
| Kargo | warehouse + stages | aucune config |
Pour l'onboarder un jour : aligner la structure sur backend/+frontend/,
repasser les Components en @1, ajouter values + ApplicationSet + Kargo (cf. §6).
8 Points de vigilance & anti-patterns
Écarts réellement observés entre l'état actuel et les bonnes pratiques prod. Aucun secret n'est reproduit — seuls les faits de configuration.
Le firewall Hetzner de prod ouvre à 0.0.0.0/0 (tout Internet) :
SSH (22), API Kubernetes (6443) et la plage
NodePort (30000-32767) — et n'a aucune règle WireGuard.
Le dev, lui, n'expose ni SSH ni 6443 et force le passage par le VPN (51820).
Reco : restreindre SSH & 6443 de prod au sous-réseau WireGuard, ouvrir 51820 sur prod, fermer la plage NodePort (le trafic passe par Traefik/LB sur 80/443).
argocd-dev.zephyr-gestion.fr et harbor-dev.zephyr-gestion.fr sont
servis par un Ingress Traefik/LoadBalancer accessible depuis Internet (TLS Let's Encrypt,
mais sans restriction IP ni VPN). Seule l'app personal-site dev est protégée par un Middleware BasicAuth.
Reco : placer les UIs d'admin (ArgoCD, Harbor) derrière WireGuard ou un Middleware d'auth/IP-allowlist Traefik, comme c'est déjà fait pour personal-site dev.
latest poussé sur mainLa CI tague aussi les images en latest sur main. Kargo doit
explicitement l'exclure (ignoreTagsRegexes: ^latest$) pour ne pas le sélectionner
comme « plus récent ». Un tag qu'il faut activement neutraliser est une source de bugs.
Reco : arrêter de pousser latest, ne garder que
le tag immuable <IID>.<sha>.
Kargo (utilisé par personal-site) et le Component update-gitops (promotion par
MR depuis la CI) coexistent. Deux façons de faire la même chose = dette cognitive.
Reco : choisir Kargo comme standard, documenter update-gitops
comme déprécié ou réservé à un cas précis.
emma-website utilise une structure et des versions de Components différentes de
personal-site. Acceptable tant que c'est un choix documenté (§7), mais à converger
si le projet doit un jour être déployé par la plateforme.