Docker Build the best way with Docker Bake

Download MP3

The Docker Bake Build tool just went
general availability, and I'm excited

about what this means for creating
reproducible builds and automation

that can run anywhere CI locally.

I love it.

Really, I'm gonna break down some
of the features, the benefits

and walk through some examples.

For over six years, Docker has had this
little known tool that we could execute

with a Docker Buildex Bake command.

It's meant to provide even more
customization and flexibility than

what we're building with today.

But if Bake has been around all these
years, why isn't everyone using it?

To answer that, I'll need to
take you back in time to 2018.

Docker was on a streak of releases and
it seemed like they were creating new

tools every few months, experimenting
with various container tools on top of

Docker engine to see what would stick.

We had a release of the BuildKit
project and then Bake came out with

the release of Build X Command, even
us Docker captains were having a hard

time keeping up with all the ideas
coming out of Docker, Inc. But we also

started to see Docker deprecate products
causing some of their less popular tools

to silently stop receiving updates.

So I and others were hesitant to use
Bake in any significant way since we

weren't really confident in its future.

And we were kind of right at the
time, everyone was talking about

orchestration and Docker didn't mention
Bake again in a significant way.

So we just assumed that it would
quietly become a deprecated

idea like so many others.

Fast forward to today, and
Docker recently announced general

availability of Docker Bake.

They did this as a signal to us in the
community that after years of development

and heavy use internally, they're ready
to fully support Bake in the community.

And in fact, they're so committed to
this that they have announced that

they have a plan to change Compose,
to use, bake in the background for

all of its bills in a future release.

Now that I know I can trust in a
future for Bake, why do I care?

Like what can it do for me today?

Well, at its Core Bake is a simple
command that gets its instructions

from a file formatted in JSON,
Compose, or my preference, HCL?

Yes, that's the file format
we use with Terraform.

Bake Acts as a kind of
BuildKit native make file.

It provides a more structured
way to configure builds.

It still uses Docker files as the detailed
instructions, and you'll probably have

more stages in your Docker files if you
go fancy with it, but it replaces long

complex build commands and build scripts
with a more advanced and appropriate tool.

Bake is a superset of Docker
build and composed builds, but it

makes those things even easier.

Here's a partial list of things
that bake can do for you.

before I get to the list of benefits
and examples of how you can use Bake,

I wanna thank today's sponsor me.

I've been making Docker, Kubernetes,
and DevOps content since at least

2017, and I welcome you to my community
of cloud native DevOps engineers.

Besides this podcast, you can join
my 20,000 user Discord server.

Subscribe to my YouTube channel
where I'm posting content or

live streams You can also sign
up for my low traffic newsletter.

Or buy one of my courses with a coupon.

If you'd like to buy me a coffee
and support my work, you can become

a member on YouTube, or on Patreon.

And you'll get exclusive benefits
like videos on YouTube or

separate chat rooms on Discord.

I should also mention my High Fives
DevOps Guild, which is a monthly

virtual meetup on discord with other
DevOps professionals Where we talk

trends, what we're working on, and
anything we're really excited about.

I don't talk about that enough, but I've
been doing it for years and I always

have fun hosting that group every month.

So if you'd like to join that video call,
look for the high fives in the memberships

plans on YouTube, Patreon, or my website.

It's about six bucks a month.

Okay.

Let's talk about bakes benefits and some
examples on the YouTube version of this,

which you can see in the show notes with
everything else and all the details.

That is something where I go
through, I think it's four examples

in detail going through the files.

How it works with Compose.

The difference between the HCL
format that I prefer for using Bake,

which is the Terraform language
and how that compares to Compose.

Pretty much you can do 90% of this
stuff, or maybe 80 to 90% of all this

stuff Bake can do in a Compose file, but
I think I much prefer the HCL format.

Because it gives you a separate file
that's just focused on building images,

so it doesn't muddy the waters of
where the composed file is sort of

service centric and it has the volumes
and the services, and it's usually meant

for local dev and that sort of thing.

I like having this Docker
dash bake do HCL file in the

same route, director, my repo, where
the Dockerfile is and the Docker

ignore, and possibly a composed file.

It just feels right to have that separate
file sitting beside the Dockerfile.

But here's a short list of some
examples of things you can do with Bake.

A lot of these you can actually do
in BuildKit with just Docker build if

