Woodpecker CI — CI/CD self-hosted¶
AKKO embarque un serveur Woodpecker self-hosted (Apache-2.0, OSS) qui remplace GitHub Actions. Les pipelines tournent comme pods sur le même cluster k3s que le reste de la plateforme — pas de runners externes, pas de limites de billing, pas d'erreurs « job not started » quand le free tier GitHub est épuisé.
| Woodpecker (actuel) | GitHub Actions (legacy) | |
|---|---|---|
| Coût | 0 € | $0.008 / minute Linux après free tier |
| Concurrence | scheduler k3s | imposé par GitHub |
| Stockage | PVC local-path | cache GHA |
| Visibilité | ci.<domain> (gated par oauth2-proxy) |
github.com |
| Souveraineté | 100 % on-prem | hébergé externe |
Architecture¶
Repo GitHub ──webhook──► serveur Woodpecker (akko-woodpecker-server, port 8000)
│
│ gRPC :9000 (secret partagé)
▼
Agent Woodpecker (2 replicas)
│
│ API k8s (Role namespacé)
▼
Pods de pipeline (un par step)
│
│ PVC /woodpecker (par build)
▼
Logs streamés vers l'UI serveur
- Serveur : UI web, API REST, OAuth GitHub, scheduler. Backé par le
cluster
akko-postgresqlpartagé (databasewoodpecker). - Agent : pull le travail via gRPC, crée les pods de pipeline dans le même namespace via un Role namespacé (zéro privilège cluster-wide).
- Pods de pipeline : éphémères, un par step. Montent un PVC par build
(
workspace.pvcSize: 10Gipar défaut) pour que tous les steps d'un pipeline partagent le même workspace/woodpecker/<repo>/<branch>.
Layout dans ce repo¶
.woodpecker/ # auto-découvert par le serveur
├── 00-validate.yml # ACTIF — helm lint + template --strict + grep changeme
├── 01-helm-lint.yml # ACTIF — helm lint (dev + rendered)
├── 02-helm-template.yml # ACTIF — helm template + kubeconform
├── 03-no-hardcoding.yml # ACTIF — pas d'IP/domaines hardcodés (R01)
├── 04-secrets.yml # ACTIF — gitleaks + pas de mots de passe en clair
├── 05-doc-consistency.yml # ACTIF — nav mkdocs, bilingue, couverture services
├── 06-trivy.yml # ACTIF — scan Trivy CVE CRITICAL (14 images)
├── 07-trino-ai-plugin.yml # ACTIF — build Maven + tests unitaires
├── 08-deploy-netcup.yml.disabled # DÉSACTIVÉ — deploy vers Netcup (activer manuellement)
├── 09-tests.yml # ACTIF — pytest + Playwright smoke
├── 10-aden-tests.yml # ACTIF — tests unitaires ADEN + seuil couverture
└── 12-post-deploy-tests.yml.disabled # DÉSACTIVÉ — tests E2E post-deploy (dépend de 08)
helm/akko/charts/akko-woodpecker/ # sub-chart Helm qui déploie serveur + agent
Le préfixe numérique donne un ordre stable dans le dashboard Woodpecker ; tous les pipelines tournent en parallèle par défaut — le préfixe est purement cosmétique.
Activer un pipeline désactivé¶
Renommer le fichier pour retirer .disabled :
Committer et pousser. Woodpecker auto-découvre tous les fichiers .yml dans .woodpecker/.
Matrice des pipelines¶
| Pipeline | Déclencheur | Gate | Sur PR ? |
|---|---|---|---|
00-validate |
changements helm/** |
lint + template + changeme | Oui |
01-helm-lint |
changements helm/** |
lint dev + rendered | Oui |
02-helm-template |
changements helm/** |
template + kubeconform | Oui |
03-no-hardcoding |
changements helm/** |
grep patterns interdits | Oui |
04-secrets |
tout push / PR | gitleaks + scan plaintext | Oui |
05-doc-consistency |
tout push / PR | build mkdocs, bilingue | Oui |
06-trivy |
changements docker/** |
scan CVE CRITICAL | Oui |
07-trino-ai-plugin |
docker/trino-ai-functions/** |
test Maven + package | Oui |
09-tests |
changements tests/** |
pytest + Playwright | Oui |
10-aden-tests |
docker/aden/** |
tests unitaires + 70% couverture | Oui |
08-deploy-netcup |
push sur main uniquement | helm upgrade (secrets requis) | Non (désactivé) |
12-post-deploy-tests |
après succès de 08 | E2E health + UI | Non (désactivé) |
Activer sur un cluster¶
1. Créer une OAuth App GitHub¶
GitHub → Settings → Developer settings → OAuth Apps → New OAuth App
| Champ | Valeur |
|---|---|
| Application name | AKKO Woodpecker (<env>) |
| Homepage URL | https://ci.<domain>/ |
| Authorization callback URL | https://ci.<domain>/authorize |
Noter le Client ID + le Client Secret.
2. Générer le secret partagé agent¶
3. Ajouter à helm/examples/values-dev-secrets.yaml (gitignored)¶
akko-woodpecker:
agent:
secret: <secret-partagé-agent>
github:
client_id: <client-id-oauth-app>
client_secret: <client-secret-oauth-app>
4. Activer le sub-chart¶
5. Helm upgrade¶
helm upgrade akko helm/akko/ -n akko \
-f helm/examples/values-dev.yaml \
-f helm/examples/values-domain.yaml \
-f helm/examples/values-dev-secrets.yaml \
--set-file akko-keycloak.realm.data=helm/examples/realm-domain.json
6. Ajouter le webhook GitHub¶
Après le premier login OAuth, Woodpecker imprime l'URL du webhook —
la coller dans le repo GitHub (Settings → Webhooks → Add webhook).
Content type application/json, secret = le secret partagé agent.
7. Ajouter les secrets de deploy dans l'UI Woodpecker¶
Le pipeline 08-deploy-netcup.yml lit deux secrets depuis le store
Woodpecker (Repo Settings → Secrets) :
| Secret | Valeur |
|---|---|
kubeconfig |
contenu de /etc/rancher/k3s/k3s.yaml (le kubeconfig in-cluster que l'agent utilisera) |
akko_domain |
hostname brut, ex. 159.195.77.208.nip.io |
Les marquer disponibles pour les events push uniquement (pas pull requests) pour qu'une PR malveillante ne puisse pas déployer en prod.
Migrer un workflow depuis GitHub Actions¶
Le schéma Woodpecker est suffisamment proche de GHA pour qu'un port 1:1 soit généralement trivial. Les deux différences principales :
| GitHub Actions | Woodpecker |
|---|---|
jobs.<id>.steps.[].uses: actions/checkout@v4 |
implicite — chaque pipeline reçoit un git clone frais |
runs-on: ubuntu-latest |
N/A — chaque step choisit sa propre image: (Docker) |
env: (niveau job) |
environment: (niveau step) |
secrets.MY_SECRET |
secrets: [my_secret] + wiring from_secret: |
if: github.ref == 'refs/heads/main' |
bloc when: au top du fichier pipeline |
Dépannage¶
- Pipeline bloqué « Pending » — l'agent a atteint
WOODPECKER_MAX_WORKFLOWS=4. Soit attendre, soit bump le nombre de replicas danshelm/akko/charts/akko-woodpecker/values.yaml. agent secret mismatch— l'agent et le serveur ont desWOODPECKER_AGENT_SECRETdifférents. Re-roll : éditer le Secret Helm et redémarrer les deux deployments.github oauth: invalid client— vérifier que le callback URL de l'OAuth App GitHub correspond exactement àhttps://ci.<domain>/authorize.postgres connection refused— le serveur démarre avant qu'akko-postgresqlne soit prêt. Bump leinitialDelaySecondsdu readinessProbe ou s'appuyer sur le hook post-install pour attendre.
Roadmap¶
- [ ] Approval gates style OPA pour
08-deploy-netcup(clic manuel d'un akko-admin dans l'UI avant que le helm upgrade ne tourne). - [ ] Notifications Slack sur échec (Woodpecker a un plugin
notifybuilt-in). - [ ] Endpoint metrics — Woodpecker expose des metrics Prometheus
sur
/metrics; ajouter un ServiceMonitor.
Voir aussi¶
- CI GitHub Actions (legacy) — d'où on a migré
- Backup & DR — la DB Woodpecker vit dans
akko-postgresql, couverte par le CronJobpg_dumpquotidien (voir Observabilité et SLO) - Docs upstream : https://woodpecker-ci.org/