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 como root. 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 controladores cpuset, memory y pids habilitados. El Runner termina los procesos de un Job mediante el cgroup.kill de 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.

Terminal window
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:

Terminal window
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

Omite --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:

Terminal window
bencher runner spec add my-runner \
--host https://api.bencher.example.com \
--spec intel-v1

Elimina 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:

Terminal window
runner up \
--host https://api.bencher.example.com \
--runner my-runner \
--key bencher_runner_...
Terminal window
export BENCHER_HOST=https://api.bencher.example.com
export BENCHER_RUNNER=my-runner
export BENCHER_RUNNER_KEY=bencher_runner_...
runner up

El 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 up

    runner up

    Inicia 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 entorno BENCHER_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 entorno BENCHER_RUNNER_KEY.

    --poll-timeout <POLL_TIMEOUT>

    El tiempo de espera del long-poll en segundos mientras se espera un Job, entre 1 y 900. Por defecto, se usa 55.

    --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 como root mantiene el bloqueo /run/bencher/runner.lock mientras se ejecuta, y un segundo iniciado como root sale de inmediato con un error que nombra ese bloqueo; un Runner que no es root no puede abrir el bloqueo y se ejecuta sin él. Al arrancar, y de nuevo antes de cada Job con sandbox, un Runner iniciado como root termina 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 montaje tmpfs: mantiene esa carga de escritura fuera del disco del sistema, y se acepta un sistema de archivos recién creado aunque llegue con un directorio lost+found. El sistema de archivos no debe estar montado con nodev ni noexec, como suelen estarlo /tmp, /dev/shm y /run, así que monte para él un tmpfs sin 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-runner apuntando 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 entorno BENCHER_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 ser 0. 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 entorno BENCHER_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 ser 0. También se puede establecer con la variable de entorno BENCHER_JAIL_GID.

    --danger-allow-no-sandbox

    Permite 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-pause

    Seguir 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-update

    Desactiva 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 stable o canary. Por defecto, se usa stable. El canal stable actualiza a releases versionadas. El canal canary sigue 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 entorno BENCHER_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 500 MiB. 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 con 0, el Runner no conserva blobs entre Jobs y elimina los que haya conservado antes. También se puede establecer con la variable de entorno BENCHER_IMAGE_CACHE_SIZE.

    --max-output-size <MAX_OUTPUT_SIZE>

    El tamaño máximo en bytes para stdout y stderr recolectados. Por defecto, se usan 25 MiB.

    --max-file-count <MAX_FILE_COUNT>

    El número máximo de archivos de salida a decodificar. Por defecto, se usa 255.

    El número máximo de symlinks a seguir durante la resolución de rutas, coincidiendo con el límite MAXSYMLINKS del kernel de Linux. Por defecto, se usa 40. Solo se usa en modo sin sandbox.

    Ajuste del Host

    Antes de cada benchmark, el runner aplica 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 a performance, swappiness a 10, y perf_event_paranoid a -1. En un host al que el runner no 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 runner no revierte al salir, excepto la retención de los C-states, que termina cuando el runner sale. 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 el runner registra ese valor al iniciarse. Reinicie un host compartido después de quitar el runner.

    --no-tuning

    Desactiva todas las optimizaciones de ajuste del host.

    --aslr

    No desactiva ASLR (por defecto: desactivado para benchmarks).

    --nmi-watchdog

    No desactiva el watchdog NMI (por defecto: desactivado para benchmarks).

    --smt

    No desactiva SMT / hyper-threading (por defecto: desactivado para benchmarks).

    --turbo

    No desactiva turbo boost (por defecto: desactivado para benchmarks).

    --numa-balancing

    No desactiva el balanceo NUMA automático (por defecto: desactivado para benchmarks).

    --timer-migration

    No desactiva la migración de temporizadores (por defecto: desactivada para benchmarks).

    --soft-watchdog

    No desactiva el watchdog de soft lockup (por defecto: desactivado para benchmarks).

    --ksm

    No desactiva KSM, kernel samepage merging (por defecto: desactivado para benchmarks).

    --cstates

    No desactiva los C-states profundos (por defecto: desactivados para benchmarks).

    --no-irq-steering

    No dirige las IRQ de los dispositivos ni las workqueues del kernel a los núcleos de housekeeping.

    --no-cpuset-partition

    No 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, always o leave. Use leave para mantener el modo actual del host. Por defecto, se usa never.

    --help

    Imprime 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/maintenance o /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/bencher
ExecStartPre=+/usr/bin/touch /run/bencher/maintenance.%n
OpenFile=/dev/null
ExecStart=
ExecStart=/usr/bin/flock -F /run/bencher/job.lock /sbin/fstrim --listed-in /etc/fstab:/proc/self/mountinfo --verbose --quiet-unsupported
ExecStopPost=+/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=infinity

OpenFile=/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:

Terminal window
touch /run/bencher/maintenance

El 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:

Terminal window
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.

OCI Registryrunner binaryAPI ServerOCI Registryrunner binaryAPI ServerAdminbencher runner createRunner + keybencher spec createbencher runner spec addrunner up --host --runner --keyConnect (WebSocket) and poll for JobsAssign matching JobPull ImageImage layersRun benchmarkSubmit resultsAdmin

Continúa: Referencia de la CLI runner ➡

🤖 Este documento fue traducido automáticamente por IA. Puede que no sea exacto y contenga errores. Si encuentra algún error, abra un problema en GitHub.


Published: Fri, June 19, 2026 at 8:00:00 AM UTC | Last Updated: Fri, October 9, 2026 at 3:39:11 PM UTC