Docker Build the best way with Docker Bake
Download MP3The 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


