Привет Хабр! Я Дима, 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 "ВСЁ ПРОПАЛО. ПАЙПЛАЙН УПАЛ. МЕРЖИТЬ НЕЛЬЗЯ."

Что здесь происходит?

Всё просто:

  1. Как только кто-то пытается замержить PR в main — триггерится этот воркфлоу.

  2. Ставим k6.

  3. Запускаем тест. Если 95-й перцентиль задержки превысит 800ms — k6 вернёт ненулевой exit code.

  4. Пайплайн зафейлится. Мерж заблокирован. Коммитер плачет, но продакшен — цел.

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. Ловите падение перформанса до того, как его увидят пользователи. И спите спокойно. 

(звук уходящего вдаль падающего сервера, затихающий пинг)

Комментарии (2)


  1. gribunin
    12.09.2025 16:44

    Нагрузочное тестирование делается на тестовом окружении? Если да, то оно должно быть максимально идентично продакшену, чтобы быть уверенным, что там тоже всё будет хорошо.


    1. infracoder Автор
      12.09.2025 16:44

      Да, нагрузочное тестирование должно проводиться на тестовом окружении, максимально приближенном к продакшену. Без этого результаты бесполезны и создают ложную уверенность.

      Критически важно совпадение:

      - Конфигураций (Веб-сервер, БД, JVM)
      - Типов и характеристик железа/облачных инстансов (особенно Disk I/O и сеть)
      - Версий всего ПО и оркестрации
      - Сетевых задержек до внешних сервисов

      Идеал — полная копия. Если дорого — scaled-down копия с теми же типами ресурсов, но в меньшем количестве. Это позволяет находить архитектурные проблемы (утечки памяти, блокировки БД) и сравнивать производительность версий.

      Главное правило: отличие в инфраструктуре делает цифры (RPS, latency) нерелевантными для прода, но может помочь выявить системные баги.