En esta página, se aborda el almacenamiento en caché remoto, la configuración de un servidor para alojar la caché y la ejecución de compilaciones con la caché remota.
Un equipo de desarrolladores o un sistema de integración continua (CI) usa una caché remota para compartir resultados de compilación. Si tu compilación es reproducible, los resultados de una máquina se pueden reutilizar de forma segura en otra, lo que puede hacer que las compilaciones sean mucho más rápidas.
Descripción general
Bazel divide una compilación en pasos discretos, que se denominan acciones. Cada acción tiene entradas, nombres de salida, una línea de comandos y variables de entorno. Las entradas requeridas y las salidas esperadas se declaran explícitamente para cada acción.
Puedes configurar un servidor para que sea una caché remota para los resultados de compilación, que son los resultados de estas acciones. Estos resultados consisten en una lista de nombres de archivos de salida y los hashes de su contenido. Con una caché remota, puedes reutilizar los resultados de la compilación de otro usuario, en lugar de compilar cada resultado nuevo de forma local.
Para usar el almacenamiento en caché remoto, haz lo siguiente:
- Configura un servidor como backend de la caché.
- Configura la compilación de Bazel para usar la caché remota.
- Usa la versión 0.10.0 de Bazel o una posterior.
La caché remota almacena dos tipos de datos:
- La caché de acciones, que es un mapa de hashes de acciones a metadatos de resultados de acciones.
- Un almacén direccionable por contenido (CAS) de archivos de salida.
Ten en cuenta que la caché remota también almacena stdout y stderr para cada acción. Por lo tanto, inspeccionar stdout/stderr de Bazel no es una buena señal para estimar los aciertos de caché.
Cómo una compilación usa el almacenamiento en caché remoto
Una vez que se configura un servidor como caché remota, puedes usar la caché de varias maneras:
- Leer y escribir en la caché remota
- Leer o escribir en la caché remota, excepto para destinos específicos
- Solo leer desde la caché remota
- No usar la caché remota en absoluto
Cuando ejecutas una compilación de Bazel que puede leer y escribir en la caché remota, la compilación sigue estos pasos:
- Bazel crea el gráfico de destinos que se deben compilar y, luego, crea una lista de acciones requeridas. Cada una de estas acciones tiene entradas declaradas y nombres de archivos de salida.
- Bazel verifica tu máquina local en busca de resultados de compilación existentes y reutiliza los que encuentra.
- Bazel verifica la caché en busca de resultados de compilación existentes. Si se encuentra el resultado, Bazel lo recupera. Esto es un acierto de caché.
- Para las acciones requeridas en las que no se encontraron los resultados, Bazel ejecuta las acciones de forma local y crea los resultados de compilación requeridos.
- Los resultados de compilación nuevos se suben a la caché remota.
Configura un servidor como backend de la caché
Debes configurar un servidor para que actúe como backend de la caché. Un servidor HTTP/1.1 puede tratar los datos de Bazel como bytes opacos, por lo que muchos servidores existentes se pueden usar como backend de almacenamiento en caché remoto. El protocolo de almacenamiento en caché HTTP de Bazel es lo que admite el almacenamiento en caché remoto.
Eres responsable de elegir, configurar y mantener el servidor de backend que almacenará los resultados almacenados en caché. Cuando elijas un servidor, ten en cuenta lo siguiente:
- Velocidad de la red (por ejemplo, si tu equipo está en la misma oficina, es posible que desees ejecutar tu propio servidor local)
- Seguridad (la caché remota tendrá tus objetos binarios y, por lo tanto, debe ser segura)
- Administración sencilla (por ejemplo, Google Cloud Storage es un servicio completamente administrado)
Existen muchos backends que se pueden usar para una caché remota. Estas son algunas opciones incluyen:
nginx
nginx es un servidor web de código abierto. Con su [módulo WebDAV], se puede
usar como caché remota para Bazel. En Debian y Ubuntu, puedes instalar el
nginx-extras paquete. En macOS, nginx está disponible a través de Homebrew:
brew tap denji/nginxbrew install nginx-full --with-webdav
A continuación, se muestra una configuración de ejemplo para nginx. Ten en cuenta que deberás
cambiar /path/to/cache/dir a un directorio válido en el que nginx tenga permiso
para escribir y leer. Es posible que debas cambiar la opción client_max_body_size a un
valor más grande si tienes archivos de salida más grandes. El servidor requerirá otra
configuración, como la autenticación.
Configuración de ejemplo para la sección server en nginx.conf:
location /cache/ {
# The path to the directory where nginx should store the cache contents.
root /path/to/cache/dir;
# Allow PUT
dav_methods PUT;
# Allow nginx to create the /ac and /cas subdirectories.
create_full_put_path on;
# The maximum size of a single file.
client_max_body_size 1G;
allow all;
}
bazel-remote
bazel-remote es una caché de compilación remota de código abierto que puedes usar en tu infraestructura. Se usó con éxito en producción en varias empresas desde principios de 2018. Ten en cuenta que el proyecto de Bazel no proporciona asistencia técnica para bazel-remote.
Esta caché almacena contenido en el disco y también proporciona recolección de elementos no utilizados para aplicar un límite superior de almacenamiento y limpiar los artefactos no utilizados. La caché está disponible como una [imagen de Docker] y su código está disponible en GitHub. Se admiten las APIs de caché remota de REST y gRPC.
Consulta la GitHub de GitHub para obtener instrucciones sobre cómo usarla.
Google Cloud Storage
[Google Cloud Storage] es un almacén de objetos completamente administrado que proporciona una API de HTTP compatible con el protocolo de almacenamiento en caché remoto de Bazel. Requiere que tengas una cuenta de Google Cloud con la facturación habilitada.
Para usar Cloud Storage como caché, haz lo siguiente:
Crea un bucket de almacenamiento. Asegúrate de seleccionar una ubicación de bucket que esté más cerca de ti, ya que el ancho de banda de la red es importante para la caché remota.
Crea una cuenta de servicio para que Bazel se autentique en Cloud Storage. Consulta Crea una cuenta de servicio.
Genera una clave JSON secreta y, luego, pásala a Bazel para la autenticación. Almacena la clave de forma segura, ya que cualquier persona que la tenga puede leer y escribir datos arbitrarios en tu bucket de GCS.
Para conectarte a Cloud Storage, agrega las siguientes marcas a tu comando de Bazel:
- Pasa la siguiente URL a Bazel con la marca:
--remote_cache=https://storage.googleapis.com/bucket-name, en la quebucket-namees el nombre de tu bucket de almacenamiento. - Pasa la clave de autenticación con la marca:
--google_credentials=/path/to/your/secret-key.json, o--google_default_credentialspara usar la autenticación de aplicaciones.
- Pasa la siguiente URL a Bazel con la marca:
Puedes configurar Cloud Storage para que borre automáticamente los archivos antiguos. Para ello, consulta Administra los ciclos de vida de los objetos.
Otros servidores
Puedes configurar cualquier servidor HTTP/1.1 que admita PUT y GET como backend de la caché. Los usuarios informaron que tuvieron éxito con los backends de almacenamiento en caché, como Hazelcast, Apache httpd, y AWS S3.
Autenticación
A partir de la versión 0.11.0, se agregó compatibilidad con la autenticación básica HTTP a Bazel.
Puedes pasar un nombre de usuario y una contraseña a Bazel a través de la URL de la caché remota. La
sintaxis es https://username:password@hostname.com:port/path. Ten en cuenta que
la autenticación básica HTTP transmite el nombre de usuario y la contraseña en texto sin formato a través de la
red, por lo que es fundamental usarla siempre con HTTPS.
Protocolo de almacenamiento en caché HTTP
Bazel admite el almacenamiento en caché remoto a través de HTTP/1.1. El protocolo es conceptualmente simple:
Los datos binarios (BLOB) se suben a través de solicitudes PUT y se descargan a través de solicitudes GET.
Los metadatos de los resultados de las acciones se almacenan en la ruta de acceso /ac/, y los archivos de salida se almacenan
en la ruta de acceso /cas/.
Por ejemplo, considera una caché remota que se ejecuta en http://localhost:8080/cache.
Una solicitud de Bazel para descargar metadatos de resultados de acciones para una acción con el hash SHA256
01ba4719... se verá de la siguiente manera:
GET /cache/ac/01ba4719c80b6fe911b091a7c05124b64eeece964e09c058ef8f9805daca546b HTTP/1.1
Host: localhost:8080
Accept: */*
Connection: Keep-Alive
Una solicitud de Bazel para subir un archivo de salida con el hash SHA256 15e2b0d3... a
l CAS se verá de la siguiente manera:
PUT /cache/cas/15e2b0d3c33891ebb0f1ef609ec419420c20e320ce94c65fbc8c3312448eb225 HTTP/1.1
Host: localhost:8080
Accept: */*
Content-Length: 9
Connection: Keep-Alive
0x310x320x330x340x350x360x370x380x39
Ejecuta Bazel con la caché remota
Una vez que se configura un servidor como caché remota, para usar la caché remota, debes agregar marcas a tu comando de Bazel. Consulta la lista de configuraciones y sus marcas a continuación.
Es posible que también debas configurar la autenticación, que es específica para tu servidor elegido.
Es posible que desees agregar estas marcas en un archivo .bazelrc para no tener que
especificarlas cada vez que ejecutes Bazel. Según tu proyecto y
la dinámica del equipo, puedes agregar marcas a un archivo .bazelrc que sea lo siguiente:
- En tu máquina local
- En el espacio de trabajo de tu proyecto, compartido con el equipo
- En el sistema de CI
Leer y escribir en la caché remota
Ten cuidado con quién tiene la capacidad de escribir en la caché remota. Es posible que solo quieras que tu sistema de CI pueda escribir en la caché remota.
Usa la siguiente marca para leer y escribir en la caché remota:
build --remote_cache=http://your.host:portAdemás de HTTP, también se admiten los siguientes protocolos: HTTPS, grpc, grpcs.
Usa la siguiente marca además de la anterior para solo leer desde la caché remota:
build --remote_upload_local_results=falseExcluye destinos específicos del uso de la caché remota
Para excluir destinos específicos del uso de la caché remota, etiqueta el destino con
no-remote-cache. Por ejemplo:
java_library(
name = "target",
tags = ["no-remote-cache"],
)
Borra contenido de la caché remota
Borrar contenido de la caché remota es parte de la administración del servidor. La forma en que borras contenido de la caché remota depende del servidor que configuraste como caché. Cuando borres resultados, borra toda la caché, o los resultados antiguos.
Los resultados almacenados en caché se almacenan como un conjunto de nombres y hashes. Cuando borras contenido, no hay forma de distinguir qué resultado pertenece a una compilación específica.
Es posible que desees borrar contenido de la caché para lo siguiente:
- Crear una caché limpia después de que se envenenó una caché
- Reducir la cantidad de almacenamiento que se usa borrando los resultados antiguos
Sockets Unix
La caché HTTP remota admite la conexión a través de sockets de dominio Unix. El comportamiento
es similar a la marca --unix-socket de curl. Usa lo siguiente para configurar el socket de dominio Unix:
build --remote_cache=http://your.host:port
build --remote_proxy=unix:/path/to/socketEsta función no es compatible con Windows.
Memoria caché del disco
Bazel puede usar un directorio en el sistema de archivos como caché remota. Esto es útil para compartir artefactos de compilación cuando se cambian las ramas o se trabaja en varios espacios de trabajo del mismo proyecto, como varias extracciones. Habilita la memoria caché del disco de la siguiente manera:
build --disk_cache=path/to/build/cachePuedes pasar una ruta de acceso específica del usuario a la marca --disk_cache con el alias ~
(Bazel sustituirá el directorio principal del usuario actual). Esto es útil
cuando se habilita la memoria caché del disco para todos los desarrolladores de un proyecto a través del archivo .bazelrc registrado del proyecto.
Recolección de elementos no utilizados
A partir de Bazel 7.4, puedes usar --experimental_disk_cache_gc_max_size y
--experimental_disk_cache_gc_max_age para establecer un tamaño máximo para la memoria caché del disco
o para la antigüedad de las entradas de caché individuales. Bazel recopilará automáticamente la memoria caché del disco mientras esté inactivo entre compilaciones; el temporizador de inactividad se puede configurar con --experimental_disk_cache_gc_idle_delay (el valor predeterminado es de 5 minutos).
Como alternativa a la recolección automática de elementos no utilizados, también proporcionamos una herramienta para ejecutar una recolección de elementos no utilizados a pedido.
Problemas conocidos
Modificación de archivos de entrada durante una compilación
Cuando se modifica un archivo de entrada durante una compilación, es posible que Bazel suba resultados no válidos
a la caché remota. Puedes habilitar la detección de cambios con
la --experimental_guard_against_concurrent_changes marca. No hay problemas conocidos y se habilitará de forma predeterminada en una versión futura.
Consulta el [problema #3360] para obtener actualizaciones. En general, evita modificar los archivos fuente durante una
compilación.
Variables de entorno que se filtran en una acción
Una definición de acción contiene variables de entorno. Esto puede ser un problema para
compartir aciertos de caché remota en varias máquinas. Por ejemplo, los entornos con
diferentes $PATH variables no compartirán aciertos de caché. Solo las variables de entorno
que se incluyen explícitamente en la lista blanca a través de --action_env se incluyen en una definición de acción. El paquete Debian/Ubuntu de Bazel solía instalar /etc/bazel.bazelrc
con una lista blanca de variables de entorno, incluido $PATH. Si obtienes
menos aciertos de caché de lo esperado, verifica que tu entorno no tenga un archivo
/etc/bazel.bazelrc antiguo.
Bazel no realiza un seguimiento de las herramientas fuera de un espacio de trabajo
Actualmente, Bazel no realiza un seguimiento de las herramientas fuera de un espacio de trabajo. Esto puede ser un
problema si, por ejemplo, una acción usa un compilador de /usr/bin/. Luego,
dos usuarios con diferentes compiladores instalados compartirán de forma incorrecta los aciertos de caché
porque los resultados son diferentes, pero tienen el mismo hash de acción. Consulta el
problema #4558 para obtener actualizaciones.
El estado incremental en la memoria se pierde cuando se ejecutan compilaciones dentro de contenedores de Docker Bazel usa la arquitectura cliente/servidor incluso cuando se ejecuta en un solo contenedor de Docker. En el servidor, Bazel mantiene un estado en la memoria que acelera las compilaciones. Cuando se ejecutan compilaciones dentro de contenedores de Docker, como en CI, se pierde el estado en la memoria y Bazel debe volver a compilarlo antes de usar la caché remota.
Vínculos externos
Your Build in a Datacenter: El equipo de Bazel dio una charla sobre el almacenamiento en caché y la ejecución remotos en FOSDEM 2018.
Compilaciones de Bazel más rápidas con almacenamiento en caché remoto: un punto de referencia: Nicolò Valigi escribió una entrada de blog en la que compara el almacenamiento en caché remoto en Bazel.