you wanna make a really long command.

And you can do a lot of it in Compose
if you wanna make the build section of

each composed service really long too.

Alright.

First.

Improve build speed by letting
BuildKit automate the caches and

parallelism essentially, because you
can give Bake a single command, it

will do potentially multiple builds.

You can have one command building
dozens of different images if you

set it up that way, it optimizes
the caching and parallelism across

all those different activities.

So that it only has to transfer your
local source code once into the BuildKit

engine, and it will parallelize all
the different parts of the build,

the different architectures in a
way that you can't really get in

advance cases with the Docker build
command or with composed builds.

Next you can import or export files
outside of the Docker context for

building images, which is a little,
I mean, honestly, I would feel like

it's a little bit of an anti-pattern.

'cause I always think of everything
in a Docker build is in that directory

or subdirectory that you build from.

That's, that's the context.

But there is an option where you can
add multiple context locations in the

file system that are outside that,
and when you finish the build, you

can choose to export everything in
the image to the host file system.

Maybe you were just building a go
or rust or see binary and it's a

single file and you want to put it on
GitHub releases for download, right?

So you can kind of do all this
at once, uh, except for maybe the

part where you actually upload
it to the releases in GitHub.

But you can have it not just in an image.

You can have the results
put out to the file system.

Next, there are more options for adding
variables to your builds and including

those in functions, which you can even
use Golang simplistic functions inside the

HCL format to have advanced programmatic
ish flow of how the image gets built.

next, like other ways you
can build images in BuildKit.

You can add SBOs and Providence
attestations to the images with

little options you can set in the HCL.

Next.

You can tag the image with multiple
names, which you could always do, but a

lot of people don't realize you can do
that in a single Docker build command,

but you can make a list of all the
different names you want to name it.

Maybe you want it to be colon latest, but
you also want it to be colon aversion or

a date timestamp, or you want to indicate
that it's approved for release in the tag.

Or maybe you have multiple registries,
which I see a lot, and you maybe

want to push these certain images.

For maybe an official release, you
wanna push 'em up to GitHub Container

Registry, also up to Docker Hub.

And if you're doing something
private in your company, you might

wanna push it to an ECR instance
as well as for developers and GHCR.

I mean, there's just all sorts of
scenarios, but you can do it all at

once essentially, and have a, a full
list with variables and a little bit

of advanced functions where you can put
in day timestamps and other methods to.

Inject dynamic tags into that file.

Next You can build for multiple
architectures concurrently, of course.

So you're always wanting to build these
days on arm and a MD. Next, just like you

can use Compose override files if you've
ever done that, I'm a big fan of that.

For Compose, for custom local individual
developer settings, you just create

a file called Docker Compose override
YAML, and then Compose will automatically

pick that up on your local system.

My technique there is I
usually put that particular.

File name in the dot get ignore so
it never gets back into the repo.

And then I create sort of a sample
override file for developers, and

then they will all create their
own override that they'll use for

development environment variables.

Well bake has that too.

Next you can set an option to
automatically push to registries after

the builds are finished, and that's
a part of something called the output

where you can have it, choose to load
the image into the Docker image cache,

or export to the file system, or
automatically push the registries or do

nothing and just have it leave itself
in the BuildKit cash, which I see used.

For building stages of images that
maybe aren't meant to go somewhere.

Maybe you have a stage that does a
CVE scan or a linter or some other

sort of testing, and you're really
just using, at this point, the bake

file and the Dockerfile as a way
to automate that stuff in the same

tooling during your build process.

But you don't necessarily need
those particular images pushed

anywhere or put anywhere.

You just need to run.

That build stage.

So just leave it in the build cache.

Right?

And without examples, this won't maybe
make a lot of sense, but inside the bake

file you have something called targets,
which is a particular build and that

build could technically build multiple
images or multiple architectures of

images, but it's the one thing that
you execute from the bake command.

You can also group multiple targets
into groups and build them all at once.

This is really handy for mono repo.

So if you decide that a certain file in
the mono repo changes, you wanna build

all images in that mono repo, you can
technically do that with one bake command

and just have multiple targets, and
then group those into a group and call

that group and it will automatically
cash and parallelize all that.

Next.

You can also build images remotely by
just pointing bake to a GitHub URL and

then it will build what it finds in there.

