Aller au contenu

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-postgresql partagé (database woodpecker).
  • 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: 10Gi par 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 :

cd .woodpecker/
mv 08-deploy-netcup.yml.disabled 08-deploy-netcup.yml

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

openssl rand -hex 32

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

# helm/examples/values-dev.yaml (ou ton overlay)
akko-woodpecker:
  enabled: true

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 dans helm/akko/charts/akko-woodpecker/values.yaml.
  • agent secret mismatch — l'agent et le serveur ont des WOODPECKER_AGENT_SECRET diffé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-postgresql ne soit prêt. Bump le initialDelaySeconds du 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 notify built-in).
  • [ ] Endpoint metrics — Woodpecker expose des metrics Prometheus sur /metrics ; ajouter un ServiceMonitor.

Voir aussi