Self-Hosted Bare Metal Runner
Self-Hosted Runner — это Bare Metal Runner, который вы запускаете и которым управляете сами,
вместо использования управляемого Bencher On-Demand или Dedicated Runner.
Вы указываете бинарному файлу runner API-сервер Bencher,
и он берёт и выполняет Job на вашем собственном оборудовании.
Самостоятельное размещение Runner подходит, когда вы хотите:
- Запускать бенчмарки на определённом оборудовании, которое не предлагает Bencher Cloud
- Держать benchmark-нагрузки внутри собственной сети или в изолированной (air-gapped) среде
- Запускать Bencher Self-Hosted от начала до конца
Это руководство проведёт вас через регистрацию Runner, описание его оборудования с помощью Spec,
связывание двух сущностей вместе и запуск бинарного файла runner.
Концептуальный обзор того, как Runner, Spec, Sandbox и Job сочетаются друг с другом,
смотрите в обзоре Bare Metal.
🐰 Изоляция через Firecracker требует Linux 5.14 или новее с включённым KVM и доступной для записи иерархией cgroup v2 в
/sys/fs/cgroup, а сам Runner должен работать от имениroot. Каждый Job в песочнице работает в собственной cgroup в/sys/fs/cgroup/bencher, независимо от числа ядер CPU, с включёнными контроллерамиcpuset,memoryиpids. Runner завершает процессы Job черезcgroup.killэтой cgroup, которого нет в более старых ядрах: на них Runner завершается при запуске или, если он запущен с--danger-allow-no-sandbox, завершает с ошибкой каждый Job в песочнице. Процесс Firecracker, обслуживающий каждый Job в песочнице, запирается в chroot от имени непривилегированного пользователя, и построение этой изоляции требует прав, которых одно только включение KVM не даёт. Runner, обслуживающий только не изолированные Spec, может работать на любом поддерживаемом хосте.
Создание Runner
Runner — это ресурс, который аутентифицирует бинарный файл runner на вашем API-сервере Bencher.
Создайте его с помощью CLI bencher,
REST API для Runners
или Bencher Console.
bencher runner create \ --host https://api.bencher.example.com \ --name "My Runner"Bencher возвращает новый Runner вместе с его ключом:
{ "uuid": "...", "key": "bencher_runner_..."}Ключ показывается только один раз, поэтому сохраните его в надёжном месте.
Вы передадите его бинарному файлу runner при запуске Runner.
Если ключ когда-либо потерян или скомпрометирован, замените его с помощью API POST /v0/runners/{runner}/key,
что немедленно делает предыдущий ключ недействительным.
Создание Spec
Spec описывает оборудование, которое предоставляет Runner: операционную систему, архитектуру CPU, тип Sandbox, количество CPU, память, диск и сетевой доступ. Job объявляет нужный ему Spec, а Runner берёт только те Job, чьи Spec он поддерживает.
Создайте Spec с помощью CLI bencher,
REST API для Specs
или Bencher Console:
bencher spec create \ --host https://api.bencher.example.com \ --name "Intel v1" \ --os linux \ --architecture x86_64 \ --sandbox firecracker \ --cpu 4 \ --memory 51539607552 \ --disk 137438953472Опустите --sandbox, чтобы определить не изолированный Spec,
и передайте --network, если Job на этом Spec разрешён сетевой доступ.
Память и диск указываются в байтах.
Подробнее о Spec и о том, как Testbed записывает Spec, использованный для каждого Report,
смотрите в Testbeds и Specs.
Назначение Spec для Runner
Runner Spec связывает Spec с Runner. Runner может поддерживать несколько Spec, а Spec может поддерживаться несколькими Runner. Runner берёт только те Job, чей Spec ему назначен.
Добавьте Spec к Runner с помощью CLI bencher
или REST API для Runner Specs:
bencher runner spec add my-runner \ --host https://api.bencher.example.com \ --spec intel-v1Удалить связь позже можно с помощью API DELETE /v0/runners/{runner}/specs/{spec}.
Запуск Runner
После того как Runner создан и назначен хотя бы один Spec,
запустите бинарный файл runner на вашем оборудовании с помощью runner up.
Укажите хост API-сервера, UUID или slug Runner и ключ Runner,
либо в виде флагов, либо в виде переменных окружения:
runner up \ --host https://api.bencher.example.com \ --runner my-runner \ --key bencher_runner_...export BENCHER_HOST=https://api.bencher.example.comexport BENCHER_RUNNER=my-runnerexport BENCHER_RUNNER_KEY=bencher_runner_...runner upБинарный файл runner открывает одно WebSocket-соединение с API-сервером,
опрашивает на наличие Job, соответствующих его Spec, выполняет каждую и сообщает результаты обратно.
Соединение остаётся открытым между Job,
и бинарный файл обновляет себя между Job, когда доступна новая версия.
По умолчанию Runner следует каналу обновлений stable
и обновляется только до версионированных релизов.
Канал canary вместо этого отслеживает скользящую canary-сборку, развёрнутую в Bencher Cloud.
Runner, выполняющий Job в песочнице, должен работать от имени root,
поэтому команды выше приведены так, как их запустил бы пользователь root,
или под менеджером служб, который запускает Runner от имени root.
По умолчанию Runner отклоняет любую Job, чей Spec не имеет Sandbox.
Чтобы разрешить Runner выполнять не изолированные Job напрямую на хосте,
запустите его с флагом --danger-allow-no-sandbox.
runner uprunner upЗапускает runner, который опрашивает сервер и выполняет benchmark Job. Это долго работающая команда, используемая для работы с Self-Hosted Runner. Runner открывает одно WebSocket-соединение с API-сервером, берёт Job, соответствующие его Spec, выполняет их и сообщает результаты обратно. Runner пишет свой журнал в stderr в формате JSON, по одному объекту на строку, а вывод Job записывает только как количество байтов.
runner up [OPTIONS]Опции
--host <HOST>API-сервер Bencher, к которому подключаться. По умолчанию используется
https://api.bencher.dev. Также может быть задано переменной окруженияBENCHER_HOST.--runner <RUNNER>UUID или slug Runner, от имени которого работать. Также может быть задано переменной окружения
BENCHER_RUNNER.--key <KEY>Ключ аутентификации Runner (
bencher_runner_...), возвращённый при создании Runner. Также может быть задано переменной окруженияBENCHER_RUNNER_KEY.--poll-timeout <POLL_TIMEOUT>Тайм-аут длинного опроса в секундах при ожидании Job, от
1до900. По умолчанию используется55.--state-dir <STATE_DIR>Постоянный каталог состояния Runner. Путь должен быть абсолютным. Изолирующая среда (jail), ограничивающая песочницу, создаётся внутри этого каталога, а среды, оставшиеся после аварийного завершения, удаляются из него перед запуском каждого Job с песочницей. Каждая среда содержит полную корневую файловую систему гостя и копию двоичного файла microVM, а Runner выполняет свои Job по одному, поэтому этому каталогу нужен реальный объём для одной среды. С
--image-cache-sizeв нём также хранится кеш Image, до этого размера. На хосте одновременно работает только один Runner, независимо от его каталога состояния: Runner, запущенный от имениroot, удерживает блокировку/run/bencher/runner.lock, пока работает, а второй, запущенный от имениroot, сразу завершается с ошибкой, в которой названа эта блокировка; Runner, запущенный не от имениroot, не может открыть блокировку и работает без неё. При запуске и снова перед каждым Job с песочницей Runner, запущенный от имениroot, завершает любой процесс, который ещё выполняется в cgroup внутри/sys/fs/cgroup/bencher, например песочницу Runner, убитого посреди Job, независимо от каталога состояния этого Runner. Выделенная файловая система или монтированиеtmpfsподдерживается и рекомендуется: это уводит нагрузку на запись с системного диска, а только что созданная файловая система принимается, даже если в ней есть каталогlost+found. Файловая система не должна быть смонтирована сnodevилиnoexec, как часто бывает с/tmp,/dev/shmи/run, поэтому смонтируйте для неё отдельныйtmpfsбез этих опций. Сам каталог состояния может быть символической ссылкой, созданной root, на такую файловую систему, например/var/lib/bencher-runner, указывающей на выделенный диск. Ссылка используется только тогда, когда в каталог, содержащий её, может писать только root, она указывает прямо на свою конечную цель, и эта цель уже существует по пути, куда может писать только root; ссылка, цель которой ещё не существует, отклоняется, поэтому сначала создайте цель. По умолчанию используется/var/lib/bencher-runner. Также может быть задан переменной окруженияBENCHER_STATE_DIR.--jail-uid <JAIL_UID>Непривилегированный идентификатор пользователя, на который переходит процесс песочницы. По умолчанию используется
61016. Он не может быть равен0. Процесс на хосте, которому принадлежит этот идентификатор, может посылать сигналы песочнице, поэтому выберите идентификатор, который хост ни на что другое не выделяет. Также может быть задан переменной окруженияBENCHER_JAIL_UID.--jail-gid <JAIL_GID>Непривилегированный идентификатор группы, на который переходит процесс песочницы. По умолчанию используется
61016. Он не может быть равен0. Также может быть задан переменной окруженияBENCHER_JAIL_GID.--danger-allow-no-sandboxРазрешить выполнение Job без Sandbox. Без этого флага Job, чей Spec не имеет Sandbox, отклоняется во время выполнения. Не изолированные Job выполняются напрямую на хосте, поэтому включайте это только для доверенных нагрузок. Также может быть задано переменной окружения
BENCHER_DANGER_ALLOW_NO_SANDBOX.--sandbox-log-level <SANDBOX_LOG_LEVEL>Уровень логирования для процесса sandbox. По умолчанию используется
warning.--no-raid-pauseПродолжать принимать Job, пока md RAID массив на хосте выполняет ресинхронизацию, восстановление, проверку, исправление или перестроение. По умолчанию Runner проверяет свои md массивы перед запросом каждого Job, и пока любой из них выполняет одну из этих операций, Runner приостанавливается: он не принимает новый Job, пока синхронизация не завершится, и никогда не останавливает уже выполняющийся Job. Приостановленный Runner остается подключенным и продолжает обновляться.
--no-auto-updateОтключить автоматические обновления с сервера. По умолчанию runner обновляет себя между Job, когда сервер предлагает новую версию. Также может быть задано переменной окружения
BENCHER_NO_AUTO_UPDATE.--update-channel <UPDATE_CHANNEL>Канал автоматических обновлений: либо
stable, либоcanary. По умолчанию используетсяstable. Каналstableобновляет до версионированных релизов. Каналcanaryотслеживает скользящую canary-сборку, которая пересобирается всякий раз, когда runner меняется при деплое Bencher Cloud. Также может быть задано переменной окруженияBENCHER_UPDATE_CHANNEL. Конфликтует с--no-auto-update.--max-download-size <MAX_DOWNLOAD_SIZE>Максимальный размер загрузки в байтах для бинарных файлов самообновления. По умолчанию используется
500MiB. Конфликтует с--no-auto-update.--image-cache-size <IMAGE_CACHE_SIZE>Максимальный размер в байтах блобов Image, которые Runner хранит между Job. Runner хранит блобы конфигурации и слоёв каждого Image, который он загружает, в
blobsвнутри своего--state-dir, поэтому Job загружает только те блобы, которых у Runner ещё нет, но манифест своего Image по-прежнему каждый раз получает из реестра. Между Job Runner удаляет блобы, которые дольше всего не использовались, пока остальные не уместятся в этот размер. При запуске Runner создаёт хранилище и делает его своим, а если не может, сразу завершается с ошибкой, называющей каталог. По умолчанию, или при значении0, Runner не хранит блобы между Job и удаляет те, что хранил раньше. Также может быть задан переменной окруженияBENCHER_IMAGE_CACHE_SIZE.--max-output-size <MAX_OUTPUT_SIZE>Максимальный размер в байтах для собираемых
stdoutиstderr. По умолчанию используется25MiB.--max-file-count <MAX_FILE_COUNT>Максимальное количество выходных файлов для декодирования. По умолчанию используется
255.--max-symlinks <MAX_SYMLINKS>Максимальное количество символических ссылок, по которым следует переходить при разрешении путей, соответствующее ограничению
MAXSYMLINKSядра Linux. По умолчанию используется40. Используется только в не изолированном режиме.Тонкая настройка хоста
Перед каждым бенчмарком
runnerприменяет тонкую настройку хоста, чтобы снизить шум измерений. По умолчанию он отключает ASLR, NMI watchdog, SMT / hyper-threading и turbo boost; устанавливает регулятор масштабирования частоты CPU вperformance, swappiness в10, аperf_event_paranoidв-1. На хосте, которыйrunnerне настраивал с момента последней перезагрузки, флаги ниже вместо этого оставляют отдельные оптимизации на значениях хоста по умолчанию.Тонкая настройка хоста сохраняется до перезагрузки хоста: каждый параметр записывается только во время выполнения, и
runnerне откатывает его при завершении, кроме удержания C-состояний, которое прекращается при завершенииrunner. После запуска с тонкой настройкой флаг, который пропускает любой другой параметр, вступает в силу со следующей перезагрузки: до тех пор параметр сохраняет настроенное значение, аrunnerзаписывает это значение в журнал при запуске. Перезагрузите общий хост после удаленияrunner.--no-tuningОтключить все оптимизации тонкой настройки хоста.
--aslrНе отключать ASLR (по умолчанию: отключён для бенчмарков).
--nmi-watchdogНе отключать NMI watchdog (по умолчанию: отключён для бенчмарков).
--smtНе отключать SMT / hyper-threading (по умолчанию: отключён для бенчмарков).
--turboНе отключать turbo boost (по умолчанию: отключён для бенчмарков).
--numa-balancingНе отключать автоматическую балансировку NUMA (по умолчанию: отключена для бенчмарков).
--timer-migrationНе отключать миграцию таймеров (по умолчанию: отключена для бенчмарков).
--soft-watchdogНе отключать soft lockup watchdog (по умолчанию: отключён для бенчмарков).
--ksmНе отключать KSM, kernel samepage merging (по умолчанию: отключён для бенчмарков).
--cstatesНе отключать глубокие C-состояния (по умолчанию: отключены для бенчмарков).
--no-irq-steeringНе направлять IRQ устройств и рабочие очереди ядра на служебные ядра CPU.
--no-cpuset-partitionНе отделять ядра CPU для бенчмарков от планировщика с помощью изолированного раздела cpuset.
--swappiness <SWAPPINESS>Установить значение swappiness. По умолчанию используется
10.--governor <GOVERNOR>Установить регулятор масштабирования частоты CPU. По умолчанию используется
performance.--perf-event-paranoid <PERF_EVENT_PARANOID>Установить значение
perf_event_paranoid. По умолчанию используется-1.--thp <THP>Установить режим transparent hugepage на хосте:
never,madvise,alwaysилиleave. Со значениемleaveтекущий режим хоста сохраняется. По умолчанию используетсяnever.--helpВывести справку.
Все опции смотрите в справочнике по CLI runner,
а сообщения, которыми обмениваются с сервером, — в справочнике по Runner Protocol.
Обслуживание хоста
Runner и обслуживание его хоста, например обновление пакетов или проверка RAID, выполняются по очереди, поэтому обслуживание никогда не идет во время Job.
Очередность задается через /run/bencher, каталог, который Runner, запущенный от root, создает только для root:
- Блокировка Job,
/run/bencher/job.lock. Runner берет ее перед запросом Job и держит, пока этот опрос не закончится без Job или пока не закончится полученный Job. Обслуживание ждет эту блокировку, поэтому начинается только между Job, а Runner, обнаруживший занятую блокировку, не принимает Job, пока она не освободится. - Маркеры обслуживания,
/run/bencher/maintenanceили/run/bencher/maintenance.<name>. Обслуживание создает свой маркер перед тем, как ждать блокировку, и удаляет его по завершении. Пока существует хотя бы один маркер, Runner не запрашивает Job и оставляет блокировку свободной, поэтому ожидающее обслуживание начинается, как только закончится текущий опрос Runner или Job, полученный этим опросом.
Пока Runner ждет обслуживание, он приостановлен: он остается подключенным и продолжает обновляться.
runner run тоже ждет блокировку Job, а пока существует маркер или md массив синхронизируется, выводит предупреждение, но выполняется.
Runner, запущенный не от root, не может ни открыть блокировку Job, ни увидеть маркеры, поэтому принимает Job без них.
В systemd drop-in заставляет юнит обслуживания дожидаться своей очереди.
Например, /etc/systemd/system/fstrim.service.d/zz-bencher-quiet.conf оборачивает собственную команду юнита в flock -F.
Пустой ExecStart= сбрасывает эту команду, поэтому следующая строка должна точно ее повторить:
[Service]ExecStartPre=+/usr/bin/install -d -m 0700 /run/bencherExecStartPre=+/usr/bin/touch /run/bencher/maintenance.%nOpenFile=/dev/nullExecStart=ExecStart=/usr/bin/flock -F /run/bencher/job.lock /sbin/fstrim --listed-in /etc/fstab:/proc/self/mountinfo --verbose --quiet-unsupportedExecStopPost=+/bin/sh -c '/usr/bin/busctl get-property org.freedesktop.login1 /org/freedesktop/login1 org.freedesktop.login1.Manager PreparingForShutdown | /usr/bin/grep -q true || /usr/bin/rm -f /run/bencher/maintenance.%n'TimeoutStartSec=infinityOpenFile=/dev/null занимает файловый дескриптор 3, поэтому блокировка остается занятой, даже если команда заново открывает дескриптор 3, как это делает apt.systemd.daily.
Пока хост готовится к выключению, ExecStopPost= оставляет маркер, поэтому Runner не принимает Job, пока перезагрузка не очистит /run.
Освободить Runner
Чтобы освободить Runner от Job, создайте простой маркер от root:
touch /run/bencher/maintenanceRunner завершает текущий опрос, не дольше --poll-timeout секунд, и любой Job, который выполняется или получен этим опросом, после чего не принимает другой Job, пока маркер не исчезнет:
rm /run/bencher/maintenance/run очищается при загрузке, поэтому перезагрузка тоже удаляет маркер.
Рабочий процесс Self-Hosted Runner
Как только Runner подключён, вы отправляете бенчмарки так же, как и с любым Bare Metal Runner:
соберите и отправьте Image, затем запустите bencher run --image с соответствующим Spec.
Диаграмма ниже показывает полный путь, от регистрации Runner до выполнения Job.