Anatomie d'un Pipeline CI¶
Comprendre la structure d'un pipeline, ses composants, et les techniques pour le rendre rapide et fiable.
Structure d'un pipeline¶
Un pipeline CI est compose de trois niveaux : stages, jobs et steps.
- Stage : groupe logique d'étapes (build, test, deploy). Les stages s'exécutent en sequence.
- Job : unite d'exécution au sein d'un stage. Les jobs d'un même stage peuvent tourner en parallèle.
- Step : commande individuelle au sein d'un job.
graph LR
subgraph "Stage: Build"
A["compile"]
end
subgraph "Stage: Verify"
B["unit-tests"]
C["lint"]
end
subgraph "Stage: Package"
D["build-image"]
E["scan-image"]
end
subgraph "Stage: Deploy"
F["deploy-staging"]
end
A --> B
A --> C
B --> D
C --> D
D --> E
E --> F Stages en sequence, jobs en parallèle
Les stages se suivent : on ne passe pas au stage suivant si le précédent a échoué. À l'intérieur d'un stage, les jobs sont indépendants et peuvent s'exécuter en parallèle, reduisant le temps total du pipeline.
Artefacts¶
Un artefact est la sortie d'un job — un binaire compile, une image Docker, un rapport de tests. Les artefacts permettent de passer des résultats entre jobs sans recalculer.
Cycle de vie¶
graph LR
A["Job build<br/>produit l'artefact"] --> B["Stockage temporaire<br/>sur le runner CI"]
B --> C["Job suivant<br/>telecharge l'artefact"]
C --> D["Expiration<br/>apres N jours"]
B --> E["Registre d'artefacts<br/>retention longue"] | Type d'artefact | Rétention recommandee | Exemple |
|---|---|---|
| Rapport de tests | 30 jours | JUnit XML, coverage HTML |
| Binaire de build | 90 jours | JAR, wheel Python |
| Image conteneur | Indefinie (taguee) | Image Docker dans un registre |
| Rapport de sécurité | 1 an | SARIF, rapport SBOM |
Ne pas rebuilder en prod
L'artefact produit en CI doit être le même qui part en production. Rebuilder l'image au moment du déploiement brise la traçabilite et peut introduire des différences subtiles dues aux dépendances.
Parallelisation¶
Jobs indépendants¶
Les jobs sans dépendance entre eux peuvent tourner en parallèle. Dans l'exemple ci-dessus, unit-tests et lint tournent en même temps, reduisant la durée totale.
Matrix builds¶
Un matrix build exécuté le même job avec plusieurs combinaisons de parametres. Utile pour tester sur plusieurs versions d'un runtime.
Cela généré 6 jobs automatiquement. Si l'un échoué, les autres continuent.
Cache¶
Le cache permet de réutiliser des données coûteuses a produire entre les executions du pipeline.
Types de cache¶
| Type | Ce qu'on cache | Invalidation |
|---|---|---|
| Dépendances | node_modules/, .venv/, .m2/ | Quand le lockfile change |
| Build incremental | Fichiers objet .o, bytecode | Quand les sources changent |
| Images Docker | Couches intermédiaires | Quand le Dockerfile change |
- name: Cache dependances pip
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: pip-${{ hashFiles('requirements.txt') }}
restore-keys: pip-
Clé de cache basée sur le hash du lockfile
Une clé de cache qui inclut le hash de package-lock.json ou requirements.txt est invalidee automatiquement quand les dépendances changent. C'est le pattern recommande.
Exemple concret¶
Pipeline complet pour une application Python, syntaxe Gitea Actions / GitHub Actions :
name: CI
on:
push:
branches: [main, develop]
pull_request:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Cache pip
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: pip-${{ hashFiles('requirements.txt') }}
- run: pip install ruff
- run: ruff check .
- run: ruff format --check .
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Cache pip
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: pip-${{ hashFiles('requirements.txt') }}
- run: pip install -r requirements.txt pytest pytest-cov
- run: pytest --cov=src --cov-report=xml
- uses: actions/upload-artifact@v4
with:
name: coverage-report
path: coverage.xml
retention-days: 30
build:
needs: [lint, test]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- name: Scan image
run: trivy image --exit-code 1 --severity HIGH,CRITICAL myapp:${{ github.sha }}
- name: Push to registry
run: docker push registry.example.com/myapp:${{ github.sha }}
needs: déclaré les dépendances entre jobs
Le job build ne démarré que si lint et test ont réussi. Sans needs, tous les jobs démarrent en même temps.
Outils¶
| Outil | Description | Lien |
|---|---|---|
| Gitea Actions | CI/CD intégré a Gitea, compatible GitHub Actions | gitea.com |
| GitHub Actions | CI/CD natif GitHub, marketplace de milliers d'actions | github.com/features/actions |
| GitLab CI | CI/CD intégré a GitLab, runners Docker et Kubernetes | docs.gitlab.com/ee/ci |
| Jenkins | CI/CD open-source, très flexible, écosystème de plugins | jenkins.io |