Como solucionar problemas de execução remota do Bazel com o sandbox do Docker

Reportar um problema Ver a fonte Nightly · 8.4 · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

As compilações do Bazel que são bem-sucedidas localmente podem falhar quando executadas remotamente devido a restrições e requisitos que não afetam as compilações locais. As causas mais comuns dessas falhas são descritas em Adaptação das regras do Bazel para execução remota.

Nesta página, descrevemos como identificar e resolver os problemas mais comuns que surgem com a execução remota usando o recurso de sandbox do Docker, que impõe restrições ao build iguais às da execução remota. Isso permite que você resolva problemas no build sem precisar de um serviço de execução remota.

O recurso de sandbox do Docker imita as restrições da execução remota da seguinte maneira:

  • As ações de build são executadas em contêineres de conjunto de ferramentas. É possível usar os mesmos contêineres de cadeia de ferramentas para executar a compilação local e remotamente por um serviço que ofereça suporte à execução remota em contêineres.

  • Nenhum dado estranho cruza o limite do contêiner. Somente as entradas e saídas declaradas explicitamente entram e saem do contêiner, e somente depois que a ação de build associada é concluída.

  • Cada ação é executada em um contêiner novo. Um contêiner novo e exclusivo é criado para cada ação de build gerada.

É possível resolver esses problemas usando um dos seguintes métodos:

  • Solução de problemas nativa Com esse método, o Bazel e as ações de build são executados de forma nativa na sua máquina local. O recurso de sandbox do Docker impõe restrições à build iguais às da execução remota. No entanto, esse método não detecta ferramentas, estados e dados locais que vazam para sua build, o que causa problemas com a execução remota.

  • Solução de problemas em um contêiner do Docker. Com esse método, o Bazel e as ações de build são executados em um contêiner do Docker, o que permite detectar ferramentas, estados e vazamento de dados da máquina local para o build, além de impor restrições iguais às da execução remota. Esse método fornece insights sobre sua build, mesmo que partes dela estejam falhando. Esse método é experimental e não tem suporte oficial.

Pré-requisitos

Antes de começar a resolver problemas, faça o seguinte se ainda não tiver feito isso:

  • Instale o Docker e configure as permissões necessárias para executá-lo.
  • Instale o Bazel 0.14.1 ou mais recente. As versões anteriores não são compatíveis com o recurso de sandbox do Docker.
  • Adicione o repositório bazel-toolchains, fixado na versão mais recente, ao arquivo WORKSPACE do build, conforme descrito neste link.
  • Adicione flags ao arquivo .bazelrc para ativar o recurso. Crie o arquivo no diretório raiz do projeto do Bazel, caso ele não exista. As flags abaixo são um exemplo de referência. Consulte o arquivo .bazelrc mais recente no repositório bazel-toolchains e copie os valores das flags definidas ali para a configuração 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

Se as regras exigirem ferramentas extras, faça o seguinte:

  1. Crie um contêiner do Docker personalizado instalando ferramentas usando um Dockerfile e criando a imagem localmente.

  2. Substitua o valor da flag --experimental_docker_image acima pelo nome da sua imagem de contêiner personalizada.

Solução de problemas nativa

Esse método executa o Bazel e todas as ações de build diretamente na máquina local e é uma maneira confiável de confirmar se o build será bem-sucedido quando executado remotamente.

No entanto, com esse método, ferramentas, binários e dados instalados localmente podem vazar para o build, especialmente se ele usar regras de WORKSPACE no estilo de configuração. Esses vazamentos causam problemas na execução remota. Para detectá-los, solucione problemas em um contêiner do Docker, além de fazer isso de forma nativa.

Etapa 1: executar o build

  1. Adicione a flag --config=docker-sandbox ao comando do Bazel que executa seu build. Exemplo:

    bazel --bazelrc=.bazelrc build --config=docker-sandbox target
  2. Execute o build e aguarde a conclusão. A build será executada até quatro vezes mais lenta do que o normal devido ao recurso de sandbox do Docker.

Talvez você encontre o seguinte erro:

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

Se sim, execute o build novamente com a flag --experimental_docker_verbose. Essa flag ativa mensagens de erro detalhadas. Esse erro geralmente é causado por uma instalação do Docker com falha ou falta de permissões para executá-lo na conta de usuário atual. Consulte a documentação do Docker para mais informações. Se os problemas persistirem, pule para Solução de problemas em um contêiner do Docker.

Etapa 2: resolver os problemas detectados

