mirror of https://github.com/docker/docs.git
guides: build compose projects with bake
Signed-off-by: David Karlsson <35727626+dvdksn@users.noreply.github.com>
This commit is contained in:
parent
1252967400
commit
d0ff808ce1
|
@ -0,0 +1,406 @@
|
|||
---
|
||||
title: Building Compose projects with Bake
|
||||
description: Learn how to build Docker Compose projects with Docker Buildx Bake
|
||||
summary: |
|
||||
This guide demonstrates how you can use Bake to build production-grade images for Docker Compose projects.
|
||||
languages: []
|
||||
tags: [devops]
|
||||
params:
|
||||
time: 20 minutes
|
||||
---
|
||||
|
||||
This guide explores how you can use Bake to build images for Docker Compose
|
||||
projects with multiple services.
|
||||
|
||||
[Docker Buildx Bake](/manuals/build/bake/_index.md) is a build orchestration
|
||||
tool that enables declarative configuration for your builds, much like Docker
|
||||
Compose does for defining runtime stacks. For projects where Docker Compose is
|
||||
used to spin up services for local development, Bake offers a way of seamlessly
|
||||
extending the project with a production-ready build configuration.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
This guide assumes that you're familiar with
|
||||
|
||||
- Docker Compose
|
||||
- [Multi-stage builds](/manuals/build/building/multi-stage.md)
|
||||
- [Multi-platform builds](/manuals/build/building/multi-platform.md)
|
||||
|
||||
## Orientation
|
||||
|
||||
This guide will use the
|
||||
[dvdksn/example-voting-app](https://github.com/dvdksn/example-voting-app)
|
||||
repository as an example of a monorepo using Docker Compose that can be
|
||||
extended with Bake.
|
||||
|
||||
```console
|
||||
$ git clone https://github.com/dvdksn/example-voting-app.git
|
||||
$ cd example-voting-app
|
||||
```
|
||||
|
||||
This repository uses Docker Compose to define the runtime configurations for
|
||||
running the application, in the `compose.yaml` file. This app consists of the
|
||||
following services:
|
||||
|
||||
| Service | Description |
|
||||
| -------- | ---------------------------------------------------------------------- |
|
||||
| `vote` | A front-end web app in Python which lets you vote between two options. |
|
||||
| `result` | A Node.js web app which shows the results of the voting in real time. |
|
||||
| `worker` | A .NET worker which consumes votes and stores them in the database. |
|
||||
| `db` | A Postgres database backed by a Docker volume. |
|
||||
| `redis` | A Redis instance which collects new votes. |
|
||||
| `seed` | A utility container that seeds the database with mock data. |
|
||||
|
||||
The `vote`, `result`, and `worker` services are built from code in this
|
||||
repository, whereas `db` and `redis` use pre-existing Postgres and Redis images
|
||||
from Docker Hub. The `seed` service is a utility that invokes requests against
|
||||
the front-end service to populate the database, for testing purposes.
|
||||
|
||||
## Build with Compose
|
||||
|
||||
When you spin up a Docker Compose project, any services that define the `build`
|
||||
property are automatically built before the service is started. Here's the
|
||||
build configuration for the `vote` service in the example repository:
|
||||
|
||||
```yaml {title="compose.yaml"}
|
||||
services:
|
||||
vote:
|
||||
build:
|
||||
context: ./vote # Build context
|
||||
target: dev # Dockerfile stage
|
||||
```
|
||||
|
||||
The `vote`, `result`, and `worker` services all have a build configuration
|
||||
specified. Running `docker compose up` will trigger a build of these services.
|
||||
|
||||
Did you know that you can also use Compose just to build the service images?
|
||||
The `docker compose build` command lets you invoke a build using the build
|
||||
configuration specified in the Compose file. For example, to build the `vote`
|
||||
service with this configuration, run:
|
||||
|
||||
```console
|
||||
$ docker compose build vote
|
||||
```
|
||||
|
||||
Omit the service name to build all services at once:
|
||||
|
||||
```console
|
||||
$ docker compose build
|
||||
```
|
||||
|
||||
The `docker compose build` command is useful when you only need to build images
|
||||
without running services.
|
||||
|
||||
The Compose file format supports a number of properties for defining your
|
||||
build's configuration. For example, to specify the tag name for the images, set
|
||||
the `image` property on the service.
|
||||
|
||||
```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
|
||||
#...
|
||||
```
|
||||
|
||||
Running `docker compose build` creates three service images with fully
|
||||
qualified image names that you can push to Docker Hub.
|
||||
|
||||
The `build` property supports a [wide range](/reference/compose-file/build.md)
|
||||
of options for configuring builds. However, building production-grade images
|
||||
are often different from images used in local development. To avoid cluttering
|
||||
your Compose file with build configurations that might not be desirable for
|
||||
local builds, consider separating the production builds from the local builds
|
||||
by using Bake to build images for release. This approach separates concerns:
|
||||
using Compose for local development and Bake for production-ready builds, while
|
||||
still reusing service definitions and fundamental build configurations.
|
||||
|
||||
## Build with Bake
|
||||
|
||||
Like Compose, Bake parses the build definition for a project from a
|
||||
configuration file. Bake supports HashiCorp Configuration Language (HCL), JSON,
|
||||
and the Docker Compose YAML format. When you use Bake with multiple files, it
|
||||
will find and merge all of the applicable configuration files into one unified
|
||||
build configuration. The build options defined in your Compose file are
|
||||
extended, or in some cases overridden, by options specified in the Bake file.
|
||||
|
||||
The following section explores how you can use Bake to extend the build options
|
||||
defined in your Compose file for production.
|
||||
|
||||
### View the build configuration
|
||||
|
||||
Bake automatically creates a build configuration from the `build` properties of
|
||||
your services. Use the `--print` flag for Bake to view the build configuration
|
||||
for a given Compose file. This flag evaluates the build configuration and
|
||||
outputs the build definition in JSON format.
|
||||
|
||||
```console
|
||||
$ docker buildx bake --print
|
||||
```
|
||||
|
||||
The JSON-formatted output shows the group that would be executed, and all the
|
||||
targets of that group. A group is a collection of builds, and a target
|
||||
represents a single build.
|
||||
|
||||
```json
|
||||
{
|
||||
"group": {
|
||||
"default": {
|
||||
"targets": [
|
||||
"vote",
|
||||
"result",
|
||||
"worker",
|
||||
"seed"
|
||||
]
|
||||
}
|
||||
},
|
||||
"target": {
|
||||
"result": {
|
||||
"context": "result",
|
||||
"dockerfile": "Dockerfile",
|
||||
"network": ""
|
||||
},
|
||||
"seed": {
|
||||
"context": "seed-data",
|
||||
"dockerfile": "Dockerfile",
|
||||
"network": ""
|
||||
},
|
||||
"vote": {
|
||||
"context": "vote",
|
||||
"dockerfile": "Dockerfile",
|
||||
"target": "dev",
|
||||
"network": ""
|
||||
},
|
||||
"worker": {
|
||||
"context": "worker",
|
||||
"dockerfile": "Dockerfile",
|
||||
"network": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, Bake has created a `default` group that includes four targets:
|
||||
|
||||
- `seed`
|
||||
- `vote`
|
||||
- `result`
|
||||
- `worker`
|
||||
|
||||
This group is created automatically from your Compose file; it includes all of
|
||||
your services containing a build configuration. To build this group of services
|
||||
with Bake, run:
|
||||
|
||||
```console
|
||||
$ docker buildx bake
|
||||
```
|
||||
|
||||
### Customize the build group
|
||||
|
||||
Start by redefining the default build group that Bake executes. The current
|
||||
default group includes a `seed` target — a Compose service used solely to
|
||||
populate the database with mock data. Since this target doesn't produce a
|
||||
production image, it doesn’t need to be included in the build group.
|
||||
|
||||
To customize the build configuration that Bake uses, create a new file at the
|
||||
root of the repository, alongside your `compose.yaml` file, named
|
||||
`docker-bake.hcl`.
|
||||
|
||||
```console
|
||||
$ touch docker-bake.hcl
|
||||
```
|
||||
|
||||
Open the Bake file and add the following configuration:
|
||||
|
||||
```hcl {title=docker-bake.hcl}
|
||||
group "default" {
|
||||
targets = ["vote", "result", "worker"]
|
||||
}
|
||||
```
|
||||
|
||||
Save the file and print your Bake definition again.
|
||||
|
||||
```console
|
||||
$ docker buildx bake --print
|
||||
```
|
||||
|
||||
The JSON output shows that the `default` group only includes the targets you
|
||||
care about.
|
||||
|
||||
```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"]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```hcl
|
||||
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`:
|
||||
|
||||
```json
|
||||
{
|
||||
"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](/manuals/build/metadata/attestations/_index.md) 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](/manuals/build/metadata/annotations.md) 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:
|
||||
|
||||
```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"]
|
||||
}
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
- [Bake documentation](/manuals/build/bake/_index.md)
|
||||
- [Building with Bake from a Compose file](/manuals/build/bake/compose-file.md)
|
||||
- [Bake file reference](/manuals/build/bake/reference.md)
|
||||
- [Mastering multi-platform builds, testing, and more with Docker Buildx Bake](/guides/bake/index.md)
|
||||
- [Bake GitHub Action](https://github.com/docker/bake-action)
|
Loading…
Reference in New Issue