Финальный проект: внедрите k6 в свой проект
Цель финального проекта
К концу этого урока у вас будет:
- ✅ Работающий smoke-тест, интегрированный в CI/CD
- ✅ Load-тест с baseline для ключевого user journey
- ✅ Настроенная интеграция с Prometheus/Grafana (или альтернатива)
- ✅ Документированный процесс Go/No-Go для релизов
- ✅ План дальнейшего развития (3-6 месяцев)
Этот проект — не теоретическое упражнение. Внедряйте k6 в ваш реальный проект параллельно с прохождением шагов. В конце вы получите working solution, который сразу приносит пользу.
🏆 Критерии оценки: уровни достижений
Выберите уровень, который соответствует вашим целям и ресурсам. Каждый уровень — полноценное достижение, которое приносит реальную пользу.
🥉 Bronze — Минимально жизнеспособное внедрение
Подходит для: малых команд, MVP-проектов, первого опыта с k6
Обязательные требования:
- ✅ Smoke-тест покрывает 3+ критических endpoints
- ✅ Тест интегрирован в CI/CD (запускается на каждом PR)
- ✅ Thresholds привязаны к реальным SLO или временным целям
- ✅ Команда знает, как интерпретировать результаты smoke-теста
- ✅ Есть документация: что тестируем, как запускать локально
Время внедрения: 1-2 недели Польза: Предотвращение критических регрессий перед деплоем
Bronze достаточно, чтобы предотвратить 70% инцидентов, связанных с производительностью. Не стремитесь сразу к Gold — лучше сделать Bronze качественно.
🥈 Silver — Рекомендуемый уровень
Подходит для: продакшн-проектов с регулярными релизами, команд 5+ человек
Включает Bronze +:
- ✅ Load-тест для ключевого user journey (checkout, регистрация, поиск)
- ✅ Baseline зафиксирован и сохранен в Git/S3
- ✅ Автоматическое сравнение с baseline (скрипт или CI/CD stage)
- ✅ Интеграция с observability: Prometheus + Grafana или альтернатива
- ✅ Grafana dashboard доступен команде и задокументирован
- ✅ Процесс Go/No-Go задокументирован (критерии, ответственные, template отчета)
- ✅ Load-тест запускается перед каждым major release
Время внедрения: 3-4 недели Польза: Обнаружение регрессий до production, данные для capacity planning, прозрачный процесс релиза
🥇 Gold — Advanced уровень
Подходит для: high-load проектов, e-commerce, финтех, enterprise
Включает Silver +:
- ✅ Покрытие тестами 3+ критических user journeys
- ✅ Stress-тест для поиска breakpoint (запускается перед big sale/маркетинговыми кампаниями)
- ✅ Soak-тест (4-8 часов) раз в месяц для поиска утечек памяти
- ✅ Масштабирование генераторов: k6-operator в Kubernetes или distributed execution
- ✅ Интеграция трейсов (traceparent header) для корреляции k6 ↔ APM
- ✅ Автоматический fail в CI/CD при деградации > 10% к baseline
- ✅ Multi-region тестирование (если приложение geo-distributed)
- ✅ Continuous load testing в production (канарейка, shadow traffic)
Дополнительно (опционально):
- ✅ Custom metrics для бизнес-KPI (conversion rate, cart abandonment)
- ✅ Chaos engineering: k6 + Chaos Mesh для тестов отказоустойчивости
- ✅ Библиотека паттернов и best practices для команды
- ✅ Метрики ROI: prevented incidents, сэкономленное время/деньги
Время внедрения: 2-3 месяца Польза: Максимальная уверенность в стабильности, предотвращение крупных инцидентов, обоснование инфраструктурных расходов
🎯 Как выбрать свой уровень
Начните с Bronze, если:
- У вас нет опыта с k6
- Команда < 5 человек
- Проект в стадии MVP/beta
- Нет выделенного Performance Engineer
Стремитесь к Silver, если:
- Проект в production с регулярными релизами
- У вас были инциденты из-за производительности
- Нужны данные для capacity planning
- Команда готова инвестировать 3-4 недели
Выбирайте Gold, если:
- High-load проект (> 10K RPS в пиках)
- Downtime стоит дорого (финтех, e-commerce)
- Есть SRE/Performance Engineer в команде
- Уже есть mature observability (Prometheus, Grafana, трейсинг)
Не пытайтесь прыгнуть сразу на Gold! Это приведет к burnout и забрасыванию проекта. Лучше качественно внедрить Bronze за 2 недели, чем потратить месяц на недоделанный Gold.
Фаза 1: Smoke-тест в CI/CD (неделя 1)
Шаг 1.1: Определите критические endpoints
**Задание:** Составьте список критических API endpoints вашего приложения
Критерии критичности:
- [ ] Endpoint используется в 80% пользовательских сценариев
- [ ] Деградация этого endpoint влияет на revenue
- [ ] Endpoint участвует в критическом business flow (регистрация, оплата, авторизация)
**Мой список критических endpoints:**
1. POST /auth/login — авторизация
2. GET /api/products — каталог товаров
3. POST /api/cart/add — добавление в корзину
4. POST /api/orders/create — создание заказа
5. ...Шаг 1.2: Напишите первый smoke-тест
// tests/smoke.js
import http from "k6/http";
import { check, sleep } from "k6";
export const options = {
scenarios: {
smoke: {
executor: "shared-iterations",
iterations: 10,
vus: 2,
maxDuration: "2m",
},
},
thresholds: {
http_req_failed: ["rate<0.05"], // < 5% ошибок
http_req_duration: ["p(95)<1000"], // p95 < 1s (временный, уточните позже)
checks: ["rate>0.95"], // > 95% проверок прошли
},
};
const BASE_URL = __ENV.BASE_URL || "https://staging.yourapp.com";
export default function () {
// Замените на ваши критические endpoints
// 1. Health check
let res = http.get(`${BASE_URL}/health`);
check(res, {
"health check is 200": (r) => r.status === 200,
});
// 2. Критический endpoint 1
res = http.get(`${BASE_URL}/api/products?limit=10`);
check(res, {
"products list is 200": (r) => r.status === 200,
"has products": (r) => {
const body = JSON.parse(r.body || "{}");
return body.products && body.products.length > 0;
},
});
// 3. Критический endpoint 2 (с авторизацией)
const token = __ENV.TEST_TOKEN; // Передайте через env
res = http.post(
`${BASE_URL}/api/cart/add`,
JSON.stringify({ productId: "test-1", quantity: 1 }),
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
},
}
);
check(res, {
"cart add is 200": (r) => r.status === 200 || r.status === 201,
});
sleep(1);
}Шаг 1.3: Интегрируйте в CI/CD
GitHub Actions:
# .github/workflows/smoke-test.yml
name: Smoke Test
on:
pull_request:
branches: [main, develop]
push:
branches: [main]
jobs:
smoke-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run k6 smoke test
uses: grafana/k6-action@v0.3.1
with:
filename: tests/smoke.js
env:
BASE_URL: ${{ secrets.STAGING_URL }}
TEST_TOKEN: ${{ secrets.TEST_TOKEN }}
- name: Upload results
if: always()
uses: actions/upload-artifact@v3
with:
name: k6-results
path: summary.jsonGitLab CI:
# .gitlab-ci.yml
smoke-test:
stage: test
image: grafana/k6:latest
script:
- k6 run tests/smoke.js --summary-export summary.json
artifacts:
when: always
paths:
- summary.json
expire_in: 30 days
variables:
BASE_URL: $STAGING_URL
TEST_TOKEN: $TEST_TOKEN
only:
- merge_requests
- mainЧек-лист фазы 1:
- Smoke-тест написан и покрывает 3-5 критических endpoints
- Тест запускается локально:
k6 run tests/smoke.js - Тест интегрирован в CI/CD pipeline
- Тест падает при нарушении thresholds (exit code 1)
- Команда знает, как интерпретировать результаты smoke-теста
Milestone 1: Вы предотвращаете deploy, который сломает критические endpoints!
Фаза 2: Load-тест с baseline (недели 2-3)
Шаг 2.1: Выберите ключевой user journey
Пример: "Browse → Add to Cart → Checkout"
// tests/load-checkout.js
import http from "k6/http";
import { check, sleep } from "k6";
import { SharedArray } from "k6/data";
// Загружаем тестовые данные
const products = new SharedArray("products", function () {
return JSON.parse(open("./fixtures/products.json"));
});
export const options = {
scenarios: {
load_test: {
executor: "ramping-vus",
startVUs: 0,
stages: [
{ duration: "2m", target: 10 }, // Warmup
{ duration: "5m", target: 50 }, // Ramp-up
{ duration: "10m", target: 50 }, // Plateau (основной тест)
{ duration: "2m", target: 0 }, // Ramp-down
],
gracefulRampDown: "30s",
},
},
thresholds: {
// Уточните на основе ваших SLO
"http_req_duration{flow:checkout}": ["p(95)<800", "p(99)<1500"],
"http_req_failed{flow:checkout}": ["rate<0.01"],
"checks{flow:checkout}": ["rate>0.97"],
},
};
const BASE_URL = __ENV.BASE_URL || "https://staging.yourapp.com";
export default function () {
const product = products[Math.floor(Math.random() * products.length)];
// 1. Browse products
let res = http.get(`${BASE_URL}/api/products`, {
tags: { flow: "browse" },
});
check(res, { "browse OK": (r) => r.status === 200 });
sleep(2); // Think time
// 2. View product details
res = http.get(`${BASE_URL}/api/products/${product.id}`, {
tags: { flow: "browse" },
});
check(res, { "product details OK": (r) => r.status === 200 });
sleep(1);
// 3. Add to cart
res = http.post(
`${BASE_URL}/api/cart/add`,
JSON.stringify({ productId: product.id, quantity: 1 }),
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${__ENV.TEST_TOKEN}`,
},
tags: { flow: "checkout" },
}
);
check(res, { "add to cart OK": (r) => r.status === 200 || r.status === 201 });
sleep(2);
// 4. Checkout
res = http.post(
`${BASE_URL}/api/orders/create`,
JSON.stringify({
paymentMethod: "test",
shippingAddress: "Test Street 1",
}),
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${__ENV.TEST_TOKEN}`,
},
tags: { flow: "checkout" },
}
);
check(res, {
"checkout OK": (r) => r.status === 200 || r.status === 201,
"has orderId": (r) => {
const body = JSON.parse(r.body || "{}");
return body.orderId !== undefined;
},
});
sleep(5); // Think time after purchase
}Шаг 2.2: Соберите baseline
# 1. Запустите тест на чистом стенде
k6 run tests/load-checkout.js --summary-export baseline.json
# 2. Сохраните baseline в Git
git add baseline.json
git commit -m "feat: add load test baseline for checkout flow"
git push
# 3. Документируйте условия baseline
echo "## Baseline для checkout flow
**Дата:** $(date)
**Версия:** v1.2.3
**Условия:**
- Стенд: staging (4 CPU, 8GB RAM)
- БД: PostgreSQL 15, пустая (только fixtures)
- Сценарий: 50 VU, 10 минут plateau
**Результаты:**
- p95: 450ms
- p99: 850ms
- Error rate: 0.2%
- Checks: 98.5%
" > baseline-checkout.mdШаг 2.3: Автоматическое сравнение с baseline
// scripts/compare-baseline.js
import fs from "fs";
const baseline = JSON.parse(fs.readFileSync("baseline.json", "utf8"));
const current = JSON.parse(fs.readFileSync("summary.json", "utf8"));
const metrics = ["http_req_duration", "http_req_failed"];
let hasRegression = false;
for (const metric of metrics) {
const baseVal = baseline.metrics[metric].values["p(95)"];
const currVal = current.metrics[metric].values["p(95)"];
const diff = ((currVal - baseVal) / baseVal) * 100;
console.log(`${metric} p95: ${currVal}ms (${diff.toFixed(1)}% vs baseline)`);
if (Math.abs(diff) > 10) {
console.error(`⚠️ Regression detected: ${diff.toFixed(1)}%`);
hasRegression = true;
}
}
process.exit(hasRegression ? 1 : 0);Чек-лист фазы 2:
- Load-тест написан для ключевого user journey
- Baseline собран и задокументирован (версия, условия, результаты)
- Baseline сохранен в Git/S3
- Скрипт сравнения с baseline работает
- В CI/CD добавлен stage для load-теста (опционально, можно запускать вручную)
Milestone 2: Вы можете обнаружить регрессию производительности до production!
Фаза 3: Observability (недели 3-4)
Шаг 3.1: Настройте отправку метрик
Вариант A: Prometheus (если есть)
k6 run tests/load-checkout.js \
--out prometheus-remote-write=http://prometheus:9090/api/v1/write \
--summary-export summary.jsonВариант B: Grafana Cloud (бесплатный tier)
# 1. Зарегистрируйтесь: https://grafana.com/auth/sign-up/create-user
# 2. Получите Prometheus remote write URL и токен
# 3. Запустите тест:
K6_PROMETHEUS_REMOTE_URL=https://prometheus-xxx.grafana.net/api/prom/push \
K6_PROMETHEUS_INSECURE_SKIP_TLS_VERIFY=false \
k6 run tests/load-checkout.js \
--out experimental-prometheus-rwВариант C: InfluxDB + Grafana (Docker)
# docker-compose.yml
version: '3'
services:
influxdb:
image: influxdb:2.7
ports:
- "8086:8086"
environment:
DOCKER_INFLUXDB_INIT_MODE: setup
DOCKER_INFLUXDB_INIT_USERNAME: admin
DOCKER_INFLUXDB_INIT_PASSWORD: adminpassword
DOCKER_INFLUXDB_INIT_ORG: myorg
DOCKER_INFLUXDB_INIT_BUCKET: k6
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
# Запуск:
docker-compose up -d
# Тест:
k6 run tests/load-checkout.js --out influxdb=http://localhost:8086/k6Шаг 3.2: Создайте Grafana dashboard
Импортируйте готовый дашборд k6:
- Откройте Grafana → Dashboards → Import
- ID дашборда:
2587(k6 Load Testing Results) - Выберите ваш Prometheus/InfluxDB datasource
Или создайте кастомный с ключевыми панелями:
http_req_duration{flow="checkout"}(p50, p95, p99)http_req_failed{flow="checkout"}(error rate)http_reqs(throughput RPS)vus(active virtual users)
Чек-лист фазы 3:
- Метрики k6 отправляются в Prometheus/InfluxDB/Grafana Cloud
- Grafana dashboard создан и доступен команде
- Dashboard содержит панели: latency (p95), error rate, RPS, VUs
- Ссылка на dashboard добавлена в README/Wiki
Milestone 3: Вы видите метрики в реальном времени и можете быстро найти bottleneck!
Фаза 4: Процесс Go/No-Go (неделя 4)
Шаг 4.1: Документируйте критерии релиза
# Критерии Go/No-Go для релизов
## Smoke test (обязательно перед каждым PR)
- ✅ Go: checks > 95%, http_req_failed < 5%, p95 < 1s
- ⚠️ Review: checks 90-95% (проверить причину)
- ❌ No-Go: checks < 90% или http_req_failed > 10%
## Load test (обязательно перед major release)
- ✅ Go: p95 в SLO, error rate < 1%, деградация к baseline < 10%
- ⚠️ Review: деградация 10-20% (обсудить с владельцем продукта)
- ❌ No-Go: p95 вне SLO, error rate > 2%, деградация > 20%
## Stress test (перед big sale / маркетинговая кампания)
- ✅ Go: нашли breakpoint > ожидаемого пика × 1.5
- ⚠️ Review: breakpoint близко к пику (нужен plan масштабирования)
- ❌ No-Go: breakpoint < ожидаемого пика
## Ответственные
- За запуск тестов: DevOps / QA
- За анализ результатов: Tech Lead / Performance Engineer
- За решение Go/No-Go: Product Owner + Tech LeadШаг 4.2: Создайте template отчета
# Load Test Report: Checkout Flow
**Дата:** 2024-01-15
**Версия:** v1.3.0
**Тип теста:** Load (ramping-vus, 50 VU, 10 min)
**Dashboard:** https://grafana.yourapp.com/d/k6-checkout
## Результаты
| Метрика | Baseline | Current | Diff | Status |
| ----------- | -------- | ------- | ----- | --------- |
| p95 latency | 450ms | 520ms | +15% | ⚠️ |
| p99 latency | 850ms | 980ms | +15% | ⚠️ |
| Error rate | 0.2% | 0.3% | +50% | ✅ (< 1%) |
| Checks | 98.5% | 98.1% | -0.4% | ✅ |
| RPS | 85 | 82 | -3% | ✅ |
## Анализ
**Bottleneck:** Рост latency на 15% к baseline
**Причина:**
- http_req_waiting вырос с 400ms до 480ms
- CPU сервиса стабильный (40%)
- БД latency выросла с 50ms до 120ms
- Обнаружено: N+1 query в новом endpoint `/api/orders/items`
**Триангуляция:**
- Grafana: http_req_waiting ↑ 20%
- Traces (Jaeger): span `orders.getItems` = 80% времени
- Logs: "Slow query: SELECT \* FROM order_items WHERE..."
## Решение
⚠️ **Review рекомендован**
**Рекомендация:**
- Оптимизировать N+1 query (JOIN вместо loop)
- Или: принять деградацию +15% (укладывается в SLO < 800ms)
**Решение владельца продукта:** [Заполнить]
**Действия:**
- [ ] Создать задачу на оптимизацию БД: JIRA-123
- [ ] Запланировать повторный тест после фикса
- [ ] Обновить baseline если принимаем деградациюЧек-лист фазы 4:
- Критерии Go/No-Go задокументированы и согласованы с командой
- Template отчета создан
- Процесс понятен: кто запускает, кто анализирует, кто принимает решение
- Команда знает, где искать результаты (Grafana dashboard, summary.json, отчет)
Milestone 4: У вас есть четкий, прозрачный процесс принятия решений о релизе!
Фаза 5: Roadmap (3-6 месяцев)
Месяц 1-2: Стабилизация
- Smoke-тест проходит стабильно на всех PR
- Load-тест запускается перед каждым релизом
- Baseline обновляется раз в спринт
- Команда привыкает использовать результаты для Go/No-Go
Месяц 3-4: Расширение покрытия
- Добавить stress-тест для критических сценариев
- Добавить soak-тест (4-8 часов) раз в месяц
- Покрыть тестами top-5 user journeys (не только checkout)
- Интегрировать трейсы (traceparent) для корреляции с APM
Месяц 5-6: Масштабирование
- Внедрить k6-operator в Kubernetes (если нужны большие нагрузки)
- Настроить распределенные тесты (multi-region)
- Автоматическое сравнение с baseline в CI/CD (fail если > 10%)
- Канарейка в production (ограниченный RPS под feature flag)
Долгосрочно
- Каталог паттернов: что сработало, что нет
- Lessons learned: инциденты, которые предотвратили благодаря k6
- Метрики ROI: сколько денег/времени сэкономили
- Обучение новых членов команды (этот курс + внутренние best practices)
Финальный чек-лист проекта
Практика: что сделать до следующего урока
1.Фаза 1: Smoke-тест в CI/CD
- —✅ Smoke-тест написан (3-5 критических endpoints)
- —✅ Интегрирован в CI/CD (GitHub Actions / GitLab CI)
- —✅ Тест падает при нарушении thresholds
- —✅ Команда понимает, как читать результаты
2.Фаза 2: Load-тест с baseline
- —✅ Load-тест написан для ключевого user journey
- —✅ Baseline собран и задокументирован
- —✅ Скрипт сравнения с baseline работает
- —✅ Процесс запуска load-теста перед релизом установлен
3.Фаза 3: Observability
- —✅ Метрики отправляются в Prometheus/InfluxDB/Grafana
- —✅ Dashboard создан и доступен команде
- —✅ Ссылка на dashboard в README
4.Фаза 4: Процесс Go/No-Go
- —✅ Критерии Go/No-Go задокументированы
- —✅ Template отчета создан
- —✅ Ответственные назначены
- —✅ Команда знает процесс принятия решений
5.Фаза 5: Roadmap на 3-6 месяцев
- —✅ План развития составлен
- —✅ Задачи добавлены в backlog
- —✅ Определены метрики успеха (ROI, prevented incidents)
Поздравляем! 🎉
Вы завершили курс "k6: нагрузочное тестирование как система" и внедрили k6 в реальный проект!
Что вы получили:
- 🎯 Работающий процесс нагрузочного тестирования
- 📊 Метрики и дашборды для принятия решений
- 🛡️ Защиту от регрессий производительности
- 📈 Roadmap для масштабирования
Следующие шаги:
- Запустите первый smoke-тест в CI/CD и дождитесь успешного прохождения
- Соберите baseline для критического user journey
- Поделитесь результатами с командой
- Продолжайте улучшать покрытие и автоматизацию
Помните: нагрузочное тестирование — это не разовая активность, а непрерывный процесс. Обновляйте тесты вместе с продуктом, делитесь находками, учитесь на инцидентах.
Удачи в production! May your p95 be ever low and your RPS ever high! 🚀
🎉 Congratulations on completing the course!
Share your experience and get a promo code for free access to any premium material of your choice
Free access to any premium material of your choice
Your experience will help other students
Promo code will arrive via email within 24 hours