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

Compilar proyectos Compose con Bake

Esta guía explora cómo usar Bake para compilar imágenes en proyectos Docker Compose con varios servicios.

Docker Buildx Bake es una herramienta de orquestación de compilación que permite configuración declarativa para tus builds, igual que Docker Compose define stacks de ejecución. En proyectos donde Docker Compose se usa para levantar servicios en desarrollo local, Bake ofrece una forma de ampliar el proyecto con una configuración de compilación lista para producción.

Requisitos previos

Esta guía asume que conoces

Orientación

Esta guía usará el repositorio dvdksn/example-voting-app como ejemplo de monorepo que usa Docker Compose y puede ampliarse con Bake.

$ git clone https://github.com/dvdksn/example-voting-app.git
$ cd example-voting-app

Este repositorio usa Docker Compose para definir las configuraciones de ejecución de la aplicación en el archivo compose.yaml. Esta aplicación consta de los siguientes servicios:

ServicioDescripción
voteAplicación web front-end en Python que permite votar entre dos opciones.
resultAplicación web en Node.js que muestra los resultados de la votación en tiempo real.
workerWorker en .NET que consume votos y los guarda en la base de datos.
dbBase de datos Postgres respaldada por un volumen Docker.
redisInstancia Redis que recopila votos nuevos.
seedContenedor de utilidad que rellena la base de datos con datos de prueba.

Los servicios vote, result y worker se compilan a partir del código de este repositorio, mientras que db y redis usan imágenes existentes de Postgres y Redis de Docker Hub. El servicio seed es una utilidad que invoca peticiones contra el servicio front-end para poblar la base de datos con fines de prueba.

Compilar con Compose

Cuando levantas un proyecto Docker Compose, los servicios que definen la propiedad build se compilan automáticamente antes de iniciar el servicio. Esta es la configuración de compilación del servicio vote en el repositorio de ejemplo:

compose.yaml
services:
  vote:
    build:
      context: ./vote # Build context
      target: dev # Dockerfile stage

Los servicios vote, result y worker tienen una configuración de compilación definida. Ejecutar docker compose up activará la compilación de estos servicios.

¿Sabías que también puedes usar Compose solo para compilar las imágenes de los servicios? El comando docker compose build te permite invocar una compilación con la configuración definida en el archivo Compose. Por ejemplo, para compilar el servicio vote con esta configuración, ejecuta:

$ docker compose build vote

Omite el nombre del servicio para compilar todos los servicios a la vez:

$ docker compose build

El comando docker compose build es útil cuando solo necesitas compilar imágenes sin ejecutar servicios.

El formato de archivo Compose admite varias propiedades para definir la configuración de compilación. Por ejemplo, para especificar el nombre de etiqueta de las imágenes, establece la propiedad image en el servicio.

services:
  vote:
    image: username/vote
    build:
      context: ./vote
      target: dev
    #...

  result:
    image: username/result
    build:
      context: ./result
    #...

  worker:
    image: username/worker
    build:
      context: ./worker
    #...

Ejecutar docker compose build crea tres imágenes de servicio con nombres completos que puedes enviar a Docker Hub.

La propiedad build admite una amplia gama de opciones para configurar compilaciones. Sin embargo, las imágenes de nivel producción suelen diferir de las usadas en desarrollo local. Para no saturar tu archivo Compose con configuraciones de compilación que quizá no convengan para compilaciones locales, plantéate separar las compilaciones de producción de las locales usando Bake para compilar imágenes de release. Este enfoque separa responsabilidades: Compose para desarrollo local y Bake para compilaciones listas para producción, reutilizando definiciones de servicios y configuraciones de compilación fundamentales.

Compilar con Bake

Al igual que Compose, Bake interpreta la definición de compilación de un proyecto desde un archivo de configuración. Bake admite HashiCorp Configuration Language (HCL), JSON y el formato YAML de Docker Compose. Cuando usas Bake con varios archivos, encuentra y fusiona todos los archivos de configuración aplicables en una configuración de compilación unificada. Las opciones de compilación definidas en tu archivo Compose se amplían o, en algunos casos, se sustituyen por opciones del archivo Bake.

La siguiente sección explora cómo usar Bake para ampliar las opciones de compilación definidas en tu archivo Compose para producción.

Ver la configuración de compilación

Bake crea automáticamente una configuración de compilación a partir de las propiedades build de tus servicios. Usa la opción --print de Bake para ver la configuración de compilación de un archivo Compose dado. Esta opción evalúa la configuración de compilación y muestra la definición de compilación en formato JSON.

$ docker buildx bake --print

La salida en JSON muestra el grupo que se ejecutaría y todos los targets de ese grupo. Un grupo es una colección de compilaciones y un target representa una sola compilación.

{
  "group": {
    "default": {
      "targets": ["vote", "result", "worker", "seed"]
    }
  },
  "target": {
    "result": {
      "context": "result",
      "dockerfile": "Dockerfile"
    },
    "seed": {
      "context": "seed-data",
      "dockerfile": "Dockerfile"
    },
    "vote": {
      "context": "vote",
      "dockerfile": "Dockerfile",
      "target": "dev"
    },
    "worker": {
      "context": "worker",
      "dockerfile": "Dockerfile"
    }
  }
}

Como puedes ver, Bake ha creado un grupo default que incluye cuatro targets:

  • seed
  • vote
  • result
  • worker

