When creating applications that extend or interact with Kubernetes, there are times when it’s necessary to deploy and develop against a real K8s cluster. While Kubernetes makes it trivial to apply and roll out new changes, the building and pushing new dev Docker images for your application can be a rigamarole. On top of that, you also have to remember to configure the imagePullPolicy
for your containers to Always
. Otherwise, who knows if the node
your app ends up running on has the old image cached!
Fortunately, there is a tool that can help solve all of these problems. The kbld
CLI (pronounced “k build”) assists with all things around image building and pushing for Kubernetes. It’s under active development so refer to the kbld site for the most up to date feature set, but I’m a fan of its ability to do the following:
- Know where my source code to build lives
- Build an OCI image (using Docker or Cloud Native Buildpacks)
- Tag the image and push it to the registry of my choice (local registry for KIND, DockerHub, GCR, etc.)
- Find references to the image in Kubernetes deployment YAMLs and replace vague references with image digests for deterministic deployments
I’m less of a fan, however, of its terse documentation. So in this post, I’m going to show how I use kbld
to build Docker images for my projects.
Understanding kbld Configuration
Like most things in the Kubernetes ecosystem, the kbld
CLI is configured by YAML files. There are several options here, but the two main YAML objects I use are Sources
and ImageDestinations
.
Sources
apiVersion: kbld.k14s.io/v1alpha1
kind: Sources
sources:
- image: image-repository/image-name
path: /path/to/source/code
pack:
build:
builder: heroku/buildpacks:18
A Sources
object declares the images that kbld should be responsible for building. It includes information about the path
for the source code of an image as well as configuration for the image builder (docker
or pack
).
ImageDestinations
apiVersion: kbld.k14s.io/v1alpha1
kind: ImageDestinations
destinations:
- image: image-repository/image-name
newImage: docker.io/image-repository/image-name
ImageDestinations
tell kbld how it should tag and push the images that it has built. It’s a pretty simple resource, and I was surprised at first that there was nothing about authentication here for private registries. That config, however, comes in either through your Docker config or as environment variables. See these kbld authentication docs for more information on that.
Are these Kubernetes Resources?
An astute developer might recognize that these kbld resources look suspiciously similar to Kubernetes resource objects and wonder if there are any CRDs involved here. That’s not the case, though. The similarities are purely superficial, and these resources are used client-side directly by the kbld
CLI.
As always, refer to the kbld config documentation for the latest on what is possible.
How to Use kbld
The following examples refer to a simple Go app called mando that will be built and deployed to Kubernetes using kbld
.
Building an app with kbld using a Dockerfile
If you wish to follow along, you’ll need the following:
- Install docker
- Sign up for a free DockerHub account or have access to a different image registry
- Install kbld
- Have access to a Kubernetes cluster and
kubectl
if you want to deploy
To start, since we’ll be publishing to an OCI image registry, we’ll first need to authenticate. Since I’m pushing my images to DockerHub that means I just need to docker login
.
For the following, I’ll be working off of the kbld-dockerfile-example
branch of my test app repo.
In this repo, I have an example Deployment
for Kubernetes in the deploy
directory and the kbld files within the build
directory.
---
apiVersion: kbld.k14s.io/v1alpha1
kind: Sources
sources:
- image: downey/mando
path: .
Here I’ve configured kbld to build my image, downey/mando
, using the code and Dockerfile
at the root of my repository.
---
apiVersion: kbld.k14s.io/v1alpha1
kind: ImageDestinations
destinations:
- image: downey/mando
newImage: docker.io/downey/mando
This ImageDestinations
configuration tells kbld to tag and push my image to DockerHub at docker.io/downey/mando
.
Now to use this configuration, in the root of the app directory we can run:
kbld -f build -f deploy
We will then see kbld work its magic. It will:
- Build the
mando
app using itsDockerfile
- Push it to DockerHub
- Update the references to the image in our Kubernetes
Deployment
to use the digest for the image we just built - Output the Kubernetes YAML with all changes
We can then either write this output to a file or deploy it directly to Kubernetes:
kbld -f build -f deploy | kubectl apply -f -
It might not seem like much at first. But after dozens of cycles of docker build
, docker push
, updating Kubernetes config to point to a new tag, and deploying, kbld can end up saving a bunch of time!
Where I really find kbld useful though, is with Cloud Native Buildpacks.
Building an app with kbld using Buildpacks
For this section I’ll be working off of the kbld-pack-example
branch of my test app repo. If you’re unfamiliar with the concept of buildpacks, I’d encourage you to learn more about them or check out my blog post on deploying apps to Kubernetes with Buildpacks.
Using Buildpacks instead of a Dockerfile to build is simple with kbld
. The flow is pretty much the same – instead of a Dockerfile, we will use the pack CLI (install it if you haven’t already) and make some minor tweaks to our Sources
YAML.
---
apiVersion: kbld.k14s.io/v1alpha1
kind: Sources
sources:
- image: downey/mando
path: .
pack:
build:
builder: cloudfoundry/cnb:tiny
Here we tell kbld which “builder” to use. I’m using the cnb:tiny
builder since it’s optimized for creating “distroless” lightweight images for Go binaries. Perfect for this use case. If you’re unsure which builder to use, you can always run pack suggest-builders
to get an up-to-date list of builders from Cloud Foundry and Heroku.
Anyways, as I said earlier, the flow is the same as before. To build and deploy, just run:
kbld -f build -f deploy | kubectl apply -f -
The kbld
CLI will now build using pack
instead of docker
! Since I use the pack
CLI pretty infrequently, I’m more than happy to hand over the reigns to kbld
and let it orchestrate the build and push.
Summary
Well that’s about it. If you’ve gotten this far, hopefully this post has helped demystify some of the basic use cases for kbld
and how it can help streamline the Docker image push-build-deploy flow. If you’re looking to learn more, check out the kbld docs or join the #k14s
channel on Kubernetes Slack. Good luck! 🌝