Bare Metal Runners Autoalojados
Un Runner Autoalojado es un Bare Metal Runner que ejecutas y gestionas tú mismo,
en lugar de usar un Runner On-Demand o Dedicated gestionado por Bencher.
Apuntas el binario runner a un servidor API de Bencher,
y este reclama y ejecuta Jobs en tu propio hardware.
Autoalojar un Runner es una buena opción cuando quieres:
- Ejecutar benchmarks en hardware específico que Bencher Cloud no ofrece
- Mantener las cargas de trabajo de benchmark dentro de tu propia red o un entorno aislado (air-gapped)
- Ejecutar Bencher Self-Hosted de principio a fin
Esta guía recorre el registro de un Runner, la descripción de su hardware con un Spec,
la vinculación de ambos, y el inicio del binario runner.
Para una visión general conceptual de cómo encajan Runners, Specs, Sandboxes y Jobs,
consulta la Visión General de Bare Metal.
🐰 El sandboxing con Firecracker requiere Linux 5.14 o posterior con KVM habilitado y una jerarquía cgroup v2 con permiso de escritura en
/sys/fs/cgroup, y el Runner debe ejecutarse comoroot. Cada Job con sandbox se ejecuta en su propio cgroup bajo/sys/fs/cgroup/bencher, sea cual sea el número de núcleos de CPU, con los controladorescpuset,memoryypidshabilitados. El Runner termina los procesos de un Job mediante elcgroup.killde ese cgroup, que los kernels más antiguos no tienen: en ellos un Runner sale al arrancar o, iniciado con--danger-allow-no-sandbox, hace fallar cada Job con sandbox. El proceso de Firecracker detrás de cada Job con sandbox queda confinado en un chroot como usuario sin privilegios, y construir ese confinamiento necesita permisos que habilitar KVM por sí solo no concede. Un Runner que solo sirve Specs sin sandbox puede ejecutarse en cualquier host compatible.
Crear un Runner
Un Runner es el recurso que autentica el binario runner con tu servidor API de Bencher.
Crea uno con la CLI bencher,
la API REST de Runners,
o la Bencher Console.
bencher runner create \ --host https://api.bencher.example.com \ --name "My Runner"Bencher devuelve el nuevo Runner junto con su clave:
{ "uuid": "...", "key": "bencher_runner_..."}La clave solo se muestra una vez, así que guárdala de forma segura.
Se la pasarás al binario runner cuando inicies el Runner.
Si una clave se pierde o se filtra alguna vez, rótala con la API POST /v0/runners/{runner}/key,
lo cual invalida inmediatamente la clave anterior.
Crear un Spec
Un Spec describe el hardware que proporciona un Runner: sistema operativo, arquitectura de CPU, tipo de Sandbox, número de CPU, memoria, disco y acceso a la red. Un Job declara el Spec que necesita, y un Runner solo reclama Jobs para los Specs que soporta.
Crea un Spec con la CLI bencher,
la API REST de Specs,
o la 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 137438953472Omite --sandbox para definir un Spec sin sandbox,
y pasa --network si los Jobs en este Spec tienen permitido el acceso a la red.
La memoria y el disco se especifican en bytes.
Para más sobre los Specs y cómo un Testbed registra el Spec usado para cada Report,
consulta Testbeds & Specs.
Asignar un Spec a un Runner
Un Runner Spec vincula un Spec a un Runner. Un Runner puede soportar múltiples Specs, y un Spec puede ser soportado por múltiples Runners. Un Runner solo reclama Jobs cuyo Spec le ha sido asignado.
Añade un Spec a un Runner con la CLI bencher
o la API REST de Runner Specs:
bencher runner spec add my-runner \ --host https://api.bencher.example.com \ --spec intel-v1Elimina la vinculación más tarde con la API DELETE /v0/runners/{runner}/specs/{spec}.
Iniciar el Runner
Con un Runner creado y al menos un Spec asignado,
inicia el binario runner en tu hardware con runner up.
Proporciona el host del servidor API, el UUID o slug del Runner, y la clave del Runner,
ya sea como flags o variables de entorno:
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 upEl binario runner abre una única conexión WebSocket al servidor API,
sondea Jobs que coincidan con sus Specs, ejecuta cada uno, y reporta los resultados de vuelta.
La conexión permanece abierta entre Jobs,
y el binario se actualiza a sí mismo entre Jobs cuando hay una nueva versión disponible.
Por defecto, el Runner sigue el canal de actualización stable
y solo se actualiza a releases versionadas.
El canal canary sigue en cambio la compilación canary continua desplegada en Bencher Cloud.
Un Runner que ejecuta Jobs con sandbox debe correr como root,
así que los comandos anteriores se muestran tal como los ejecutaría el usuario root,
o bajo un gestor de servicios que inicie el Runner como root.
Por defecto, un Runner rechaza cualquier Job cuyo Spec no tenga Sandbox.
Para permitir que un Runner ejecute Jobs sin sandbox directamente en el host,
inícialo con el flag --danger-allow-no-sandbox.
runner uprunner upInicia el runner, sondeando y ejecutando Jobs de benchmark. Este es el comando de larga duración usado para operar un Runner Autoalojado. El runner abre una única conexión WebSocket al servidor API, reclama Jobs que coincidan con sus Specs, los ejecuta, y reporta los resultados de vuelta. El runner escribe su registro en stderr como JSON, un objeto por línea, y registra la salida de un Job solo como conteos de bytes.
runner up [OPTIONS]Opciones
--host <HOST>El servidor API de Bencher al que conectarse. Por defecto, se usa
https://api.bencher.dev. También se puede establecer con la variable de entornoBENCHER_HOST.--runner <RUNNER>El UUID o slug del Runner como el que operar. También se puede establecer con la variable de entorno
BENCHER_RUNNER.--key <KEY>La clave de autenticación del Runner (
bencher_runner_...) devuelta cuando se creó el Runner. También se puede establecer con la variable de entornoBENCHER_RUNNER_KEY.--poll-timeout <POLL_TIMEOUT>El tiempo de espera del long-poll en segundos mientras se espera un Job, entre
1y900. Por defecto, se usa55.--state-dir <STATE_DIR>El directorio de estado persistente del Runner. Debe ser una ruta absoluta. La jaula que confina el sandbox se crea dentro de este directorio, y las jaulas que quedaron tras una salida no limpia se eliminan de él antes de cada Job con sandbox. Cada jaula contiene un sistema de archivos raíz completo del huésped y una copia del binario de la microVM, y un Runner ejecuta sus Jobs de uno en uno, por lo que este directorio necesita capacidad real para una jaula. Con
--image-cache-size, también guarda la caché de Image, hasta ese tamaño. Un host ejecuta un solo Runner a la vez, sea cual sea su directorio de estado: un Runner iniciado comorootmantiene el bloqueo/run/bencher/runner.lockmientras se ejecuta, y un segundo iniciado comorootsale de inmediato con un error que nombra ese bloqueo; un Runner que no esrootno puede abrir el bloqueo y se ejecuta sin él. Al arrancar, y de nuevo antes de cada Job con sandbox, un Runner iniciado comoroottermina cualquier proceso que siga ejecutándose en un cgroup bajo/sys/fs/cgroup/bencher, como la sandbox de un Runner terminado a mitad de un Job, sea cual sea el directorio de estado de ese Runner. Se admite y se recomienda un sistema de archivos dedicado o un montajetmpfs: mantiene esa carga de escritura fuera del disco del sistema, y se acepta un sistema de archivos recién creado aunque llegue con un directoriolost+found. El sistema de archivos no debe estar montado connodevninoexec, como suelen estarlo/tmp,/dev/shmy/run, así que monte para él untmpfssin esas opciones. El propio directorio de estado puede ser un enlace simbólico creado por root hacia un sistema de archivos así, como/var/lib/bencher-runnerapuntando a un disco dedicado. El enlace solo se sigue cuando el directorio que lo contiene solo puede ser escrito por root, apunta directamente a su destino final, y ese destino ya existe en una ruta que solo root puede escribir; un enlace cuyo destino aún no existe se rechaza, así que cree primero el destino. Por defecto, se usa/var/lib/bencher-runner. También se puede establecer con la variable de entornoBENCHER_STATE_DIR.--jail-uid <JAIL_UID>El ID de usuario sin privilegios al que cambia el proceso del sandbox. Por defecto, se usa
61016. No puede ser0. Un proceso del host que sea propietario de ese ID de usuario puede enviar señales al sandbox, así que asígnele un ID que el host no destine a ninguna otra cosa. También se puede establecer con la variable de entornoBENCHER_JAIL_UID.--jail-gid <JAIL_GID>El ID de grupo sin privilegios al que cambia el proceso del sandbox. Por defecto, se usa
61016. No puede ser0. También se puede establecer con la variable de entornoBENCHER_JAIL_GID.--danger-allow-no-sandboxPermite ejecutar Jobs sin un Sandbox. Sin este flag, un Job cuyo Spec no tenga Sandbox se rechaza en tiempo de ejecución. Los Jobs sin sandbox se ejecutan directamente en el host, así que solo habilita esto para cargas de trabajo de confianza. También se puede establecer con la variable de entorno
BENCHER_DANGER_ALLOW_NO_SANDBOX.--sandbox-log-level <SANDBOX_LOG_LEVEL>El nivel de log para el proceso del sandbox. Por defecto, se usa
warning.--no-raid-pauseSeguir aceptando Jobs mientras un array RAID md del host se resincroniza, se recupera, se verifica, se repara o se remodela. Por defecto, el Runner revisa sus arrays md antes de pedir cada Job, y mientras alguno de ellos ejecuta una de estas operaciones se pausa: no acepta ningún Job nuevo hasta que termine la sincronización, y nunca detiene un Job que ya se está ejecutando. Un Runner pausado sigue conectado y se sigue actualizando a sí mismo.
--no-auto-updateDesactiva las actualizaciones automáticas desde el servidor. Por defecto, el runner se actualiza a sí mismo entre Jobs cuando el servidor ofrece una nueva versión. También se puede establecer con la variable de entorno
BENCHER_NO_AUTO_UPDATE.--update-channel <UPDATE_CHANNEL>El canal de actualización para las actualizaciones automáticas, ya sea
stableocanary. Por defecto, se usastable. El canalstableactualiza a releases versionadas. El canalcanarysigue la compilación canary continua, que se reconstruye cada vez que el runner cambia en un despliegue de Bencher Cloud. También se puede establecer con la variable de entornoBENCHER_UPDATE_CHANNEL. Entra en conflicto con--no-auto-update.--max-download-size <MAX_DOWNLOAD_SIZE>El tamaño máximo de descarga en bytes para los binarios de auto-actualización. Por defecto, se usan
500MiB. Entra en conflicto con--no-auto-update.--image-cache-size <IMAGE_CACHE_SIZE>El tamaño máximo en bytes de los blobs de Image que el Runner conserva entre Jobs. El Runner conserva los blobs de configuración y de capas de cada Image que descarga en
blobs, dentro de su--state-dir, de modo que un Job descarga solo los blobs que el Runner aún no tiene, aunque sigue obteniendo el manifiesto de su Image del registro cada vez. Entre Jobs, el Runner elimina los blobs usados hace más tiempo hasta que el resto cabe en este tamaño. Al iniciar, el Runner crea el almacén y lo hace suyo, y si no puede, termina de inmediato con un error que nombra el directorio. Por defecto, o con0, el Runner no conserva blobs entre Jobs y elimina los que haya conservado antes. También se puede establecer con la variable de entornoBENCHER_IMAGE_CACHE_SIZE.--max-output-size <MAX_OUTPUT_SIZE>El tamaño máximo en bytes para
stdoutystderrrecolectados. Por defecto, se usan25MiB.--max-file-count <MAX_FILE_COUNT>El número máximo de archivos de salida a decodificar. Por defecto, se usa
255.--max-symlinks <MAX_SYMLINKS>El número máximo de symlinks a seguir durante la resolución de rutas, coincidiendo con el límite
MAXSYMLINKSdel kernel de Linux. Por defecto, se usa40. Solo se usa en modo sin sandbox.Ajuste del Host
Antes de cada benchmark, el
runneraplica ajustes al host para reducir el ruido de medición. Por defecto, desactiva ASLR, el watchdog NMI, SMT / hyper-threading, y turbo boost; establece el governor de escalado de CPU aperformance, swappiness a10, yperf_event_paranoida-1. En un host al que elrunnerno ha aplicado ajustes desde su último reinicio, los flags de abajo mantienen las optimizaciones individuales en sus valores por defecto del host en su lugar.El ajuste del host persiste hasta que el host se reinicia: cada ajuste es una escritura solo en tiempo de ejecución que el
runnerno revierte al salir, excepto la retención de los C-states, que termina cuando elrunnersale. Tras una ejecución con ajustes, un flag que omite cualquier otro ajuste surte efecto a partir del siguiente reinicio: hasta entonces, el ajuste conserva su valor ajustado, y elrunnerregistra ese valor al iniciarse. Reinicie un host compartido después de quitar elrunner.--no-tuningDesactiva todas las optimizaciones de ajuste del host.
--aslrNo desactiva ASLR (por defecto: desactivado para benchmarks).
--nmi-watchdogNo desactiva el watchdog NMI (por defecto: desactivado para benchmarks).
--smtNo desactiva SMT / hyper-threading (por defecto: desactivado para benchmarks).
--turboNo desactiva turbo boost (por defecto: desactivado para benchmarks).
--numa-balancingNo desactiva el balanceo NUMA automático (por defecto: desactivado para benchmarks).
--timer-migrationNo desactiva la migración de temporizadores (por defecto: desactivada para benchmarks).
--soft-watchdogNo desactiva el watchdog de soft lockup (por defecto: desactivado para benchmarks).
--ksmNo desactiva KSM, kernel samepage merging (por defecto: desactivado para benchmarks).
--cstatesNo desactiva los C-states profundos (por defecto: desactivados para benchmarks).
--no-irq-steeringNo dirige las IRQ de los dispositivos ni las workqueues del kernel a los núcleos de housekeeping.
--no-cpuset-partitionNo separa los núcleos de benchmark del planificador mediante una partición cpuset aislada.
--swappiness <SWAPPINESS>Establece el valor de swappiness. Por defecto, se usa
10.--governor <GOVERNOR>Establece el governor de escalado de CPU. Por defecto, se usa
performance.--perf-event-paranoid <PERF_EVENT_PARANOID>Establece el valor de
perf_event_paranoid. Por defecto, se usa-1.--thp <THP>Establece el modo de transparent hugepage del host:
never,madvise,alwaysoleave. Useleavepara mantener el modo actual del host. Por defecto, se usanever.--helpImprime la ayuda.
Consulta la referencia de la CLI runner para conocer todas las opciones,
y la referencia del Protocolo Runner para los mensajes intercambiados con el servidor.
Mantenimiento del host
Un Runner y el mantenimiento de su host, como las actualizaciones de paquetes o una verificación de RAID, se turnan, de modo que el mantenimiento nunca se ejecuta durante un Job.
Se turnan a través de /run/bencher, un directorio que un Runner iniciado como root crea solo para root:
- El bloqueo de Job,
/run/bencher/job.lock. El Runner lo toma antes de pedir un Job y lo mantiene hasta que esa consulta termine sin Job o termine el Job que traiga. El mantenimiento espera el bloqueo, así que solo comienza entre Jobs, y un Runner que encuentra el bloqueo tomado no acepta ningún Job hasta que quede libre. - Marcadores de mantenimiento,
/run/bencher/maintenanceo/run/bencher/maintenance.<name>. El mantenimiento crea su propio marcador antes de esperar el bloqueo y lo elimina cuando termina. Mientras exista algún marcador, el Runner no pide ningún Job y deja el bloqueo libre, así que el mantenimiento en espera comienza en cuanto termina la consulta actual del Runner, o el Job que esa consulta traiga.
Mientras espera el mantenimiento, un Runner está pausado: sigue conectado y se sigue actualizando a sí mismo.
runner run también espera el bloqueo de Job, y advierte pero se ejecuta mientras exista un marcador o un array md se sincronice.
Un Runner que no es root no puede abrir el bloqueo de Job ni ver los marcadores, así que acepta Jobs sin ellos.
Con systemd, un drop-in hace que una unidad de mantenimiento espere su turno.
Por ejemplo, /etc/systemd/system/fstrim.service.d/zz-bencher-quiet.conf envuelve el comando propio de la unidad en flock -F.
El ExecStart= vacío borra ese comando, así que la línea siguiente debe repetirlo exactamente:
[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 ocupa el descriptor de archivo 3, así que el bloqueo sigue tomado aunque el comando reabra el descriptor 3, como hace apt.systemd.daily.
Mientras el host se prepara para apagarse, ExecStopPost= deja el marcador, así que el Runner no acepta ningún Job antes de que el reinicio vacíe /run.
Vaciar un Runner
Para vaciar un Runner, crea el marcador simple como root:
touch /run/bencher/maintenanceEl Runner termina su consulta actual, como máximo --poll-timeout segundos, y cualquier Job en ejecución o que traiga esa consulta, y luego no acepta ningún otro Job hasta que el marcador desaparezca:
rm /run/bencher/maintenance/run se vacía al arrancar, así que un reinicio también elimina el marcador.
Flujo de Trabajo del Runner Autoalojado
Una vez que el Runner está conectado, envías benchmarks de la misma forma que con cualquier Bare Metal Runner:
construyes y subes una Image, luego ejecutas bencher run --image con un Spec coincidente.
El diagrama de abajo muestra la ruta completa, desde el registro del Runner hasta la ejecución de un Job.