Este grupo se crea automáticamente desde tu archivo Compose; incluye todos tus servicios con configuración de compilación. Para compilar este grupo de servicios con Bake, ejecuta:

$ docker buildx bake

Personalizar el grupo de compilación

Empieza redefiniendo el grupo de compilación por defecto que ejecuta Bake. El grupo por defecto actual incluye un target seed, un servicio de Compose usado solo para poblar la base de datos con datos de prueba. Como este target no produce una imagen de producción, no hace falta incluirlo en el grupo de compilación.

Para personalizar la configuración de compilación que usa Bake, crea un archivo nuevo en la raíz del repositorio, junto a tu archivo compose.yaml, llamado docker-bake.hcl.

$ touch docker-bake.hcl

Abre el archivo Bake y añade la siguiente configuración:

docker-bake.hcl
group "default" {
  targets = ["vote", "result", "worker"]
}

Guarda el archivo e imprime de nuevo tu definición Bake.

$ docker buildx bake --print

La salida JSON muestra que el grupo default solo incluye los targets que te interesan.

{
  "group": {
    "default": {
      "targets": ["vote", "result", "worker"]
    }
  },
  "target": {
    "result": {
      "context": "result",
      "dockerfile": "Dockerfile",
      "tags": ["username/result"]
    },
    "vote": {
      "context": "vote",
      "dockerfile": "Dockerfile",
      "tags": ["username/vote"],
      "target": "dev"
    },
    "worker": {
      "context": "worker",
      "dockerfile": "Dockerfile",
      "tags": ["username/worker"]
    }
  }
}

Aquí, la configuración de compilación de cada target (context, tags, etc.) se toma del archivo compose.yaml. El grupo lo define el archivo docker-bake.hcl.

Personalizar targets

El archivo Compose define actualmente la etapa dev como target de compilación del servicio vote. Eso encaja con la imagen que ejecutarías en desarrollo local, porque la etapa dev incluye dependencias y configuraciones adicionales de desarrollo. Para la imagen de producción, en cambio, querrás apuntar a la imagen final.

Para modificar la etapa target usada por el servicio vote, añade la siguiente configuración al archivo Bake:

target "vote" {
  target = "final"
}

Esto sustituye la propiedad target del archivo Compose por un valor distinto cuando ejecutas la compilación con Bake. Las demás opciones de compilación del archivo Compose (tag, context) no cambian. Puedes comprobarlo inspeccionando la configuración de compilación del target vote con docker buildx bake --print vote:

{
  "group": {
    "default": {
      "targets": ["vote"]
    }
  },
  "target": {
    "vote": {
      "context": "vote",
      "dockerfile": "Dockerfile",
      "tags": ["username/vote"],
      "target": "final"
    }
  }
}

Funciones de compilación adicionales

Las compilaciones de nivel producción suelen tener características distintas a las de desarrollo. Aquí tienes algunos ejemplos de lo que podrías añadir para imágenes de producción.

Multiplataforma
En desarrollo local solo necesitas compilar para tu plataforma local, ya que esas imágenes se ejecutarán en tu máquina. Pero para imágenes que envías a un registro, suele ser buena idea compilar para varias plataformas, en particular arm64 y amd64.
Attestations
Las attestations son manifiestos adjuntos a la imagen que describen cómo se creó la imagen y qué componentes contiene. Adjuntar attestations a tus imágenes ayuda a seguir las buenas prácticas de la cadena de suministro de software.
Annotations
Las annotations aportan metadatos descriptivos para imágenes. Úsalas para registrar información arbitraria y adjuntarla a tu imagen, lo que ayuda a consumidores y herramientas a entender el origen, el contenido y el uso de la imagen.
Tip

¿Por qué no definir estas opciones de compilación adicionales directamente en el archivo Compose?

La propiedad build del formato de archivo Compose no admite todas las funciones de compilación. Además, algunas funciones, como compilaciones multiplataforma, pueden aumentar mucho el tiempo de compilación de un servicio. En desarrollo local conviene mantener la compilación simple y rápida, reservando las funciones avanzadas para compilaciones de release.

Para añadir estas propiedades a las imágenes que compilas con Bake, actualiza el archivo Bake así:

group "default" {
  targets = ["vote", "result", "worker"]
}

target "_common" {
  annotations = ["org.opencontainers.image.authors=username"]
  platforms = ["linux/amd64", "linux/arm64"]
  attest = [
    "type=provenance,mode=max",
    "type=sbom"
  ]
}

target "vote" {
  inherits = ["_common"]
  target = "final"
}

target "result" {
  inherits = ["_common"]
}

target "worker" {
  inherits = ["_common"]
}

Esto define un target _common con configuración de compilación reutilizable para añadir soporte multiplataforma, annotations y attestations a tus imágenes. Los targets de compilación heredan el target reutilizable.

Con estos cambios, compilar el proyecto con Bake produce tres conjuntos de imágenes multiplataforma para las arquitecturas linux/amd64 y linux/arm64. Cada imagen lleva una annotation de autor y registros de attestation SBOM y de procedencia.

Conclusiones

El patrón de esta guía ofrece un enfoque útil para gestionar imágenes Docker listas para producción en proyectos que usan Docker Compose. Usar Bake te da acceso a todas las funciones potentes de Buildx y BuildKit, y también ayuda a separar configuración de desarrollo y de compilación de forma razonable.

Lecturas adicionales

Para más información sobre cómo usar Bake, consulta estos recursos: