Customizing Cloud native buildpacks: practical examples

CNCF Buildpacks come in a variety of flavors; just look at what the pack CLI (as of version 0.16) documents by default:

Scope of the article

This article will focus on how to build a Java maven based project, but many parts of it could be re used for other languages.

This article won’t cover the Google builder in particular, since, even if it’s a standard CNCF buildpack, it is focused on Google Cloud deployment (including function); the documentation is pretty extensive though, check it out.

Also, this article won’t cover the Heroku builder, also a standard CNCF buildpack, also focused on a PaaS vendor, Heroku. Their java support documentation can be found on their website.

This article will mainly list examples on how to customize the standard and also paketo builpacks behavior; since they provide, according to me, the greatest level of flexibility (a lot of buildpacks can be swapped in / out and each of them has a specific focus), a non vendor approach (paketo buildpacks were launched by Pivotal Cloud Foundry but do not target Pivotal products specifically) and also because I found some use cases difficult to come by, hence this blog post !

One interesting thing to note is that while all 3 builders listed by the pack CLI are CNCF buildpack builders, they all have their different way to customize the build:

  • Google builder seems to lean on environment variable to override defaults
  • Heroko builder uses a file named
  • Paketo uses a mix of environment variables and bindings

Paketo buildpacks: choose a different JVM version than the default one

At the time of writing, Java 11 is the default version for the Bellsoft Liberica buildpack.

But you can change that, setting the environment variable named BP_JVM_VERSION to 15.* for example; the official documentation describes in great detail what other environment variables are available.

Paketo buildpacks: choose a different JVM than Bellsoft Liberica

By default, the paketo builder will choose a Bellsoft Liberica JVM;

but you can override this default behavior specifying another paketo supported JVM buildpack:

A bit verbose, I got to admit; but you could imagine creating your own meta-buildpack that would reference all those buildpacks: this is what the paketo team did with the java meta buildpack.(also called buildpack-group)

Paketo buildpacks: use custom CA certificates

For every need, there’s a buildpack! The ca-certificates buildpack will help you ship your own ca certificate in your image.

You’ll need to create a binding folder with the CA public certificate and a type file with only the string content ca-certificates

Add certificates binding at runtime

If your image was already built, then you can add your ca-certificates binding at runtime

Add certificates binding at build time

If you can though, it’s probably better to add your public CA certificate at build time, so that your container will accept your CA no matter how the container was called

Paketo buildpacks: use a custom settings.xml

In case you need access to private Maven repository to get your project 3rd party libraries, you’ll need to configure your maven buildpack to pick up your custom settings.xml; once again, bindings to the rescue !

First, provide your settings.xml and a type file with content equals to the string maven in a binding folder

Of course, you’ll need to provide this binding to the pack CLI:

You’ll notice the additional environment variable named BP_MAVEN_BUILD_ARGUMENTS being used here to provide the password to access the private repository, as well as the maven goal. Here are the relevant parts of the settings.xml :

How to extend your buildpack run image

It’s possible that you don’t want to rely on your buildpack provider run image (the base image of your app image); for example because it’s too heavy for your needs or because there’s a missing tool or library that your app will require at runtime.

So could something as simple as this work?

Unfortunately, no…

But it’s not that big of a deal… it’s just a missing label! Let’s build an image with the right label (and proper user too while we’re at it)

Oups, proper mixins are required by this stack… I could go on and add the required labels, but… maybe I could just extend the existing run image

How to extend your buildpack builder image

You would extend or replace the buildpack builder image when you need a special tool or library to build your app; take for example a preprocessor maven would call via the exec-plugin

Given this scenario, just inherit from the buildpack builder image and add your required libraries / tools