Load testing k6 dans le pipeline CI
À la fin de ce tutoriel, vous saurez poser un load test Grafana k6 comme quality gate : script JS versionné, checks, thresholds qui font échouer le job, GitHub Actions (ou Docker), artefact JSON, et un lab en
ca-central-1sur votre staging — jamais un tiers, jamais la prod ouverte. Angle DevOps Elastic Hayway (DEH) : perf mesurable, pas un PDF JMeter mort.Niveau : Intermédiaire · Temps estimé : 50–70 min · Versions cibles : Grafana k6 OSS (v0.57 / 1.x) · Docker · GitHub Actions · Dernière vérification : 2026-09-11 · Region :
ca-central-1Slug :
wow-load-testing-k6· Série : WOW (30/50) · Mot-clé SEO : load testing k6 · Publish : HOLD← Précédent : Chaos Engineering Litmus · → Suivant : Trivy scan CI · Aussi : GitHub Actions reusable · SLO / error budgets · Prometheus Grafana Helm
Prérequis
- Un staging que vous contrôlez (Docker local, ou cible AWS
lab) - Git + CI — GitHub Actions reusable
- Compte lab optionnel (
AWS_PROFILE=lab) — Démarrer avec AWS - Docker (k6 sans installer le binaire)
Coût : 0 € en local ; 0–quelques € si cible AWS jetable. k6 OSS est gratuit. Interdit de bombarder un SaaS public « pour voir ».
export AWS_PROFILE=lab
export AWS_DEFAULT_REGION=ca-central-1
docker --version
Ce que nous allons construire
Load testing k6 CI (WOW 30/50) — ca-central-1
├── Pourquoi k6 + contrat éthique
├── Script : HTTP, checks, thresholds, BASE_URL
├── Scénarios : ramp VU vs arrival-rate
├── Lab nginx Docker + option AWS
├── GitHub Actions : gate + artefacts
└── Anti-patterns, quiz, FAQ
(Schéma — alt : « k6 dans le CI DEH : script versionné, seuils, job Actions, cible staging ca-central-1 ».)
Étape 1 — Pourquoi k6 dans le CI
Un load test hors pipeline pourrit : personne ne le relance. DEH : même repo, même PR, exit ≠ 0 si les seuils cassent.
| Outil | Force | Limite CI |
|---|---|---|
| JMeter | GUI, héritage | XML lourd, peu « as code » |
| Locust | Python | Agents à scaler |
| Artillery | YAML/JS | Moins d’écosystème Grafana |
| k6 | JS, CLI, Docker, thresholds = tests | Pas un e2e navigateur |
k6 (Grafana) : binaire / image, JS, métriques natives. Grafana Cloud existe ; ce WOW = OSS dans le CI.
Éthique : uniquement vos URLs. Interdit : prod sans runbook, sites tiers, flood httpbin. Chaos ≠ flood HTTP — Litmus.
Étape 2 — Script : checks + thresholds
Fichier tests/load/health.js. BASE_URL vient de l’env — jamais un hostname en dur.
import http from 'k6/http';
import { check, sleep } from 'k6';
export const options = {
vus: 5,
duration: '30s',
thresholds: {
http_req_failed: ['rate<0.01'],
http_req_duration: ['p(95)<500'],
checks: ['rate>0.99'],
},
};
export default function () {
const base = __ENV.BASE_URL;
if (!base) throw new Error('BASE_URL manquant');
const res = http.get(`${base}/health`, {
tags: { name: 'health' },
timeout: '10s',
});
check(res, {
'status 200': (r) => r.status === 200,
});
sleep(1);
}
checks = assertions par itération (seuls, ils ne rougissent pas le process). thresholds = critères globaux : un seuil raté → exit souvent 99 → job CI rouge. Tags name: évitent d’exploser les séries d’URL. Timeout explicite : un hung n’est pas un p95 cosmétique.
Étape 3 — Scénarios : ramp vs arrival-rate
VUs fixes = smoke. Un test « comme la prod » décrit des arrivées, pas seulement des boucles sleep.
export const options = {
scenarios: {
smoke: {
executor: 'constant-vus',
vus: 2,
duration: '20s',
tags: { test_type: 'smoke' },
},
ramp: {
executor: 'ramping-vus',
startTime: '20s',
stages: [
{ duration: '30s', target: 10 },
{ duration: '1m', target: 10 },
{ duration: '20s', target: 0 },
],
tags: { test_type: 'ramp' },
},
},
thresholds: {
http_req_failed: ['rate<0.01'],
'http_req_duration{test_type:ramp}': ['p(95)<800'],
},
};
| Executor | Idée | Quand DEH |
|---|---|---|
constant-vus |
N utilisateurs | Smoke PR |
ramping-vus |
Montée / palier | Soak court |
constant-arrival-rate |
N req/s visées | SLO débit |
Séparez smoke PR (2–5 VUs, 20–30 s) et soak nightly (staging dimensionné). 50 VUs sur un nginx laptop saturent le laptop. Seuils = SLO — error budgets.
Étape 4 — Lab local + option ca-central-1
4.1 — nginx (0 €)
mkdir -p lab-k6 && echo ok > lab-k6/index.html
docker run --rm -d --name deh-wow30-nginx -p 8080:80
-v "$PWD/lab-k6:/usr/share/nginx/html:ro" nginx:1.27-alpine
Alignez le check : GET / (body ok) ou un location /health { return 200 'ok'; }.
docker run --rm -i --network host
-e BASE_URL=http://127.0.0.1:8080
grafana/k6:latest run - < tests/load/health.js
--network host (Linux). macOS/Windows : host.docker.internal.
4.2 — Cible AWS lab (optionnel)
Uniquement votre ALB / ECS en ca-central-1 — ECS Fargate. Pas us-east-1 par défaut.
aws sts get-caller-identity
aws elbv2 describe-load-balancers --query 'LoadBalancers[].DNSName'
export BASE_URL="https://<votre-alb-lab>.ca-central-1.elb.amazonaws.com"
# 2–10 VUs. Cleanup après le lab.
Pas de NAT/RDS « pour k6 ». Pas de 1000 VUs. SG : source = runner / IP lab, pas 0.0.0.0/0.
docker rm -f deh-wow30-nginx
Étape 5 — GitHub Actions : quality gate
Smoke sur PR, même script, BASE_URL en variable (staging). Image officielle : reproductible.
# .github/workflows/k6-smoke.yml
name: k6-smoke
on:
pull_request:
paths: ['tests/load/**', 'app/**', '.github/workflows/k6-smoke.yml']
jobs:
k6:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: k6 smoke
env:
BASE_URL: ${{ vars.STAGING_BASE_URL }}
run: |
docker run --rm -e BASE_URL
-v "$PWD:/work"
grafana/k6:latest run
--summary-export=/work/k6-summary.json
/work/tests/load/health.js
- uses: actions/upload-artifact@v4
if: always()
with:
name: k6-summary
path: k6-summary.json
Les thresholds restent la source rouge/vert. L’action grafana/k6-action existe ; Docker marche aussi sur GitLab / Buildkite. OIDC vers AWS si ALB interne : Actions OIDC AWS — pas de clés longues.
Nightly : schedule + workflow_dispatch, scénario ramp, VUs plus hauts seulement si staging isolé. Ne collez pas le soak dans le smoke PR.
Étape 6 — Lire les résultats sans se mentir
Métriques utiles : http_reqs, http_req_duration (p90/p95/p99), http_req_failed, vus.
| Lecture naïve | Lecture DEH |
|---|---|
| avg 80 ms = OK | p95 / p99 + erreurs |
| 0 erreur / 2 VUs | Smoke ≠ capacité |
| « ça passe en local » | Runner ≠ prod (CPU, TLS) |
| 10k VUs tout de suite | D’abord le bottleneck (app, DB, ALB) |
k6 mesure côté client (runner, DNS, WAF possibles). Corrélez la cible — OpenTelemetry, Prometheus. Cloud Grafana = add-on, pas un prérequis.
Étape 7 — Anti-patterns + checklist DEH
Anti-patterns : load prod sans fenêtre ; viser un tiers ; 500 VUs sur un micro ; seuils p(95)<10000 ; URL en dur ; un scénario fourre-tout ; ignorer http_req_failed ; SG 0.0.0.0/0 ; confondre k6 et e2e.
Checklist : cible = staging à vous ; BASE_URL injecté ; smoke petit + nightly séparé ; thresholds = SLO ; tags name ; timeout HTTP ; timeout-minutes job ; artefact ; APM/métriques ; region ca-central-1 ; teardown ; qui a le droit de lancer le soak.
Erreurs fréquentes
| Erreur | Impact | Correction |
|---|---|---|
Tester httpbin / un site public |
Abuse, éthique | Staging votre |
| Thresholds trop lâches | Gate cosmétique | p95 + http_req_failed réels |
| Checks sans thresholds | CI toujours vert | Thresholds checks + HTTP |
localhost dans Actions |
Connexion refusée | BASE_URL staging |
| Soak 15 min sur chaque PR | File CI | Smoke court / soak schedule |
Region us-east-1 |
Incohérence DEH | Forcer ca-central-1 |
| Oublier teardown | Bruit / facture | docker rm / scale-in |
| k6 = chaos | Mauvais outil | Litmus = fautes ; k6 = charge |
Quiz (5 questions)
1. Ce qui fait échouer le job CI k6 :
– A. Un check isolé à 99 %
– B. Un threshold global raté (exit ≠ 0)
– C. L’absence de Grafana Cloud
2. Où pointer BASE_URL en CI ?
– A. La homepage d’un SaaS célèbre
– B. Votre staging (variable CI)
– C. http://127.0.0.1 sur le runner (sans service)
3. Region lab de ce tuto :
– A. us-east-1
– B. ca-central-1
– C. eu-west-3
4. Le smoke PR DEH doit être :
– A. 10 000 VUs pendant 30 min
– B. Court, peu de VUs, chaque PR pertinente
– C. Uniquement manuel
5. constant-arrival-rate sert surtout à :
– A. Remplacer les probes K8s
– B. Viser un débit (req/s), pas N boucles VU
– C. Signer les images (Cosign)
Réponses : 1‑B · 2‑B · 3‑B · 4‑B · 5‑B
FAQ
Pourquoi ca-central-1 ?
Standard lab DEH : IAM, ALB, ECS alignés. Le runner GitHub n’est pas dans cette region : c’est la cible qui l’est.
k6 vs JMeter ?
JMeter = GUI héritée. k6 = CI as code (JS, Docker, thresholds). Gates PR DEH = k6.
Faut-il Grafana Cloud k6 ?
Non pour démarrer. OSS + summary + job rouge/vert suffisent. Cloud = géo / UI équipe.
GraphQL / gRPC ?
Oui (http, k6/net/grpc). Commencez par health + 1 parcours métier.
Load test = chaos ?
Non. k6 = charge. Chaos = fautes — Litmus. Les deux, sur staging.
Combien de VUs ?
Smoke : 2–10. Soak : calé sur le budget staging, par paliers — pas un chiffre LinkedIn.
k6 dans Kubernetes ?
Job / opérateur possible ; DEH PR = Actions + Docker d’abord.
Navigateur / Web Vitals ?
k6 browser ≠ ce smoke CLI. E2E perf = autre job (Playwright). Ne mélangez pas dans le même p95 HTTP.
Pour aller plus loin
- Chaos Engineering Litmus
- Trivy scan images & IaC
- SLO et error budgets
- GitHub Actions reusable
- GitHub Actions OIDC AWS
- OpenTelemetry
- Prometheus + Grafana Helm
- ECS Fargate prod
- Pipeline DevSecOps
Maillage série WOW
| ← Précédent | Chaos Engineering Litmus |
| → Suivant | Trivy scan CI |
| Aussi | GitHub Actions reusable · SLO / error budgets · Prometheus Grafana |
Meta publication (SEO)
- Title SEO : Load testing k6 dans le pipeline CI : seuils, gates, lab FR
- Meta description : Intégrez Grafana k6 dans le CI : script JS, checks, thresholds, GitHub Actions, lab ca-central-1, FAQ, quiz et check-list DEH.
- Focus keyword : load testing k6
- Secondary : Grafana k6 CI, k6 GitHub Actions, load test thresholds, quality gate performance
- Image :
assets/web/devopelastichayway/cover-wow-load-testing-k6-1200x630.webp(à générer) - Catégorie : WOW / SRE · Niveau : Intermédiaire
- URL cible : https://devopelastichayway.com/tutoriels/wow-load-testing-k6/
- Post live : N/A (nouveau) · slug
wow-load-testing-k6· Publish : HOLD (draft — push WP-CLI sur feu vert Maître)
Pour aller plus loin — hubs live
Retour parcours Catalogue Tutoriels — hub de la série et leçons sœurs.