Финальный проект: внедрите 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! 🚀
🎉 Поздравляем с завершением курса!
Поделитесь опытом и получите промокод на бесплатный доступ к любому premium-материалу на выбор
Бесплатный доступ к любому premium-материалу на выбор
Ваш опыт поможет другим студентам
Промокод придет на email в течение 24 часов