Comprendre la CI Dagger : Easy Mode et Power Mode¶
Ce que vous allez comprendre¶
- Expliquer pourquoi gitrust utilise Dagger plutôt qu'un système CI YAML classique
- Distinguer le « Easy Mode » (
.gitrust-ci.yml) du « Power Mode » (module.dagger/) - Évaluer quand conseiller à vos utilisateurs de passer de l'un à l'autre
Le problème concret¶
Un utilisateur vous signale que sa CI « ne fait pas ce qu'il veut » avec .gitrust-ci.yml. Il a besoin de logique conditionnelle, de dépendances entre jobs, et de construire plusieurs images Docker en parallèle. Devez-vous modifier le moteur CI ou lui dire qu'il doit changer d'approche ?
L'analogie¶
Easy Mode, c'est la recette de cuisine imprimée sur la boîte de gâteau : elle marche pour 95 % des cas, est accessible aux débutants, mais on ne peut pas y ajouter de la fleur d'oranger sans sortir du cadre.
Power Mode, c'est le livre de pâtisserie professionnel : vous écrivez vos propres recettes en code (Go, Python, TypeScript), vous pouvez tout faire, mais il faut savoir pâtisser.
Dagger est l'atelier qui garantit que les deux approches s'exécutent dans exactement le même environnement, reproductible sur n'importe quelle machine.
Le modèle¶
Pourquoi Dagger ?¶
Les systèmes CI YAML classiques (GitHub Actions, GitLab CI) ont un problème fondamental : la logique de pipeline est encodée dans du YAML qui devient vite illisible, non-testable, et non-composable. Dagger a été créé par l'équipe fondatrice de Docker pour résoudre ce problème.
graph LR
subgraph "CI YAML classique"
Y[.github/workflows/ci.yml
GitLab CI / Jenkins]
Y --> E[Exécuté sur runner
CI propriétaire]
E --> R1[Résultat dépend
du runner]
end
subgraph "CI Dagger"
D[Pipeline en code
Go / Python / TS]
D --> DE[Dagger Engine
Docker containers]
DE --> R2[Reproductible
local = CI = prod]
end
Avantages de Dagger pour gitrust : - Reproductibilité : le même pipeline s'exécute identiquement en local et sur le serveur - Isolation : chaque job dans son propre conteneur Docker - Cache automatique : les layers Docker non modifiés ne sont pas reconstruits - Pas de dépendance à un service CI externe (GitHub Actions, etc.)
Easy Mode : .gitrust-ci.yml¶
Le fichier .gitrust-ci.yml est un profil YAML simplifié interprété par le moteur CI générique de gitrust (un module Dagger Python interne à la plateforme).
flowchart LR
A[.gitrust-ci.yml
dans le dépôt] -->|lecture| B[Moteur CI gitrust
module Dagger Python]
B -->|dagger call| C[Dagger Engine]
C --> D[Container isolé
build + test]
D --> E[Résultat → DB + UI]
Structure type :
# .gitrust-ci.yml
pipeline:
name: CI principale
image: rust:1.77-slim
steps:
- name: Vérifier le formatage
run: cargo fmt --check
- name: Linting
run: cargo clippy -- -D warnings
- name: Tests
run: cargo test --workspace
cache:
- path: ~/.cargo/registry
- path: target/
Ce que Easy Mode fait bien : - Build + test + lint pour des projets simples à intermédiaires - Configuration en quelques lignes - Accessible aux utilisateurs sans expertise CI/CD
Limites du Easy Mode : - Pas de logique conditionnelle complexe (si branche = main alors déployer) - Pas de fan-out/fan-in (jobs parallèles avec synchronisation) - Pas d'accès au Daggerverse (bibliothèque de modules Dagger communautaires) - La logique reste dans le YAML de la plateforme, pas dans le code du projet
Power Mode : module .dagger/¶
Quand un dépôt contient un dossier .dagger/, gitrust détecte sa présence et exécute directement le module Dagger natif. La plateforme ne l'interprète pas : elle lance dagger call sur le module du projet.
flowchart LR
A[.dagger/
main.go ou main.py] -->|détecté| B[gitrust CI Worker]
B -->|dagger call -m .dagger/ ci| C[Dagger Engine]
C --> D[Pipeline défini
par l'utilisateur]
D --> E[Résultat → DB + UI]
Ce que Power Mode apporte : - La logique pipeline est du code versionné avec le projet - Tests unitaires des pipelines possibles - Composition via le Daggerverse - Accès à toutes les fonctionnalités Dagger (secrets, services, multi-platform builds) - Aucune dépendance au moteur CI de gitrust pour la logique
Exemple minimal en Go :
// .dagger/main.go
package main
import (
"context"
"dagger.io/dagger"
)
func main() {
ctx := context.Background()
client, _ := dagger.Connect(ctx)
defer client.Close()
rust := client.Container().
From("rust:1.77-slim").
WithMountedCache("/usr/local/cargo/registry", client.CacheVolume("cargo-registry")).
WithDirectory("/src", client.Host().Directory(".")).
WithWorkdir("/src")
rust.WithExec([]string{"cargo", "fmt", "--check"}).
WithExec([]string{"cargo", "clippy", "--", "-D", "warnings"}).
WithExec([]string{"cargo", "test", "--workspace"}).
Sync(ctx)
}
Alternatives et compromis¶
| Critère | Easy Mode (.gitrust-ci.yml) |
Power Mode (.dagger/) |
|---|---|---|
| Accessibilité | Excellent (quelques lignes YAML) | Courbe d'apprentissage |
| Puissance | Limitée aux cas simples | Illimitée |
| Logique conditionnelle | Non | Oui |
| Parallélisme avancé | Non | Oui |
| Testabilité du pipeline | Nulle | Totale |
| Composition (Daggerverse) | Non | Oui |
| Maintenance | Moteur géré par la plateforme | Chaque dépôt est autonome |
| Alignement philosophie Dagger | Partiel (YAML encode de la logique) | Total |
Recommandation pour vos utilisateurs :
- Commencer en Easy Mode pour les projets simples
- Migrer en Power Mode quand : besoin de logique conditionnelle, de fan-out/fan-in, d'intégration avec des services externes, ou quand le .gitrust-ci.yml dépasse 50 lignes
Implications pour l'administration¶
En tant qu'administrateur :
CI_ENABLED=falsedésactive toute exécution CI (Easy et Power Mode), utile lors d'une maintenanceCI_MAX_CONCURRENTs'applique aux deux modes- Le moteur Easy Mode (
CI_ENGINE_PATH) doit être synchronisé lors des mises à jour de gitrust - Les modules Power Mode sont autonomes — leur mise à jour est la responsabilité de l'utilisateur
Vérifier votre compréhension¶
-
Un utilisateur vous demande d'ajouter une étape « déploiement vers staging si la branche est
main» dans son.gitrust-ci.yml. Quelle est la réponse correcte ? Quelle alternative proposez-vous ? -
En quoi le fait que Dagger garantisse la reproductibilité facilite-t-il le débogage d'un pipeline qui échoue uniquement sur le serveur et pas en local ?