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
- Docker Compose
- Constructions multi-étapes
- Constructions multi-plateformes
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 :
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 :
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.
TipWhy 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: