Compartir comentarios
Las respuestas se generan en base a la documentación.

Driver Kubernetes

El driver Kubernetes te permite conectar tus entornos locales de desarrollo o CI a builders en un clúster de Kubernetes, lo que facilita el acceso a recursos informáticos más potentes y, opcionalmente, en múltiples arquitecturas nativas.

Sinopsis

Ejecuta el siguiente comando para crear un nuevo builder, llamado kube, que utilice el driver Kubernetes:

$ docker buildx create \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  --driver-opt=[key=value,...]

La siguiente tabla describe las opciones específicas del driver disponibles que puedes pasar a --driver-opt:

ParámetroTipoPredeterminadoDescripción
imageStringEstablece la imagen que se utilizará para ejecutar BuildKit.
namespaceStringEspacio de nombres en el contexto actual de KubernetesEstablece el espacio de nombres (namespace) de Kubernetes.
default-loadBooleanfalseCarga automáticamente las imágenes en el almacenamiento de imágenes de Docker Engine.
replicasInteger1Establece el número de réplicas de Pod a crear. Consulta Escalabilidad de BuildKit.
requests.cpuUnidades de CPUEstablece el valor de solicitud de CPU en unidades de CPU de Kubernetes. Por ejemplo: requests.cpu=100m o requests.cpu=2.
requests.memoryTamaño de memoriaEstablece la solicitud de memoria en bytes o con un sufijo válido. Por ejemplo: requests.memory=500Mi o requests.memory=4G.
requests.ephemeral-storageTamaño de almacenamientoEstablece el valor de solicitud de almacenamiento efímero en bytes o con un sufijo válido. Por ejemplo: requests.ephemeral-storage=2Gi.
persistent-volume-claim.requests.storageTamaño de almacenamientoEstablece el tamaño solicitado para una reclamación de volumen persistente (PVC). Cuando se configura, Buildx crea un StatefulSet y almacena la caché de compilación de BuildKit en la reclamación. Por ejemplo: persistent-volume-claim.requests.storage=20Gi.
limits.cpuUnidades de CPUEstablece el límite de CPU en unidades de CPU de Kubernetes. Por ejemplo: limits.cpu=100m o limits.cpu=2.
limits.memoryTamaño de memoriaEstablece el límite de memoria en bytes o con un sufijo válido. Por ejemplo: limits.memory=500Mi o limits.memory=4G.
limits.ephemeral-storageTamaño de almacenamientoEstablece el límite de almacenamiento efímero en bytes o con un sufijo válido. Por ejemplo: limits.ephemeral-storage=100M.
buildkit-root-volume-memoryTamaño de memoriaUtiliza el sistema de archivos habitualMonta /var/lib/buildkit en un volumen respaldado por memoria emptyDir, con SizeLimit como valor. Por ejemplo: buildkit-root-volume-memory=6G.
nodeselectorCadena CSVEstablece las etiquetas nodeSelector del pod. Consulta Asignación de nodos.
annotationsCadena CSVEstablece anotaciones adicionales en el Deployment o StatefulSet y en los pods.
labelsCadena CSVEstablece etiquetas descriptivas (labels) adicionales en el Deployment o StatefulSet y en los pods.
tolerationsCadena CSVConfigura las tolerancias a perturbaciones (tolerations) del pod. Consulta Asignación de nodos.
serviceaccountStringEstablece el serviceAccountName del pod.
schedulernameStringEstablece el programador responsable de programar el pod.
timeoutTiempo120sEstablece el límite de tiempo de espera que determina cuánto tiempo esperará Buildx a que se aprovisionen los pods antes de una compilación.
rootlessBooleanfalseEjecuta el contenedor como un usuario sin privilegios root. Consulta Modo rootless.
loadbalanceStringstickyEstrategia de equilibrio de carga (sticky o random). Si se establece en sticky, el pod se elige mediante el hash de la ruta del contexto.
qemu.installBooleanfalseInstala la emulación QEMU para el soporte multi-plataforma. Consulta QEMU.
qemu.imageStringtonistiigi/binfmt:latestEstablece la imagen de emulación QEMU. Consulta QEMU.

Escalabilidad de BuildKit

Una de las ventajas principales del driver Kubernetes es que puedes escalar el número de réplicas de los builders hacia arriba o hacia abajo para manejar una mayor carga de compilación. El escalado es configurable mediante las siguientes opciones del driver:

  • replicas=N

    Esto escala el número de pods de BuildKit al tamaño deseado. De forma predeterminada, solo crea un único pod. Aumentar el número de réplicas te permite aprovechar múltiples nodos en tu clúster.

  • requests.cpu, requests.memory, requests.ephemeral-storage, limits.cpu, limits.memory, limits.ephemeral-storage

    Estas opciones permiten solicitar y limitar los recursos disponibles para cada pod de BuildKit de acuerdo con la documentación oficial de Kubernetes.

Por ejemplo, para crear 4 pods réplicas de BuildKit:

$ docker buildx create \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  --driver-opt=namespace=buildkit,replicas=4

Al listar los pods obtienes lo siguiente:

$ kubectl -n buildkit get deployments
NAME    READY   UP-TO-DATE   AVAILABLE   AGE
kube0   4/4     4            4           8s

$ kubectl -n buildkit get pods
NAME                     READY   STATUS    RESTARTS   AGE
kube0-6977cdcb75-48ld2   1/1     Running   0          8s
kube0-6977cdcb75-rkc6b   1/1     Running   0          8s
kube0-6977cdcb75-vb4ks   1/1     Running   0          8s
kube0-6977cdcb75-z4fzs   1/1     Running   0          8s

Además, puedes utilizar la opción loadbalance=(sticky|random) para controlar el comportamiento del equilibrio de carga cuando hay múltiples réplicas. La opción random selecciona nodos aleatorios del conjunto de nodos, proporcionando una distribución uniforme del trabajo entre las réplicas. La opción sticky (predeterminada) intenta conectar una misma compilación realizada varias veces al mismo nodo en cada ocasión, asegurando un mejor uso de la caché local.

Para obtener más información sobre la escalabilidad, consulta las opciones de docker buildx create.

Almacenamiento persistente

Establece la opción del driver persistent-volume-claim.requests.storage para almacenar la caché de compilación de BuildKit en una reclamación de volumen persistente (PVC) en lugar de en el sistema de archivos del pod. Cuando configuras esta opción, Buildx crea un StatefulSet en lugar de un Deployment.

Si también configuras replicas, cada réplica obtiene su propia reclamación de volumen persistente. Esto mantiene la caché de compilación local para cada pod a través de los reinicios.

Por ejemplo, para crear un builder con 20 GiB de almacenamiento persistente por réplica:

$ docker buildx create \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  --driver-opt=namespace=buildkit,replicas=4,persistent-volume-claim.requests.storage=20Gi

Asignación de nodos

El driver Kubernetes te permite controlar la programación (scheduling) de los pods de BuildKit utilizando las opciones del driver nodeSelector y tolerations. También puedes configurar la opción schedulername si deseas utilizar un programador totalmente personalizado.

Puedes utilizar las opciones annotations y labels del driver para aplicar metadatos adicionales al Deployment o StatefulSet y a los pods que alojan tus builders.

El valor del parámetro nodeSelector es una cadena separada por comas de pares clave-valor, donde la clave es la etiqueta del nodo y el valor es el texto de la etiqueta. Por ejemplo: "nodeselector=kubernetes.io/arch=arm64".

El parámetro tolerations es una lista de perturbaciones (taints) separada por punto y coma. Acepta los mismos valores que el manifiesto de Kubernetes. Cada entrada de tolerations especifica una clave de perturbación, el valor, el operador o el efecto. Por ejemplo: "tolerations=key=foo,value=bar;key=foo2,operator=exists;key=foo3,effect=NoSchedule".

Estas opciones aceptan cadenas delimitadas por comas (CSV) como valores. Debido a las reglas de entrecomillado para los comandos de la shell, debes envolver los valores entre comillas simples. Incluso puedes envolver toda la opción --driver-opt entre comillas simples, por ejemplo:

$ docker buildx create \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  '--driver-opt="nodeselector=label1=value1,label2=value2","tolerations=key=key1,value=value1"'

Compilaciones multi-plataforma

El driver Kubernetes tiene soporte para crear imágenes multi-plataforma, ya sea utilizando QEMU o aprovechando la arquitectura nativa de los nodos.

QEMU

Al igual que el driver docker-container, el driver Kubernetes también admite el uso de QEMU (modo de usuario) para compilar imágenes para plataformas no nativas. Incluye la bandera --platform y especifica las plataformas a las que deseas exportar la imagen.

Por ejemplo, para compilar una imagen de Linux para amd64 y arm64:

$ docker buildx build \
  --builder=kube \
  --platform=linux/amd64,linux/arm64 \
  -t <user>/<image> \
  --push .
Warning

QEMU realiza una emulación completa de la CPU para plataformas no nativas, lo que es mucho más lento que las compilaciones nativas. Tareas pesadas como la compilación y la compresión/descompresión probablemente experimentarán un impacto significativo en el rendimiento.

El uso de una imagen de BuildKit personalizada o la invocación de binarios no nativos en las compilaciones puede requerir que actives explícitamente QEMU mediante la opción qemu.install al crear el builder:

$ docker buildx create \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  --driver-opt=namespace=buildkit,qemu.install=true

Nativo

Si tienes acceso a nodos del clúster con diferentes arquitecturas, el driver Kubernetes puede aprovechar estos recursos para realizar compilaciones nativas. Para hacerlo, utiliza la bandera --append de docker buildx create.

Primero, crea tu builder con soporte explícito para una sola arquitectura, por ejemplo amd64:

$ docker buildx create \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  --platform=linux/amd64 \
  --node=builder-amd64 \
  --driver-opt=namespace=buildkit,nodeselector="kubernetes.io/arch=amd64"