And you can do all of that in a single
bake command, which you can then throw

into your CI, you can run it locally.

And that's one of the wonderful
things of Bake is it is meant to run

everywhere In the true style of Docker,
it works on more than your machine.

And you know, all of our different cis
nowadays have abstracted the Docker and

BuildKit stuff into YAML or whatever their
format is, which is usually YAML nowadays.

And so you're usually doing YAML
work in their specific CI format.

And the power of this bake is that
you can take a lot of, at least

the build complexity, possibly even
more than the build complexity.

since you can make all these fancy
Dockerfile stages to do other things,

I. You could choose to use the bake
file and then in your CI, let's talk

about GitHub Actions for a second.

You really are just running a
Docker buildex bake command, and

you can easily switch cis or run
it locally in exactly the same way.

We don't today have that option in
GitHub Actions because as far as I

know, act is the only real way to try
to run GitHub Actions locally, but it's.

A non-official third party tool that
has limits and functionality problems.

So I would absolutely prefer
the bake file format there.

And of course, Docker has their own
official GitHub Actions, of which one

of them all along has been the bake
GitHub action that I haven't been

using because I was for reasons not
sure what its purpose or future was.

So I was always using and teaching
and showing off examples of using

the Docker build GitHub action.

Which I probably wouldn't be surprised
to find out that behind it is really

bake, just running in the background.

But there's now an official bake action,
so I'm going to personally be switching

a lot of my stuff over from the Docker
build action as I start writing some

of these HCL files for Docker Bake.

I'm gonna switch over to that GitHub
action to hopefully reduce the amount.

Of YAML, I have to type in order
to get things at GitHub to work.

And then with the advantage of being able
to run that exact same build locally.

And like I said earlier, you can watch
the YouTube video in in LinkedIn, the

show notes to see some of the examples
as well as a little bit of the video of

me showing how I baked cookies, which was
just a fun part of that video to make.

All right.

One of my final thoughts about Bake
is that to take full advantage of

it as a CI workflow engine, you
need to lean into Dockerfile stages.

If you like the idea of a Docker Buildex
Bake command being one of the only

things you need to run in your CI.

Then you need to lean into expanding
your Dockerfile with testing stages,

maybe CVE scanning stages, et cetera.

Now.

I've given demos at conferences where
I do that exact thing with multi-stage

builds, showing off how multi-stage
builds work and the things you can do

with them, and trying to shove every
possible CI action into a Dockerfile.

But the reality is, is that
Dockerfile stages aren't a

great place for a lot of that.

Stuff to live.

A lot of the CI tools actually
expect to run from outside

the image once it's built.

So for bigger teams and projects, it
kind of muddies the waters between

building your app image and all the other
activities you want to happen In CI, do we

want the single file format of Dockerfile
to be that single source of truth for

everything and then you end up with a
possible 300 or 400 line Dockerfile.

Also CI solutions don't
monitor BuildKit well.

So to them, this just looks like
one big pipeline step rather than

the detailed view you would get if
each action was its own CI step.

I've noticed that over the years as
I've tried to make advanced Docker

builds, and it's unfortunate that the
CI companies don't do more to see into

what BuildKit is doing to give you that
advanced workflow or pipeline view.

This really comes down to preference
of where you like to spend

your time creating automation.

Do you love the Dockerfile format
and want to use it to the max?

Great.

Use Bake for as much as you can.

Do you use GitHub Actions for
CI and prefer the YAML job

structure of that solution?

Great.

Do that.

I can tell you that if you like the
idea of bake, because you can run it

anywhere and you can make it declarative
and repeatable for more things than

just image builds, but maybe you're
not a fan of doing it all in Docker

files, then you might wanna look at
more advanced tools like Dagger that

allow you to run all these things.

With the language your app is written in.

More on that in another video.

Thanks for listening.

I'll see you in the next one.

Creators and Guests

Bret Fisher
Host
Bret Fisher
Cloud native DevOps Dude. Course creator, YouTuber, Podcaster. Docker Captain and CNCF Ambassador. People person who spends too much time in front of a computer.
Beth Fisher
Producer
Beth Fisher
Producer of DevOps and Docker Talk podcast since 2019. Assistant producer on Bret Fisher Live show on YouTube. Business and proposal writer by trade.
Docker Build the best way with Docker Bake
Broadcast by