# 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](/build/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

- Docker Compose
- [Compilaciones multi-etapa](/build/building/multi-stage/)
- [Compilaciones multiplataforma](/build/building/multi-platform/)

## Orientación

Esta guía usará el repositorio
[dvdksn/example-voting-app](https://github.com/dvdksn/example-voting-app)
como ejemplo de monorepo que usa Docker Compose y puede ampliarse con Bake.

```console
$ 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:

| Servicio | Descripción                                                                         |
| -------- | ----------------------------------------------------------------------------------- |
| `vote`   | Aplicación web front-end en Python que permite votar entre dos opciones.            |
| `result` | Aplicación web en Node.js que muestra los resultados de la votación en tiempo real. |
| `worker` | Worker en .NET que consume votos y los guarda en la base de datos.                  |
| `db`     | Base de datos Postgres respaldada por un volumen Docker.                            |
| `redis`  | Instancia Redis que recopila votos nuevos.                                          |
| `seed`   | Contenedor 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:

```yaml {title="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:

```console
$ docker compose build vote
```

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

```console
$ 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.

```yaml
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](/reference/compose-file/build/)
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.

```console
$ 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.

```json
{
  "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:

```console
$ 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`.

```console
$ touch docker-bake.hcl
```

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

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

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

```console
$ docker buildx bake --print
```

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

```json
{
  "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:

```hcl
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`:

```json
{
  "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](/build/metadata/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](/build/metadata/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í:

```hcl
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:

- [Documentación de Bake](/build/bake/)
- [Compilar con Bake desde un archivo Compose](/build/bake/compose-file/)
- [Referencia del archivo Bake](/build/bake/reference/)
- [Dominar compilaciones multiplataforma, pruebas y más con Docker Buildx Bake](/guides/bake/)
- [Bake GitHub Action](https://github.com/docker/bake-action)

