Pipeline CI/CD d'AKKO — Woodpecker + Buildah + Harbor¶
Comment les changements passent d'un git push à un pod en production
sur le cluster AKKO.
Avant/après en une ligne¶
Avant : SSH sur Netcup, git pull, lancer manuellement
bash helm/scripts/deploy-netcup-full.sh. Aucune trace d'audit, aucun
contrôle pré-merge, aucune preuve que « ce commit a été testé ».
Après : un git push main déclenche automatiquement un pipeline,
13 contrôles tournent sur le changement, Buildah reconstruit 13 images
OCI dans des pods parallèles, les pousse vers Harbor, et fait un
helm upgrade sur le cluster live. GitHub affiche ✓/✗ sur chaque commit.
Vue d'ensemble¶
Développeur
│
│ git push / ouvre une PR
▼
┌──────────────┐ webhook GitHub ┌──────────────────────────┐
│ AKKO-p/AKKO │ ──────────────────► │ Woodpecker server │
│ (GitHub) │ /api/hook │ ci.akko-ai.com │
└──────────────┘ │ (namespace akko sur k3s) │
└──────────────────────────┘
│
un pod par .woodpecker/*.yml
▼
┌─────────────────────────────────────────────────────────┐
│ 13 pipelines de validation (PR + push) │
│ ─────────────────────────────────────────────── │
│ 00-validate helm dep update + scan changeme │
│ 01-helm-lint helm lint (prod + rendered) │
│ 02-helm-template kubeconform sur les manifests │
│ 03-no-hardcoding lint (zéro akko.local dans chart) │
│ 04-secrets gitleaks + grep plaintext │
│ 05-doc-consistency cohérence README/CLAUDE/Chart │
│ 06-trivy scan CVE fs + config │
│ 07-trino-ai-plugin tests Maven plugin Trino │
│ 10-aden-tests pytest + seuil de couverture │
│ 13-np-coverage lint NetworkPolicy │
│ │
│ +2 push-only (creds Harbor, interdits aux PRs) │
│ 11-license-check scan licences syft │
│ │
│ +1 push + manuel (le vrai déploiement) │
│ 08-deploy-netcup 13 builds Buildah + helm upgrade │
│ │
│ +1 manuel-only (nécessite cluster live) │
│ 09-tests pytest + Playwright smoke │
└─────────────────────────────────────────────────────────┘
│ │
✓ tout vert │ │ 08 spécifique
▼ ▼
Statut GitHub │ ┌─────────────────────────┐
check vert │ │ 13 pods de build Buildah│
│ │ chacun push vers Harbor │
│ └─────────────────────────┘
│ │
│ ▼
│ ┌─────────────────────────┐
│ │ step helm-upgrade │
│ │ reuse-values, wait 15m │
│ └─────────────────────────┘
│ │
│ ▼
│ ┌─────────────────────────┐
└────────────► │ k3s pull les nouveaux │
│ digests 2026.04 │
└─────────────────────────┘
Pourquoi Buildah (et pas docker build ni kaniko)¶
k3s sur Netcup tourne sur containerd, pas Docker. L'image
docker:27-cli a le binaire CLI mais aucun daemon à qui parler. Chaque
docker build dans un pod Woodpecker échouait avec
ERROR: Docker daemon is not running.
Monter /var/run/docker.sock n'est pas une option — k3s ne ship que
containerd sur l'hôte, et monter des sockets hôte est une élévation de
privilèges qu'on veut éviter.
Le premier essai utilisait kaniko (builder sans daemon de Google).
Ça marchait techniquement, mais le 2026-04-23 on a découvert que
GoogleContainerTools/kaniko avait été archivé par Google — le
dernier commit était la notice d'archivage du 2025-06-03. Locker AKKO
sur une dépendance non maintenue était inacceptable, donc on a pivoté.
Buildah (Red Hat, Apache 2.0, maintenu activement avec releases toutes les ~3 semaines) est devenu le builder canonique. Il :
- Est un binaire Go compilé statiquement qui lit un Dockerfile et produit une image OCI depuis un pod ordinaire
- Ne nécessite aucun daemon, aucun privilège, aucun mount hôte
- Est le builder par défaut d'OpenShift Pipelines (Tekton) — Red Hat s'engage sur des cycles de support de plusieurs années
- A une compatibilité Dockerfile à 100% (mêmes RUN/COPY/ARG/ENV/HEALTHCHECK que docker build)
Voir akko-technical-map/decisions/ADR-024-buildah-replaces-kaniko.md
(repo de planning privé) pour l'analyse comparative complète
(Buildah vs BuildKit vs Podman vs nerdctl).
Le pipeline de déploiement (08-deploy-netcup) en détail¶
steps:
- detect-changes # écrit /tmp/needs_rebuild
- build-postgres # pod Buildah → push harbor.akko-ai.com/akko/postgres:2026.04
- build-spark # en parallèle avec les autres, 2 agents max
- build-notebook
- build-mlflow
- build-cockpit
- build-trino
- build-ai-service
- build-airflow
- build-dbt
- build-mcp-trino
- build-mcp-openmetadata
- build-docs
- build-catalog-manager
- helm-upgrade # depends_on: tous les build-*
Template de chaque step build-* :
image: quay.io/buildah/stable:v1.43.1
commands:
- 'mkdir -p /tmp/auth'
- 'AUTH=$(printf "%s:%s" "$HARBOR_USERNAME" "$HARBOR_PASSWORD" | base64 | tr -d "\n"); printf ''{"auths":{...}}'' "$AUTH" > /tmp/auth/config.json'
- 'export REGISTRY_AUTH_FILE=/tmp/auth/config.json'
- 'buildah --storage-driver vfs bud --layers --format docker -t <dest> -f <dockerfile> <context>'
- 'buildah --storage-driver vfs push <dest>'
Notes :
--storage-driver vfsévite d'avoir besoin de fuse-overlayfs ou de capabilities kernel — tourne dans un pod PodSecurity-restricted. Plus lent qu'overlay (~20%) mais portable.--layersactive le cache inter-layers pendant un build.--format dockerproduit des images v2 (OCI fonctionne aussi ;dockerest plus largement accepté par les vieux registres).REGISTRY_AUTH_FILE= manière buildah de pointer vers l'auth Harbor, équivalent au~/.docker/config.jsonde docker.
Les secrets qui alimentent tout ça¶
Stockés dans le vault de Woodpecker (pas dans k8s Secrets, pas dans GitHub Actions secrets) :
| Nom | Consommateur | Events |
|---|---|---|
harbor_username |
steps build-*, 11-license-check | push, manuel |
harbor_password |
idem | push, manuel |
kubeconfig |
step helm-upgrade | push, manuel |
akko_domain |
helm-upgrade, 09-tests | push, manuel |
Woodpecker refuse d'injecter tout from_secret: dans les pipelines à
event: pull_request — c'est l'anti-exfiltration par défaut.
Chemin de rebuild / redeploy¶
Automatique (canonique)¶
git push origin main
# → les pipelines 00..13 tournent en parallèle sur push main
# → 08-deploy-netcup build 13 images avec Buildah, push Harbor, fait helm upgrade
Manuel (fallback si CI down ou itération)¶
Le script manuel utilise docker build (toujours fonctionnel sur
l'hôte Netcup qui a Docker installé pour la commodité). Préférer le
chemin automatique.
Hot reload d'un seul service (phase de construction)¶
En phase de développement actif, passer par le pipeline complet de 14
builds + helm upgrade pour un one-liner CSS ou un tweak de
routes_query.py est absurde. Utiliser dev-reload.sh : build local
d'une seule image sur l'hôte Netcup, push avec tag dev, patch de la
Deployment live.
ssh root@159.195.77.208
cd /root/akko && git pull
bash helm/scripts/dev-reload.sh cockpit # 30-60 s au lieu de 30-40 min
bash helm/scripts/dev-reload.sh akko-rag # pour un nouveau service
bash helm/scripts/dev-reload.sh ai-service
Utilise un tag dev horodaté (harbor.akko-ai.com/akko/<svc>:2026.04-dev-<ts>)
pour que le tag de prod :2026.04 reste intact. Le prochain helm upgrade
automatique sur un push main remet la Deployment sur le tag propre.
Liste complète : bash helm/scripts/dev-reload.sh (sans argument → aide).
Quand utiliser quel chemin :
| Chemin | Latence | À utiliser quand |
|---|---|---|
dev-reload.sh <svc> |
30 s - 5 min | itération sur UN service, feedback rapide |
git push main → CI |
5-40 min | changement prêt, PR verte, audit trail |
deploy-netcup-full.sh |
30-45 min | CI down, full rebuild nécessaire |
Rollback¶
helm -n akko rollback akko # révision précédente
# OU, pour revenir à une version taguée :
AKKO_TAG=2026.04-stable bash helm/scripts/deploy-netcup-full.sh
Cache de build¶
Deux couches de cache accélèrent les rebuilds :
-
Path filters (voir
.woodpecker/08-deploy-netcup.yml) — un push qui ne touche quedocs/**ne déclenche quebuild-docs+helm-upgrade. Les builds non concernés skippent → -90 % de temps pipeline sur les commits typiques. -
Cache registry Buildah — chaque
buildah budécrit ses couches intermédiaires dansharbor.akko-ai.com/akko/cache-<service>via--cache-toet les relit via--cache-from. Quand un build est inévitable, buildah reprend à la dernière couche valide au lieu de re-exécuter chaqueRUNdepuis zéro. Gain typique sur un changement d'une ligne dans un Dockerfile :
| Image | À froid | Avec cache |
|---|---|---|
| notebook-slim | ~12 min | ~2-3 min |
| notebook-full (FROM slim) | ~35 min | ~4-6 min |
| trino (plugin Maven) | ~10 min | ~2 min |
| cockpit (nginx + HTML) | ~3 min | ~40 s |
Le premier run après l'activation de cette feature est aussi lent qu'un build à froid — les repos cache n'existent pas encore dans Harbor. Buildah tolère un 404 sur --cache-from et peuple le cache via --cache-to à la fin. À partir du run #2, le cache prend le relais.
Les images cache vivent dans des repos Harbor dédiés (akko/cache-*) pour que les tags de prod (akko/<service>:2026.04) restent propres. Politique de rétention recommandée sur cache-* : garder les 5 derniers manifests + GC hebdomadaire.
Dette connue¶
- Trust flag non utilisé : Buildah tourne totalement sans
privilèges — on n'active pas le flag
trusted.volumes. Toute future step qui en aurait besoin doit passer par un ADR. - 09-tests manuel only : smoke tests live qui n'ont de sens
qu'après un déploiement. Vrai chemin =
depends_on: [helm-upgrade]inter-pipeline, pas supporté par Woodpecker v3.4. - Bugs Dockerfile latents : le cache docker cachait des vrais bugs.
Les rebuild-from-scratch les exposent. Pattern à retirer : un
apt-get -y upgradeorphelin entreapt-get updateetapt-get install.
Politique de maintenance des outils¶
Tout builder/outil intégré dans le CI AKKO doit passer un check de
maintenance avant adoption : dernier commit < 3 mois, dernière release
< 6 mois, ≥ 2 mainteneurs actifs, organisation de support claire.
Décisions documentées via ADR. Voir
feedback_verify_tool_maintained.md dans la mémoire de session.
Références¶
.woodpecker/*.yml— les 13 pipelineshelm/scripts/build-images.sh— build local (docker)helm/scripts/deploy-netcup-full.sh— déploiement manuel- Documentation Woodpecker — référence v3.4
- Documentation Buildah —
buildah bud,buildah push