Dagger : CI as code portable
À la fin de ce tutoriel, vous saurez écrire un pipeline CI en Python avec Dagger, le rejouer à l’identique sur laptop et dans GitHub Actions, cacher les couches (BuildKit), et esquisser un publish ECR en
ca-central-1. Angle DEH : un module versionné, runners = wrappers minces, cleanup lab obligatoire.Niveau : Intermédiaire · Temps estimé : 55–75 min · Versions cibles : Dagger CLI 0.18+ · SDK Python 3.12 · Docker Engine · GitHub Actions (
dagger/dagger-for-github) · AWS CLI v2 · Dernière vérification : 2026-09-11 · Region :ca-central-1Slug :
wow-dagger-ci· Série : WOW (39/50) · Mot-clé SEO : dagger ci · Publish : READY (feu vert Maître — push centralisé)← Précédent : Buildkite agents · → Suivant : Nix flakes / devshells · Aussi : GitHub Actions reusable · DevSecOps pipeline · Trivy en CI · GHA OIDC AWS
Prérequis
- Docker Engine local (l’Engine Dagger orchestre des conteneurs)
- Python 3.12+ pour lire le module (SDK via
dagger init) - Dépôt GitHub pour le wrapper Actions — Git
- Compte AWS lab (
AWS_PROFILE=lab) si publish ECR — Démarrer avec AWS - Bases CI — Buildkite · Jenkins
Coût estimé : 0 € en local. ECR lab : < 1 € (repo vide quelques heures en ca-central-1 puis delete). Pas de NAT, EKS, runners payants.
export AWS_PROFILE=lab
export AWS_DEFAULT_REGION=ca-central-1
docker info >/dev/null
aws sts get-caller-identity
Ce que nous allons construire
Dagger CI as code (WOW 39/50) — ca-central-1
├── Pourquoi Dagger (code > YAML, local = CI)
├── Architecture : CLI → Engine → Functions
├── Install CLI + dagger init --sdk=python
├── Mini-app + functions lint / test / build
├── dagger call en local (fail fast)
├── Wrapper GitHub Actions mince
├── Sketch ECR ca-central-1 + OIDC
└── Anti-patterns + quiz + FAQ
(Schéma — alt : « Module Dagger Python : lint/test/build en conteneurs ; laptop et GitHub Actions appellent les mêmes functions ; publish optionnel ECR ca-central-1 ».)
Étape 1 — Pourquoi Dagger plutôt qu’un YAML CI
Le push-and-pray (commit, 8 min, typo YAML, recommencer) coûte cher. GitHub Actions, GitLab, Jenkins, Buildkite décrivent surtout où ça tourne. La logique (lint, pytest, image, scan) dérive entre laptop et runners.
Dagger inverse ça : pipeline = module (Go, Python, TypeScript) + functions typées. L’Engine (BuildKit) exécute chaque step en conteneur. dagger call test --source=. sur votre machine est le job CI.
| Critère | YAML CI | Dagger |
|---|---|---|
| Langage | YAML + scripts | Python / Go / TS |
| Repro locale | Approximative | Identique (dagger call) |
| Cache | Artefacts / actions | Content-addressed |
| Portabilité | Syntaxe vendor | Un module, N wrappers |
DEH : GitHub/GitLab/Buildkite pour triggers, PR, secrets d’org. La recette vit dans Dagger — même esprit que Conftest en CI : code reviewable.
Étape 2 — Architecture : CLI, Engine, module
[ Laptop / GitHub Actions / GitLab ]
│ dagger call <fn> --source=.
▼
[ Dagger CLI ] → GraphQL → [ Engine / BuildKit ]
├── lint (python:3.12-slim + ruff)
├── test (pytest)
├── build (image app)
└── publish → ECR ca-central-1 (option)
- CLI : client vers l’Engine.
- Engine : conteneurs + dédup des couches.
- Module :
dagger.json+ SDK ;dagger call --helpliste les functions. - Wrapper CI : checkout +
dagger/dagger-for-github. Zéro logique métier dans le YAML.
Dagger Cloud (traces) est optionnel. Lab : Engine local, pas d’abonnement.
Étape 3 — Installer la CLI
curl -fsSL https://dl.dagger.io/dagger/install.sh | BIN_DIR="${HOME}/.local/bin" sh
export PATH="${HOME}/.local/bin:${PATH}"
dagger version
Attendu : 0.18+. Docker doit répondre (docker ps). Sans Engine, dagger call échoue — voulu.
En CI, pinnez la version de l’action. En local, dagger version doit matcher.
Étape 4 — Mini-app + dagger init
mkdir -p ~/deh-dagger-lab/tests && cd ~/deh-dagger-lab
git init -q
cat > app.py << 'EOF'
"""Mini-app lab DEH — ne pas copier en prod."""
def ping() -> str:
return "ok"
if __name__ == "__main__":
print(ping())
EOF
cat > tests/test_app.py << 'EOF'
from app import ping
def test_ping():
assert ping() == "ok"
EOF
printf 'pytestn' > requirements.txt
dagger init --sdk=python --name=ci
dagger develop
dagger call --help
init pose dagger.json + package Python. develop synchronise le SDK. Les functions utiles arrivent à l’étape 5.
Étape 5 — Functions lint / test / build
Remplacez le squelette (src/ci/__init__.py ou src/main.py selon le scaffold — suivez init) :
import dagger
from dagger import dag, function, object_type
@object_type
class Ci:
def _py(self, source: dagger.Directory) -> dagger.Container:
return (
dag.container()
.from_("python:3.12-slim")
.with_directory("/src", source)
.with_workdir("/src")
)
@function
async def lint(self, source: dagger.Directory) -> str:
return await (
self._py(source)
.with_exec(["pip", "install", "--quiet", "ruff"])
.with_exec(["ruff", "check", "."])
.stdout()
)
@function
async def test(self, source: dagger.Directory) -> str:
return await (
self._py(source)
.with_exec(["pip", "install", "--quiet", "-r", "requirements.txt"])
.with_exec(["pytest", "-q"])
.stdout()
)
@function
def build(self, source: dagger.Directory) -> dagger.Container:
return (
self._py(source)
.with_exec(["pip", "install", "--quiet", "-r", "requirements.txt"])
.with_default_args(["python", "app.py"])
)
source: Directory: le repo monté, pas un checkout magique vendor.- Pin d’image en prod (
python:3.12-slim@sha256:…). - Pas de secrets dans le module : type
dagger.Secretà l’étape 7.
Étape 6 — Exécuter en local (le vrai CI)
dagger call lint --source=.
dagger call test --source=.
dagger call build --source=.
dagger call build --source=. export --path=./hello.tar
Cassez ping() (return "ko"), relancez test : rouge en ~20 s, sans push. Revert. 2ᵉ run : cache Engine, plus vite.
Contrat WOW : le laptop est un runner. Vert ici ⇒ le wrapper Actions n’appelle que la même function.
Étape 7 — Wrapper GitHub Actions (mince)
.github/workflows/ci.yml :
name: ci
on: [push, pull_request]
jobs:
dagger:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v4
- uses: dagger/dagger-for-github@v8
with:
version: "0.18.12"
verb: call
args: test --source=.
Dupliquez le step pour lint puis build (même version). GitLab : script: dagger call test --source=.. Jenkins / Buildkite : un step dagger call. La recette ne bouge pas.
Sketch publish ECR ca-central-1
aws ecr create-repository --repository-name deh-lab/dagger-hello
--region ca-central-1 --image-scanning-configuration scanOnPush=true
aws ecr get-login-password --region ca-central-1
OIDC : GitHub Actions OIDC AWS — rôle court, pas de clés longues. Passez le password comme Secret (--password=env:ECR_PASSWORD). Tag : ACCOUNT.dkr.ecr.ca-central-1.amazonaws.com/deh-lab/dagger-hello:${GITHUB_SHA}.
aws ecr delete-repository --repository-name deh-lab/dagger-hello
--region ca-central-1 --force
rm -f hello.tar
Étape 8 — Cache, secrets, modules
- Cache : l’Engine hash
with_exec+ fichiers.pip installinchangé = gratuit au 2ᵉcall. Ne prunez pas « pour voir ». - Secrets :
dagger.Secret; pas d’echo/set -x. Tokens,AWS_*: org/SSM, hors Git. - Modules distants :
dagger -m github.com/org/mod@vX call …— pinnez le tag. - Scan : Trivy après
build— DevSecOps.
Étape 9 — Anti-patterns
Double source YAML et Dagger ; latest partout ; clés IAM dans env: ; region us-east-1 ; Engine partagé dirty ; image root en prod ; ECR / hello.tar oubliés.
Erreurs fréquentes
| Erreur | Impact | Correction |
|---|---|---|
| Docker daemon down | dagger call KO |
docker info d’abord |
| Function introuvable | CLI confuse | dagger develop + --name=ci |
| Vert local, rouge CI | Source mal monté | --source=. après checkout |
| Cache « cassé » | Minutes + $ | Pas de docker system prune -a |
| Password en args | Fuite logs | dagger.Secret / env:ECR_PASSWORD |
| Region us-east-1 | Drift DEH | Forcer ca-central-1 |
| YAML Actions 200 lignes | Logique hors module | Wrapper mince |
Check-list DEH
- [ ]
dagger version0.18+ ; Docker OK - [ ] Module
ci:lint/test/build - [ ]
dagger call test --source=.rouge puis vert sans push - [ ] Workflow = wrappers
dagger callpinés - [ ] Secrets hors Git ; OIDC si ECR
- [ ] ECR / tar détruits ; region
ca-central-1
Quiz (5 questions)
1. Dagger sert surtout à :
– A. Remplacer Git par un daemon
– B. Écrire le pipeline en code, local = CI
– C. Imposer un SaaS payant
2. YAML GitHub Actions idéal :
– A. 400 lignes de run:
– B. Checkout + dagger call (wrapper mince)
– C. Trois docker build copiés
3. Qui exécute les steps ?
– A. Un runner Windows obligatoire
– B. Le Dagger Engine (conteneurs / BuildKit)
– C. SSH vers prod
4. Region lab ECR DEH :
– A. us-east-1
– B. ca-central-1
– C. eu-west-3
5. Mot de passe registry :
– A. En clair dans args:
– B. dagger.Secret / env:ECR_PASSWORD
– C. Dans le README
Réponses : 1‑B · 2‑B · 3‑B · 4‑B · 5‑B
FAQ
Dagger remplace GitHub Actions ?
Non. Actions / GitLab / Buildkite / Jenkins déclenchent. Dagger exécute la recette. Vous gardez PR checks, protections de branche, OIDC d’org.
Python, Go ou TypeScript ?
Celui que l’équipe review. Python = lisible DevOps. Go = types stricts. Un SDK par module.
Faut-il Dagger Cloud ?
Non pour ce lab. Cloud = traces d’équipe. Engine local suffit.
Self-hosted runners ?
Oui : Buildkite ou GHA self-hosted avec Docker. Dagger = portabilité ; l’agent = VPC ca-central-1.
Cache laptop ↔ CI ?
Pas partagé (machines différentes). Chaque Engine cache chez lui. Gain : même graphe, hits dès le 2ᵉ run ici.
Nix vs Dagger ?
Nix flakes fige le devshell. Dagger fige le pipeline. Complémentaires.
Par où commencer en équipe ?
Un module lint+test, wrapper Actions, pin de version. Puis build / publish / Trivy. Pas 12 functions jour 1.
Pour aller plus loin
- Buildkite agents · Nix flakes
- GitHub Actions reusable · OIDC AWS
- DevSecOps · Trivy · Conftest CI
- Jenkins · Docker images · Démarrer avec AWS
Maillage série WOW
| ← Précédent | Buildkite : agents self-hosted |
| → Suivant | Nix flakes : dev shells reproductibles |
| Aussi | GHA reusable · OIDC AWS · DevSecOps · Trivy · Conftest · Jenkins |
Meta publication (SEO)
- Title SEO : Dagger CI as code : pipelines portables Python (guide FR)
- Meta description : Dagger : CI as code portable. Module Python, dagger call local = CI, wrapper GitHub Actions, publish ECR ca-central-1, cache, secrets, FAQ et quiz DEH.
- Focus keyword : dagger ci
- Secondary : Dagger CI as code, dagger call, Dagger Python SDK, GitHub Actions Dagger, ECR ca-central-1
- Image :
assets/web/devopelastichayway/cover-wow-dagger-ci-1200x630.webp(à générer) - Catégorie : WOW / CI-CD · Niveau : Intermédiaire
- URL cible : https://devopelastichayway.com/tutoriels/wow-dagger-ci/
- Post live : N/A (nouveau) · slug
wow-dagger-ci· Publish : READY (feu vert Maître — push WP-CLI centralisé, parent/tutoriels/5463)
Pour aller plus loin — hubs live
Retour parcours Catalogue Tutoriels — hub de la série et leçons sœurs.