Solucionar problemas de ejecución remota de Bazel con Docker Sandbox

Denuncia un problema Ver fuente Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Las compilaciones de Bazel que se realizan correctamente de forma local pueden fallar cuando se ejecutan de forma remota debido a restricciones y requisitos que no afectan a las compilaciones locales. Las causas más comunes de estas fallas se describen en Adaptación de las reglas de Bazel para la ejecución remota.

En esta página, se describe cómo identificar y resolver los problemas más comunes que aparecen con la ejecución remota mediante la función de zona de pruebas de Docker, que impone restricciones a la compilación iguales a las de la ejecución remota. Esto te permite solucionar problemas de la compilación sin la necesidad de un servicio de ejecución remota.

La función de la zona de pruebas de Docker imita las restricciones de la ejecución remota de la siguiente manera:

  • Las acciones de compilación se ejecutan en contenedores de cadena de herramientas. Puedes usar los mismos contenedores de cadena de herramientas para ejecutar tu compilación de forma local y remota a través de un servicio que admita la ejecución remota en contenedores.

  • No hay datos ajenos que crucen el límite del contenedor. Solo las entradas y salidas declaradas de forma explícita entran y salen del contenedor, y solo después de que se completa correctamente la acción de compilación asociada.

  • Cada acción se ejecuta en un contenedor nuevo. Se crea un contenedor nuevo y único para cada acción de compilación generada.

Puedes solucionar estos problemas con uno de los siguientes métodos:

  • Solución de problemas de forma nativa. Con este método, Bazel y sus acciones de compilación se ejecutan de forma nativa en tu máquina local. La función de zona de pruebas de Docker impone restricciones a la compilación iguales a las de la ejecución remota. Sin embargo, este método no detectará las herramientas, los estados ni los datos locales que se filtren en tu compilación, lo que causará problemas con la ejecución remota.

  • Soluciona problemas en un contenedor de Docker. Con este método, Bazel y sus acciones de compilación se ejecutan dentro de un contenedor de Docker, lo que te permite detectar herramientas, estados y filtraciones de datos de la máquina local a la compilación, además de imponer restricciones iguales a las de la ejecución remota. Este método proporciona estadísticas sobre tu compilación, incluso si algunas partes fallan. Este método es experimental y no se admite oficialmente.

Requisitos previos

Antes de comenzar a solucionar el problema, haz lo siguiente si aún no lo hiciste:

  • Instala Docker y configura los permisos necesarios para ejecutarlo.
  • Instala Bazel 0.14.1 o una versión posterior. Las versiones anteriores no admiten la función de zona de pruebas de Docker.
  • Agrega el repositorio bazel-toolchains, fijado a la versión de lanzamiento más reciente, al archivo WORKSPACE de tu compilación, como se describe aquí.
  • Agrega marcas a tu archivo .bazelrc para habilitar la función. Crea el archivo en el directorio raíz de tu proyecto de Bazel si no existe. Las marcas que aparecen a continuación son una muestra de referencia. Consulta el archivo .bazelrc más reciente en el repositorio de bazel-toolchains y copia los valores de las marcas definidas allí para la configuración docker-sandbox.
# Docker Sandbox Mode
build:docker-sandbox --host_javabase=<...>
build:docker-sandbox --javabase=<...>
build:docker-sandbox --crosstool_top=<...>
build:docker-sandbox --experimental_docker_image=<...>
build:docker-sandbox --spawn_strategy=docker --strategy=Javac=docker --genrule_strategy=docker
build:docker-sandbox --define=EXECUTOR=remote
build:docker-sandbox --experimental_docker_verbose
build:docker-sandbox --experimental_enable_docker_sandbox

Si tus reglas requieren herramientas adicionales, haz lo siguiente:

  1. Crea un contenedor de Docker personalizado instalando herramientas con un Dockerfile y compilando la imagen de forma local.

  2. Reemplaza el valor de la marca --experimental_docker_image anterior por el nombre de tu imagen de contenedor personalizada.

Cómo solucionar problemas de forma nativa

Este método ejecuta Bazel y todas sus acciones de compilación directamente en la máquina local y es una forma confiable de confirmar si tu compilación se realizará correctamente cuando se ejecute de forma remota.

Sin embargo, con este método, es posible que las herramientas, los objetos binarios y los datos instalados de forma local se filtren en tu compilación, en especial si usa reglas WORKSPACE de estilo de configuración. Estas fugas causarán problemas con la ejecución remota. Para detectarlas, soluciona problemas en un contenedor de Docker además de solucionar problemas de forma nativa.

Paso 1: Ejecuta la compilación

  1. Agrega la marca --config=docker-sandbox al comando de Bazel que ejecuta la compilación. Por ejemplo:

    bazel --bazelrc=.bazelrc build --config=docker-sandbox target
    
  2. Ejecuta la compilación y espera a que se complete. La compilación se ejecutará hasta cuatro veces más lento de lo normal debido a la función de zona de pruebas de Docker.

