Привет Хабр! Я Дима, DevOps-инженер в IT-компании.
Эпик-фейлы бывают разные. Можно забыть закоммитить config.json. А можно так упаковать новый эндпоинт, что всё апи ляжет костьми в час-пик и будет тихо плакать под лавиной реквестов. Ручные нагрузочные тесты — это как проверять тормоза на уже летящем с горы автомобиле. Сегодня говорим о том, как автоматизировать эту магию — вшивать проверку производительности прямо в CI/CD, чтобы не краснеть перед продом и спокойно спать по ночам. Запускайте свои пайплайны, щупальцы в руки — погнали.
Зачем это вообще надо? Или «опять эти ваши тесты...»
Смотрите. Раньше было так: написали код → отправили в прод → получили алерт в 3 ночи → вся команда в панике → кофе льётся рекой, кулера пустеют. Знакомо? Это порочная практика. Мы называем её «тушение пожаров вслепую».
А можно иначе. Левостороннее смещение — звучит как термин из анатомии, а на деле это принцип «лови баги раньше, чем они станут багами». Запускать нагрузку не перед релизом, а на каждом пулл-реквесте. Чтобы ещё до того, как код коснётся продовой ветки, мы понимали: этот мерж рейт-лимит не сломает? А этот новый эндпоинт не отправит базу данных в глубокий и болезненный кирпич?
Перестаём тыкать палкой в монитор и начинаем жить как взрослые.
Инструменты: чем будем колдовать?
Чтобы встроить нагрузку в CI/CD, нам нужен инструмент, который:
Беспощаден к ошибкам — упал сам, уронил пайплайн.
Быстр как молния — тесты на 10 минут никто ждать не будет.
Умеет в JSON — потому что нас ждут пороги, графики и автоматические алерты.
Наш фаворит — k6. Он быстрый, написан на Go, не требует танцев с JVM, как JMeter, и не заставляет вас вспоминать Scala, как Gatling. Просто берёшь и пишешь скрипт на JavaScript. Элегантно, как удар топором.
GitHub Actions: настройка за 5 минут, чтобы спать 8 часов
Допустим, вы храните код на GitHub. Тогда вам сюда — в /.github/workflows/load-test.yml.
name: Load Test - Don't Merge If Slow
on:
pull_request:
branches: [ main ]
jobs:
load-test-k6:
runs-on: ubuntu-latest
steps:
name: Забираем код
uses: actions/checkout@v4
name: Ставим k6
uses: grafana/setup-k6@v1
name: Гоняем нагрузку как надо
run: |
k6 run --threshold "http_req_duration{p(95)<800}" src/loadtest.js
env:
BASE_URL: ${{ secrets.TEST_ENV }}
name: Если упало — светимся красным
if: failure()
run: |
echo "ВСЁ ПРОПАЛО. ПАЙПЛАЙН УПАЛ. МЕРЖИТЬ НЕЛЬЗЯ."
Что здесь происходит?
Всё просто:
Как только кто-то пытается замержить PR в main — триггерится этот воркфлоу.
Ставим k6.
Запускаем тест. Если 95-й перцентиль задержки превысит 800ms — k6 вернёт ненулевой exit code.
Пайплайн зафейлится. Мерж заблокирован. Коммитер плачет, но продакшен — цел.
GitLab CI: для тех, кто любит посложнее
Если вы из лагеря GitLab — вот вам настройка в .gitlab-ci.yml:
load_test:
image: grafana/k6:latest
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- k6 run --out json=result.json loadtest.js
artifacts:
reports:
junit: result.xml
allow_failure: false
Красиво, ёмко, и главное — если что-то пойдёт не так, мерж-реквест не пройдёт. Артефакты с результатами прикрепятся к пайплайну — можно будет тыкнуть пальцем, где именно стало плохо.
Pro-стратегии от бывалых:
Не ломайте билды сразу. Первые недели просто собирайте метрики. Потом ставьте реалистичные пороги.
Тестируйте по-разному: для PR — короткие смоук-тесты, по ночам — полные сценарии.
Используйте threshold в скриптах k6:
export const options = {
thresholds: {
'http_req_duration{status:200}': ['p(95) < 500'],
'http_req_failed': ['rate < 0.01'],
},
};
Перевожу: если больше 1% запросов упадут или 95% ответов будут медленнее 500ms — это фейл. Всё.
Если до сих пор вы запускали нагрузку вручную раз в квартал — вы живете в каменном веке. Современный пайплайн должен быть жёстким, автоматическим и безжалостным к регрессиям.
Вшивайте нагрузку в CI/CD. Ловите падение перформанса до того, как его увидят пользователи. И спите спокойно.
(звук уходящего вдаль падающего сервера, затихающий пинг)
gribunin
Нагрузочное тестирование делается на тестовом окружении? Если да, то оно должно быть максимально идентично продакшену, чтобы быть уверенным, что там тоже всё будет хорошо.
infracoder Автор
Да, нагрузочное тестирование должно проводиться на тестовом окружении, максимально приближенном к продакшену. Без этого результаты бесполезны и создают ложную уверенность.
Критически важно совпадение:
- Конфигураций (Веб-сервер, БД, JVM)
- Типов и характеристик железа/облачных инстансов (особенно Disk I/O и сеть)
- Версий всего ПО и оркестрации
- Сетевых задержек до внешних сервисов
Идеал — полная копия. Если дорого — scaled-down копия с теми же типами ресурсов, но в меньшем количестве. Это позволяет находить архитектурные проблемы (утечки памяти, блокировки БД) и сравнивать производительность версий.
Главное правило: отличие в инфраструктуре делает цифры (RPS, latency) нерелевантными для прода, но может помочь выявить системные баги.