Confira a seguir os problemas mais comuns e as soluções alternativas.

  • Um arquivo, ferramenta, binário ou recurso referenciado pela árvore de arquivos de execução do Bazel está faltando. Confirme se todas as dependências das segmentações afetadas foram declaradas explicitamente. Consulte Gerenciar dependências implícitas para mais informações.

  • Um arquivo, uma ferramenta, um binário ou um recurso referenciado por um caminho absoluto ou pela variável PATH está ausente. Confirme se todas as ferramentas necessárias estão instaladas no contêiner do conjunto de ferramentas e use as regras do conjunto de ferramentas para declarar corretamente as dependências que apontam para o recurso ausente. Consulte Como invocar ferramentas de build usando regras de toolchain para mais informações.

  • Uma execução binária falha. Uma das regras de build está referenciando um binário incompatível com o ambiente de execução (o contêiner do Docker). Consulte Como gerenciar binários dependentes da plataforma para mais informações. Se não for possível resolver o problema, entre em contato com bazel-discuss@google.com para receber ajuda.

  • Um arquivo de @local-jdk está ausente ou causando erros. Os binários Java na máquina local estão vazando para o build e são incompatíveis com ele. Use java_toolchain nas suas regras e destinos em vez de @local_jdk. Entre em contato com bazel-discuss@google.com se precisar de mais ajuda.

  • Outros erros. Entre em contato com bazel-discuss@google.com para receber ajuda.

Solução de problemas em um contêiner do Docker

Com esse método, o Bazel é executado dentro de um contêiner Docker host, e as ações de build do Bazel são executadas dentro de contêineres de cadeia de ferramentas individuais gerados pelo recurso de sandbox do Docker. O sandbox gera um contêiner de conjunto de ferramentas totalmente novo para cada ação de build, e apenas uma ação é executada em cada contêiner de conjunto de ferramentas.

Esse método oferece um controle mais granular das ferramentas instaladas no ambiente do host. Ao separar a execução da build da execução das ações de build e manter as ferramentas instaladas no mínimo, é possível verificar se a build tem dependências no ambiente de execução local.

Etapa 1: criar o contêiner

  1. Crie um Dockerfile que crie o contêiner do Docker e instale o Bazel com um conjunto mínimo de ferramentas de build:

    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. Crie o contêiner como bazel_container:

    docker build -t bazel_container - < Dockerfile

Etapa 2: iniciar o contêiner

Inicie o contêiner do Docker usando o comando mostrado abaixo. No comando, substitua o caminho do código-fonte no host que você quer criar.

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

Esse comando executa o contêiner como raiz, mapeando o soquete do Docker e ativando o diretório /tmp. Isso permite que o Bazel gere outros contêineres do Docker e use diretórios em /tmp para compartilhar arquivos com eles. O código-fonte está disponível em /src dentro do contêiner.

O comando começa intencionalmente com um contêiner base debian:stretch que inclui binários incompatíveis com o contêiner rbe-ubuntu16-04 usado como um contêiner de cadeia de ferramentas. Se binários do ambiente local estiverem vazando para o contêiner do conjunto de ferramentas, eles vão causar erros de build.

Etapa 3: testar o contêiner

Execute os comandos a seguir no contêiner do Docker para testá-lo:

docker ps
bazel version

Etapa 4: executar o build

Execute o build conforme mostrado abaixo. O usuário de saída é root para que corresponda a um diretório acessível com o mesmo caminho absoluto de dentro do contêiner host em que o Bazel é executado, dos contêineres de conjunto de ferramentas gerados pelo recurso de sandbox do Docker em que as ações de build do Bazel estão sendo executadas e da máquina local em que os contêineres de host e ação são executados.

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

Etapa 5: resolver os problemas detectados

Para resolver falhas de build, faça o seguinte:

  • Se o build falhar com um erro de "falta de espaço em disco", aumente esse limite iniciando o contêiner host com a flag --memory=XX, em que XX é o espaço em disco alocado em gigabytes. Esse recurso é experimental e pode resultar em um comportamento imprevisível.

  • Se a build falhar durante as fases de análise ou carregamento, uma ou mais das regras de build declaradas no arquivo WORKSPACE não serão compatíveis com a execução remota. Consulte Como adaptar regras do Bazel para execução remota para possíveis causas e soluções alternativas.

  • Se o build falhar por qualquer outro motivo, consulte as etapas de solução de problemas em Etapa 2: resolver problemas detectados.