Es posible que se muestre el siguiente error:

ERROR: 'docker' is an invalid value for docker spawn strategy.

Si es así, vuelve a ejecutar la compilación con la marca --experimental_docker_verbose. Esta marca habilita los mensajes de error detallados. Por lo general, este error se debe a una instalación defectuosa de Docker o a la falta de permisos para ejecutarlo en la cuenta de usuario actual. Consulta la documentación de Docker para obtener más información. Si los problemas persisten, ve a Solución de problemas en un contenedor de Docker.

Paso 2: Resuelve los problemas detectados

Los siguientes son los problemas más comunes y sus soluciones alternativas.

Soluciona problemas en un contenedor de Docker

Con este método, Bazel se ejecuta dentro de un contenedor de Docker host, y las acciones de compilación de Bazel se ejecutan dentro de contenedores de cadena de herramientas individuales generados por la función de zona de pruebas de Docker. La zona de pruebas genera un contenedor de cadena de herramientas nuevo para cada acción de compilación y solo se ejecuta una acción en cada contenedor de cadena de herramientas.

Este método proporciona un control más detallado de las herramientas instaladas en el entorno del host. Si separas la ejecución de la compilación de la ejecución de sus acciones de compilación y mantienes al mínimo las herramientas instaladas, puedes verificar si tu compilación tiene alguna dependencia en el entorno de ejecución local.

Paso 1: Compila el contenedor

  1. Crea un Dockerfile que cree el contenedor de Docker y, luego, instale Bazel con un conjunto mínimo de herramientas de compilación:

    FROM debian:stretch
    
    RUN apt-get update && apt-get install -y apt-transport-https curl software-properties-common git gcc gnupg2 g++ openjdk-8-jdk-headless python-dev zip wget vim
    
    RUN curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add -
    
    RUN add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable"
    
    RUN apt-get update && apt-get install -y docker-ce
    
    RUN wget https://releases.bazel.build/<latest Bazel version>/release/bazel-<latest Bazel version>-installer-linux-x86_64.sh -O ./bazel-installer.sh && chmod 755 ./bazel-installer.sh
    
    RUN ./bazel-installer.sh
    
  2. Compila el contenedor como bazel_container:

    docker build -t bazel_container - < Dockerfile
    

Paso 2: Inicia el contenedor

Inicia el contenedor de Docker con el siguiente comando. En el comando, reemplaza la ruta de acceso al código fuente en el host que deseas compilar.

docker run -it \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -v /tmp:/tmp \
  -v your source code directory:/src \
  -w /src \
  bazel_container \
  /bin/bash

Este comando ejecuta el contenedor como raíz, asigna el socket de Docker y activa el directorio /tmp. Esto permite que Bazel genere otros contenedores de Docker y use directorios en /tmp para compartir archivos con esos contenedores. Tu código fuente está disponible en /src dentro del contenedor.

El comando se inicia de forma intencional desde un contenedor base debian:stretch que incluye objetos binarios incompatibles con el contenedor rbe-ubuntu16-04 que se usa como contenedor de la cadena de herramientas. Si se filtran objetos binarios del entorno local en el contenedor de la cadena de herramientas, se producirán errores de compilación.

Paso 3: Prueba el contenedor

Ejecuta los siguientes comandos desde el contenedor de Docker para probarlo:

docker ps
bazel version

Paso 4: Ejecuta la compilación

Ejecuta la compilación como se muestra a continuación. El usuario de salida es root, por lo que corresponde a un directorio al que se puede acceder con la misma ruta de acceso absoluta desde el interior del contenedor de host en el que se ejecuta Bazel, desde los contenedores de cadena de herramientas generados por la función de zona de pruebas de Docker en la que se ejecutan las acciones de compilación de Bazel y desde la máquina local en la que se ejecutan los contenedores de host y de acción.

bazel --output_user_root=/tmp/bazel_docker_root --bazelrc=.bazelrc \ build --config=docker-sandbox target

Paso 5: Resuelve los problemas detectados

Puedes resolver las fallas de compilación de la siguiente manera:

  • Si la compilación falla con un error de "sin espacio en el disco", puedes aumentar este límite iniciando el contenedor host con la marca --memory=XX, donde XX es el espacio en el disco asignado en gigabytes. Esto es experimental y puede generar un comportamiento impredecible.

  • Si la compilación falla durante las fases de análisis o carga, significa que una o más de las reglas de compilación declaradas en el archivo WORKSPACE no son compatibles con la ejecución remota. Consulta Adapta las reglas de Bazel para la ejecución remota a fin de conocer las posibles causas y soluciones alternativas.

  • Si la compilación falla por algún otro motivo, consulta los pasos para solucionar problemas en el Paso 2: Soluciona los problemas detectados.