Esto crea un builder de Buildx llamado kube, que contiene un único nodo de builder llamado builder-amd64. Asignar un nombre al nodo mediante --node es opcional. Buildx generará un nombre de nodo aleatorio si no proporcionas uno.

Ten en cuenta que el concepto de nodo en Buildx no es el mismo que el concepto de nodo en Kubernetes. Un nodo de Buildx en este caso podría conectar múltiples nodos de Kubernetes de la misma arquitectura.

Con el builder kube ya creado, ahora puedes introducir otra arquitectura utilizando --append. Por ejemplo, para añadir arm64:

$ docker buildx create \
  --append \
  --bootstrap \
  --name=kube \
  --driver=kubernetes \
  --platform=linux/arm64 \
  --node=builder-arm64 \
  --driver-opt=namespace=buildkit,nodeselector="kubernetes.io/arch=arm64"

Listar tus builders muestra ambos nodos para el builder kube:

$ docker buildx ls
NAME/NODE       DRIVER/ENDPOINT                                         STATUS   PLATFORMS
kube            kubernetes
  builder-amd64 kubernetes:///kube?deployment=builder-amd64&kubeconfig= running  linux/amd64*, linux/amd64/v2, linux/amd64/v3, linux/386
  builder-arm64 kubernetes:///kube?deployment=builder-arm64&kubeconfig= running  linux/arm64*

Ahora puedes compilar imágenes multi-plataforma amd64 y arm64 especificando esas plataformas juntas en tu comando de compilación:

$ docker buildx build --builder=kube --platform=linux/amd64,linux/arm64 -t <user>/<image> --push .

Puedes repetir el comando buildx create --append para tantas arquitecturas como desees admitir.

Modo rootless

El driver Kubernetes admite el modo rootless (sin privilegios root). Para obtener más información sobre cómo funciona el modo rootless y sus requisitos, consulta la documentación de BuildKit sin privilegios (Rootless BuildKit).

Para activarlo en tu clúster, puedes utilizar la opción del driver rootless=true:

$ docker buildx create \
  --name=kube \
  --driver=kubernetes \
  --driver-opt=namespace=buildkit,rootless=true

Esto creará tus pods sin la propiedad securityContext.privileged.

Requiere la versión 1.19 de Kubernetes o posterior. Se recomienda utilizar Ubuntu como kernel del host.

Ejemplo: Crear un builder de Buildx en Kubernetes

Esta guía te muestra cómo:

  • Crear un espacio de nombres (namespace) para tus recursos de Buildx
  • Crear un builder de Kubernetes
  • Listar los builders disponibles
  • Compilar una imagen utilizando tus builders de Kubernetes

Requisitos previos:

  • Tienes un clúster de Kubernetes existente. Si no tienes uno, puedes seguir la guía instalando minikube.
  • El clúster al que deseas conectarte es accesible mediante el comando kubectl, con la variable de entorno KUBECONFIG configurada adecuadamente si es necesario.
  1. Crea un espacio de nombres buildkit.

    Crear un espacio de nombres independiente ayuda a mantener tus recursos de Buildx aislados de otros recursos en el clúster.

    $ kubectl create namespace buildkit
    namespace/buildkit created
    
  2. Crea un nuevo builder con el driver Kubernetes:

    $ docker buildx create \
      --bootstrap \
      --name=kube \
      --driver=kubernetes \
      --driver-opt=namespace=buildkit
    
    Note

    Recuerda especificar el espacio de nombres en las opciones del driver.

  3. Lista los builders disponibles mediante docker buildx ls

    $ docker buildx ls
    NAME/NODE                DRIVER/ENDPOINT STATUS  PLATFORMS
    kube                     kubernetes
      kube0-6977cdcb75-k9h9m                 running linux/amd64, linux/amd64/v2, linux/amd64/v3, linux/386
    default *                docker
      default                default         running linux/amd64, linux/386
    
  4. Inspecciona los pods en ejecución creados por el driver de compilación con kubectl.

    $ kubectl -n buildkit get deployments
    NAME    READY   UP-TO-DATE   AVAILABLE   AGE
    kube0   1/1     1            1           32s
    
    $ kubectl -n buildkit get pods
    NAME                     READY   STATUS    RESTARTS   AGE
    kube0-6977cdcb75-k9h9m   1/1     Running   0          32s
    

    El driver de compilación crea los recursos necesarios en tu clúster dentro del espacio de nombres especificado (en este caso, buildkit), mientras mantiene la configuración de tu driver localmente.

  5. Utiliza tu nuevo builder incluyendo la bandera --builder cuando ejecutes comandos de buildx. Por ejemplo:

    # Reemplaza <registry> con tu nombre de usuario de Docker
    # e <image> con el nombre de la imagen que deseas compilar
    docker buildx build \
      --builder=kube \
      -t <registry>/<image> \
      --push .
    

Eso es todo: has compilado una imagen a partir de un pod de Kubernetes utilizando Buildx.

Lectura adicional

Para obtener más información sobre el driver Kubernetes, consulta la referencia de buildx.