⚠️ Traduction non officielle - Cette documentation est une traduction communautaire non officielle de Docker.

Construire des projets Compose avec Bake

Ce guide explore comment vous pouvez utiliser Bake pour construire des images pour des projets Docker Compose avec plusieurs services.

Docker Buildx Bake est un outil d'orchestration de construction qui permet une configuration déclarative pour vos constructions, un peu comme le fait Docker Compose pour définir les piles d'exécution. Pour les projets où Docker Compose est utilisé pour lancer des services pour le développement local, Bake offre un moyen d'étendre de manière transparente le projet avec une configuration de construction prête pour la production.

Prérequis

Ce guide suppose que vous êtes familier avec

Orientation

Ce guide utilisera le dépôt dvdksn/example-voting-app comme exemple de monorepo utilisant Docker Compose qui peut être étendu avec Bake.

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

Ce dépôt utilise Docker Compose pour définir les configurations d'exécution pour l'application, dans le fichier compose.yaml. Cette application se compose des services suivants :

Service Description
vote Une application web front-end en Python qui vous permet de voter entre deux options.
result Une application web Node.js qui affiche les résultats du vote en temps réel.
worker Un worker .NET qui consomme les votes et les stocke dans la base de données.
db Une base de données Postgres soutenue par un volume Docker.
redis Une instance Redis qui collecte les nouveaux votes.
seed Un conteneur utilitaire qui ensemence la base de données avec des données fictives.

Les services vote, result et worker sont construits à partir du code de ce dépôt, tandis que db et redis utilisent des images Postgres et Redis préexistantes de Docker Hub. Le service seed est un utilitaire qui invoque des requêtes contre le service front-end pour peupler la base de données, à des fins de test.

Construire avec Compose

Lorsque vous lancez un projet Docker Compose, tous les services qui définissent la propriété build sont automatiquement construits avant le démarrage du service. Voici la configuration de construction pour le service vote dans le dépôt d'exemple :

compose.yaml
services:
  vote:
    build:
      context: ./vote # Contexte de construction
      target: dev # Étape du Dockerfile

Les services vote, result et worker ont tous une configuration de construction spécifiée. L'exécution de docker compose up déclenchera une construction de ces services.

Saviez-vous que vous pouvez également utiliser Compose juste pour construire les images de service ? La commande docker compose build vous permet d'invoquer une construction en utilisant la configuration de construction spécifiée dans le fichier Compose. Par exemple, pour construire le service vote avec cette configuration, exécutez :

$ docker compose build vote

Omettez le nom du service pour construire tous les services en même temps :

$ docker compose build

La commande docker compose build est utile lorsque vous avez seulement besoin de construire des images sans exécuter de services.

Le format de fichier Compose prend en charge un certain nombre de propriétés pour définir la configuration de votre construction. Par exemple, pour spécifier le nom du tag pour les images, définissez la propriété image sur le service.

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

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

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

L'exécution de docker compose build crée trois images de service avec des noms d'image complets que vous pouvez pousser sur Docker Hub.

La propriété build prend en charge une large gamme d'options pour configurer les constructions. Cependant, la construction d'images de qualité production est souvent différente des images utilisées en développement local. Pour éviter d'encombrer votre fichier Compose avec des configurations de construction qui pourraient ne pas être souhaitables pour les constructions locales, envisagez de séparer les constructions de production des constructions locales en utilisant Bake pour construire des images pour la publication. Cette approche sépare les préoccupations : utiliser Compose pour le développement local et Bake pour les constructions prêtes pour la production, tout en réutilisant les définitions de service et les configurations de construction fondamentales.

Construire avec Bake

Comme Compose, Bake analyse la définition de construction d'un projet à partir d'un fichier de configuration. Bake prend en charge le HashiCorp Configuration Language (HCL), JSON et le format YAML de Docker Compose. Lorsque vous utilisez Bake avec plusieurs fichiers, il trouvera et fusionnera tous les fichiers de configuration applicables en une seule configuration de construction unifiée. Les options de construction définies dans votre fichier Compose sont étendues, ou dans certains cas remplacées, par des options spécifiées dans le fichier Bake.

La section suivante explore comment vous pouvez utiliser Bake pour étendre les options de construction définies dans votre fichier Compose pour la production.

Voir la configuration de construction

Bake crée automatiquement une configuration de construction à partir des propriétés build de vos services. Utilisez l'indicateur --print pour que Bake affiche la configuration de construction pour un fichier Compose donné. Cet indicateur évalue la configuration de construction et affiche la définition de construction au format JSON.

$ docker buildx bake --print

La sortie formatée JSON montre le groupe qui serait exécuté, et toutes les cibles de ce groupe. Un groupe est une collection de constructions, et une cible représente une seule construction.

{
  "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",
    }
  }
}

Comme vous pouvez le voir, Bake a créé un groupe default qui comprend quatre cibles :

  • seed
  • vote
  • result
  • worker

Ce groupe est créé automatiquement à partir de votre fichier Compose ; il inclut tous vos services contenant une configuration de construction. Pour construire ce groupe de services avec Bake, exécutez :

$ docker buildx bake

Personnaliser le groupe de construction

Commencez par redéfinir le groupe de construction par défaut que Bake exécute. Le groupe par défaut actuel inclut une cible seed — un service Compose utilisé uniquement pour peupler la base de données avec des données fictives. Comme cette cible ne produit pas d'image de production, il n'est pas nécessaire de l'inclure dans le groupe de construction.

Pour personnaliser la configuration de construction que Bake utilise, créez un nouveau fichier à la racine du dépôt, à côté de votre fichier compose.yaml, nommé docker-bake.hcl.

$ touch docker-bake.hcl

Ouvrez le fichier Bake et ajoutez la configuration suivante :

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

Enregistrez le fichier et imprimez à nouveau votre définition Bake.

$ docker buildx bake --print

La sortie JSON montre que le groupe default n'inclut que les cibles qui vous intéressent.

{
  "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"]
    }
  }
}

Here, the build configuration for each target (context, tags, etc.) is picked up from the compose.yaml file. The group is defined by the docker-bake.hcl file.

Customize targets

The Compose file currently defines the dev stage as the build target for the vote service. That's appropriate for the image that you would run in local development, because the dev stage includes additional development dependencies and configurations. For the production image, however, you'll want to target the final image instead.

To modify the target stage used by the vote service, add the following configuration to the Bake file:

target "vote" {
  target = "final"
}

This overrides the target property specified in the Compose file with a different value when you run the build with Bake. The other build options in the Compose file (tag, context) remain unmodified. You can verify by inspecting the build configuration for the vote target with docker buildx bake --print vote:

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

Additional build features

Production-grade builds often have different characteristics from development builds. Here are a few examples of things you might want to add for production images.

Multi-platform
For local development, you only need to build images for your local platform, since those images are just going to run on your machine. But for images that are pushed to a registry, it's often a good idea to build for multiple platforms, arm64 and amd64 in particular.
Attestations
Attestations are manifests attached to the image that describe how the image was created and what components it contains. Attaching attestations to your images helps ensure that your images follow software supply chain best practices.
Annotations
Annotations provide descriptive metadata for images. Use annotations to record arbitrary information and attach it to your image, which helps consumers and tools understand the origin, contents, and how to use the image.
Tip

Why not just define these additional build options in the Compose file directly?

The build property in the Compose file format does not support all build features. Additionally, some features, like multi-platform builds, can drastically increase the time it takes to build a service. For local development, you're better off keeping your build step simple and fast, saving the bells and whistles for release builds.

To add these properties to the images you build with Bake, update the Bake file as follows:

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"]
}

This defines a new _common target that defines reusable build configuration for adding multi-platform support, annotations, and attestations to your images. The reusable target is inherited by the build targets.

With these changes, building the project with Bake produces three sets of multi-platform images for the linux/amd64 and linux/arm64 architectures. Each image is decorated with an author annotation, and both SBOM and provenance attestation records.

Conclusions

The pattern demonstrated in this guide provides a useful approach for managing production-ready Docker images in projects using Docker Compose. Using Bake gives you access to all the powerful features of Buildx and BuildKit, and also helps separate your development and build configuration in a reasonable way.

Further reading

For more information about how to use Bake, check out these resources: