En este artículo, se trata la zona de pruebas en Bazel, la instalación de sandboxfs
y la depuración
de tu entorno de zona de pruebas.
La zona de pruebas es una estrategia que restringe permisos y que aísla los procesos entre sí o de los recursos en un sistema. Para Bazel, esto significa restringir el acceso al sistema de archivos.
La zona de pruebas del sistema de archivos de Bazel ejecuta procesos en un directorio de trabajo que solo contiene entradas conocidas, de modo que los compiladores y otras herramientas no vean los archivos de origen a los que no deben acceder, a menos que conozcan las rutas de acceso absolutas a ellos.
Las zonas de pruebas no ocultan el entorno de host de ninguna manera. Los procesos pueden acceder libremente a todos los archivos del sistema de archivos. Sin embargo, en las plataformas que admiten espacios de nombres de usuarios, los procesos no pueden modificar ningún archivo fuera de su directorio de trabajo. Esto garantiza que el grafo de compilación no tenga dependencias ocultas que puedan afectar la reproducibilidad de la compilación.
Más específicamente, Bazel construye un directorio execroot/
para cada acción, que actúa como directorio de trabajo de la acción en el momento de la ejecución. execroot/
contiene todos los archivos de entrada a la acción y sirve como contenedor para las salidas generadas. Luego, Bazel usa una técnica proporcionada por el sistema operativo,
contenedores en Linux y sandbox-exec
en macOS, para limitar la acción dentro de
execroot/
.
Motivos de la zona de pruebas
Sin la zona de pruebas de acciones, Bazel no sabe si una herramienta usa archivos de entrada no declarados (archivos que no se enumeran de forma explícita en las dependencias de una acción). Cuando cambia uno de los archivos de entrada no declarados, Bazel aún cree que la compilación está actualizada y no volverá a compilar la acción. Esto puede dar como resultado una compilación incremental incorrecta.
La reutilización incorrecta de las entradas de caché crea problemas durante el almacenamiento en caché remota. Una entrada de caché incorrecta en una caché compartida afecta a cada desarrollador del proyecto, y limpiar toda la caché remota no es una solución factible.
La zona de pruebas imita el comportamiento de la ejecución remota: si una compilación funciona bien con la zona de pruebas, es probable que también funcione con la ejecución remota. Si haces que la ejecución remota suba todos los archivos necesarios (incluidas las herramientas locales), puedes reducir los costos de mantenimiento de los clústeres de compilación de forma significativa en comparación con tener que instalar las herramientas en cada máquina del clúster cada vez que quieras probar un compilador nuevo o realizar un cambio en una herramienta existente.
Qué estrategia de zona de pruebas usar
Puedes elegir qué tipo de zona de pruebas usar, si la hubiera, con las marcas de estrategia. El uso de la
estrategia sandboxed
hace que Bazel elija una de las implementaciones de las zonas de pruebas que se enumeran a continuación,
y prefieren una zona de pruebas específica del SO a la menos genérica.
Los trabajadores persistentes se ejecutan en una zona de pruebas genérica si pasas la marca --worker_sandboxing
.
La estrategia local
(también conocida como standalone
) no realiza ninguna clase de zona de pruebas.
Solo ejecuta la línea de comandos de la acción con el directorio de trabajo configurado en la exexroot de tu lugar de trabajo.
processwrapper-sandbox
es una estrategia de zona de pruebas que no requiere funciones "avanzadas". Debería funcionar en cualquier sistema POSIX listo para usar. Compila un directorio de zona de pruebas que consta de symlinks que apuntan a los archivos de origen originales, ejecuta la línea de comandos de la acción con el directorio de trabajo configurado en este directorio en lugar de execroot, luego mueve los artefactos de salida conocidos fuera de la zona de pruebas a execroot y borra la zona de pruebas. Esto evita que la acción use de manera accidental cualquier archivo de entrada que no esté declarado y que explote el execroot con archivos de salida desconocidos.
linux-sandbox
va un paso más allá y se basa en processwrapper-sandbox
. De manera similar a lo que Docker hace internamente, usa espacios de nombres de Linux (User, Mount, PID, Network y IPC) para aislar la acción del host. Es decir, hace que todo el sistema de archivos sea de solo lectura, excepto el directorio de la zona de pruebas, por lo que la acción no puede modificar nada de forma accidental en el sistema de archivos del host. Esto evita situaciones como una prueba con errores que, por accidente, inutiliza el directorio $HOME. De manera opcional, también puedes evitar que la acción acceda a la red. linux-sandbox
usa espacios de nombres PID para evitar que la acción vea cualquier otro proceso y terminar de forma confiable todos los procesos (incluso los daemons generados por la acción) al final.
darwin-sandbox
es similar, pero para macOS. Usa la herramienta sandbox-exec
de Apple
para lograr casi lo mismo que la zona de pruebas de Linux.
linux-sandbox
y darwin-sandbox
no funcionan en una situación "anidada" debido a restricciones en los mecanismos que proporcionan los sistemas operativos. Debido a que Docker también usa espacios de nombres de Linux para su magia de contenedor, no puedes ejecutar linux-sandbox
con facilidad dentro de un contenedor de Docker, a menos que uses docker run --privileged
. En macOS, no puedes ejecutar sandbox-exec
dentro de un proceso que ya está en zona de pruebas. Por lo tanto, en estos casos, Bazel
vuelve a usar processwrapper-sandbox
de forma automática.
Si prefieres obtener un error de compilación, como no crear de manera accidental con una estrategia de ejecución menos estricta, modifica de forma explícita la lista de estrategias de ejecución que Bazel intenta usar (por ejemplo, bazel build
--spawn_strategy=worker,linux-sandbox
).
Por lo general, la ejecución dinámica requiere de una zona de pruebas para la ejecución local. Para inhabilitarlos, pasa la marca --experimental_local_lockfree_output
. La ejecución dinámica silencia de forma silenciosa a los trabajadores persistentes.
Ventajas de la zona de pruebas
Las zonas de pruebas generan costos adicionales de configuración y desmontaje. El costo que se genere depende de muchos factores, como la forma de la compilación y el rendimiento del SO host. En Linux, las compilaciones de zona de pruebas casi nunca son más de un poco más lentas. Configurar
--reuse_sandbox_directories
puede mitigar el costo de configuración y desmontaje.La zona de pruebas inhabilita cualquier caché que pueda tener la herramienta. Puedes mitigar esto mediante trabajadores persistentes, a costa de garantías de zona de pruebas más débiles.
Los trabajadores multiplex requieren compatibilidad explícita con los trabajadores para la zona de pruebas. Los trabajadores que no admiten la zona de pruebas multiplex se ejecutan como trabajadores singleplex en ejecución dinámica, lo que puede tener un costo adicional de memoria.
zona de pruebas
sandboxfs
es un sistema de archivos FUSE que expone una vista arbitraria del sistema de archivos subyacente sin penalizaciones de tiempo. Bazel usa sandboxfs
a fin de
generar execroot/
de forma instantánea para cada acción, lo que evita el costo de
emitir miles de llamadas al sistema. Ten en cuenta que una mayor capacidad de E/S dentro de execroot/
podría ser más lenta debido a la sobrecarga de FUSE.
Instala sandboxfs
Usa los siguientes pasos para instalar sandboxfs
y realizar una compilación de Bazel con
ella:
Descargue
Descarga y, luego, instala sandboxfs
para que el objeto binario sandboxfs
termine en PATH
.
Ejecuta sandboxfs
- (Solo en macOS) Instala OSXFUSE.
Ejecución (solo en macOS):
sudo sysctl -w vfs.generic.osxfuse.tunables.allow_other=1
Deberás hacerlo después de la instalación y después de cada reinicio para asegurarte de que los servicios del sistema macOS principales funcionen mediante sandboxfs.
Ejecuta una compilación de Bazel con
--experimental_use_sandboxfs
.bazel build target --experimental_use_sandboxfs
Solución de problemas
Si ves local
en lugar de darwin-sandbox
o linux-sandbox
como una anotación para las acciones que se ejecutan, esto puede significar que la zona de pruebas está inhabilitada. Pasa --genrule_strategy=sandboxed --spawn_strategy=sandboxed
para habilitarlo.
Depuración
Sigue las estrategias a continuación para depurar problemas de la zona de pruebas.
Espacios de nombres desactivados
En algunas plataformas, como los nodos del clúster de Google Kubernetes Engine o Debian, los espacios de nombres de usuario se desactivan de forma predeterminada debido a problemas de seguridad. Si el archivo /proc/sys/kernel/unprivileged_userns_clone
existe y contiene un 0, puedes ejecutar lo siguiente para activar los espacios de nombres de usuario:
sudo sysctl kernel.unprivileged_userns_clone=1
Fallas en la ejecución de reglas
Es posible que la zona de pruebas no pueda ejecutar reglas debido a la configuración del sistema. Si ves un mensaje como namespace-sandbox.c:633: execvp(argv[0], argv): No such file or
directory
, intenta desactivar la zona de pruebas con --strategy=Genrule=local
para las reglas de generación y --spawn_strategy=local
para otras reglas.
Depuración detallada de fallas de compilación
Si tu compilación falló, usa --verbose_failures
y --sandbox_debug
para que
Bazel muestre el comando exacto que ejecutó cuando falló la compilación, incluida la parte
que configura la zona de pruebas.
Ejemplo de mensaje de error:
ERROR: path/to/your/project/BUILD:1:1: compilation of rule
'//path/to/your/project:all' failed:
Sandboxed execution failed, which may be legitimate (such as a compiler error),
or due to missing dependencies. To enter the sandbox environment for easier
debugging, run the following command in parentheses. On command failure, a bash
shell running inside the sandbox will then automatically be spawned
namespace-sandbox failed: error executing command
(cd /some/path && \
exec env - \
LANG=en_US \
PATH=/some/path/bin:/bin:/usr/bin \
PYTHONPATH=/usr/local/some/path \
/some/path/namespace-sandbox @/sandbox/root/path/this-sandbox-name.params --
/some/path/to/your/some-compiler --some-params some-target)
Ahora puedes inspeccionar el directorio de la zona de pruebas generado y ver qué archivos creó Bazel y volver a ejecutar el comando para ver su comportamiento.
Ten en cuenta que Bazel no borra el directorio de la zona de pruebas cuando usas
--sandbox_debug
. A menos que realices la depuración de forma activa, debes inhabilitar --sandbox_debug
porque llena tu disco con el paso del tiempo.