TLDR: Docker recently launched the Bake feature and file spec. At Shipyard, we’ve found it quite useful, and wanted to share how you can get started. You can use it to save your build config: swap long Build commands with a simple call to bake
.
What is Docker Bake?
Docker Bake is an experimental feature that allows users to store their Docker build config in a file format, instead of as CLI flags. Once you define your images’ options in a “Bake file” (a declarative file with a YAML, HCL, or JSON format) and run docker buildx bake
, Docker BuildKit will start concurrently building your images from the provided config.
Why use Docker Bake?
Docker build commands are notoriously lengthy. When you run your Dockerized application, you’re copy/pasting the same flags every time. Since your flags are unlikely to change that much from run to run, you might as well store them.
Docker Compose is also a great option for storing Docker container-specific configuration. So how is Bake different from a Compose file? Docker Bake is a tool for Docker Buildx (for context: these were previously distinct, but now when you run docker build
, you’re using an alias for docker buildx build
). Using Bake with Buildx allows you to build multiple images in parallel and is better optimized for CI/CD pipelines. Running the bake
command actually scans your repository for a Compose file, from which Bake will pull config (if found). Plus, Bake has some attributes that aren’t yet available in Compose, notably groups and inheritance.
How do I use Docker Bake?
Docker Bake will invoke a Bake file to build images using the file’s configured options. Here’s what you’ll need to do to get started:
1. Creating a Bake file
A Bake file can be written in HCL, YAML, or JSON. Docker recommends choosing HCL (HashiCorp Configuration Language) because it supports a more feature-complete Bake spec than the others. A valid Bake file should be called docker-bake
followed by your chosen file extension.
Docker Bake supports multiple Bake files within a project, and will read from all of them, using Bake’s inheritance rules for overrides.
2. Porting over your Docker config
Next, we’ll take our Docker build config options and transfer them to our Bake file. Here’s the docker build
command that we want to store:
docker build \
-f frontend/Dockerfile \
-t frontend:v1.0.2 \
--no-cache \
--platform linux/amd64,linux/386, linux/arm64 \
.
Using docker-bake.hcl
as our default file, we can convert these flags to a readable file format:
target "frontend" {
context = "."
dockerfile = "frontend/Dockerfile"
tags = ["frontend:v1.0.2"]
no-cache = true
platforms = ["linux/amd64", "linux/386", "linux/arm64"]
}
One of the perks of Bake is that you can define build configs for multiple images, then have them build in parallel, thanks to Buildx’s use of BuildKit. In this example, we’re taking our above config and adding another service: api
:
group "default" {
targets = ["frontend", "api"]
}
target "frontend" {
context = "."
dockerfile = "frontend/Dockerfile"
tags = ["frontend:v1.0.2"]
no-cache = true
platforms = ["linux/amd64", "linux/386", "linux/arm64"]
}
target "api" {
context = "."
dockerfile = "api/Dockerfile"
args = {
NODE_ENV = "development"
}
tags = ["api:v3"]
platforms = ["linux/amd64", "linux/386", "linux/arm64"]
}
3. Invoking Docker Bake
Finally, you can build your images with Bake from your Bake file by running docker buildx bake
.
What if you only want to build a certain target from the file? You can specify that. For example, in our Bake file, we’ve defined a frontend
target. The syntax to build that is simply docker buildx bake frontend
.
Docker Bake also allows users to define groups. Above, we have a default
group. We can define as many groupings as we need, depending on how we need to mix/match build definitions. We invoke a group build for default
with the syntax docker buildx bake default
.
Using Bake with Compose
Docker understands that your image build config already lives in your Docker Compose definition. Bake’s file lookup order checks for a Compose file first, and uses its configuration as a base. If you also have a Bake file, it will override any conflicting flags/options. However, if your Compose already has the config you need, you won’t need a separate Bake file.
In Compose, each container is defined as a service
. This translates to a Bake target
. For example, if you have a Compose file with a service named proxy
, you’ll be able to run docker buildx bake proxy
to get just that container built.
You can use the --print
flag to verify how Bake has interpreted your build configs. This will output the complete HCL that Bake uses to build, pulled together from both Bake and Compose files.
Beyond Bake
Once you’re ready to test your Dockerized application, you’ll want to deploy it to a production-like preview environment. That’s where Shipyard comes in. We take your Compose definition and transpile it to Kubernetes so you can get the orchestration you need to approximate your app’s real world performance. And it’s quick: we also use Docker BuildKit for lightning-fast, parallel Docker image builds. Give it a try!