libcnb.rs

libcnb.rs is a framework for writing Cloud Native Buildpacks in Rust.
It is an opinionated implementation adding language constructs and convenience methods for working
with the spec. It values strong adherence to the spec and data formats.
It currently targets version 0.10 of the CNB Buildpack API specification.
Quick Start Guide
This quick start guide walks you through writing a simple Cloud Native Buildpack in Rust with libcnb.rs. It will also demonstrate how to package your buildpack and how to build an application image with it.
Development Environment Setup
In addition to the libcnb crate, we need some tools to compile, package and run the buildpack. These steps only need to be carried out once and don't need to be repeated for each buildpack you will write.
libcnb Cargo Command
Start by installing libcnb-cargo, which provides the libcnb Cargo command
that we will use later to package our buildpack:
cargo install --locked libcnb-cargo
Cross-compilation prerequisites
It is common to write and build your buildpack on a platform that is different from the platform on which the buildpack will
eventually run. This means we have to cross-compile our buildpack. The libcnb package Cargo command tries to help you set
up your environment depending on your host platform, but we always need the appropriate target platform for Rust, which
we can install with rustup:
rustup target add x86_64-unknown-linux-musl
Docker
If you don't have it already, we need to install Docker. Refer to the Docker documentation on how to install it for your operating system: https://docs.docker.com/engine/install/
pack
To run our buildpack locally, we will use pack, a tool maintained by the Cloud Native Buildpacks project to support
the use of buildpacks. It's the tool that we will eventually use to run our buildpack and create application images.
Find their documentation about installing it here: https://buildpacks.io/docs/install-pack/
Project Setup
After we've successfully set up our development environment, we can move on and create a new Rust project for our buildpack. First, we create a new binary crate with Cargo:
cargo new my-buildpack
Then, add the libcnb dependency to your project's Cargo.toml:
cargo add libcnb
Note: If you get an error about cargo add not being a supported command, your Rust version is too old
and will need to be updated (ideally to the latest stable version).
Since we're writing a Cloud Native Buildpack, we also need a buildpack.toml. Use the template below and write it to a
file named buildpack.toml in the root of your project, right next to Cargo.toml.
= "0.10"
[]
= "libcnb-examples/my-buildpack"
= "0.1.0"
= "My Buildpack"
That's all we need! We can now move on to finally write some buildpack code!
Writing the Buildpack
The buildpack we're writing will be very simple. We will just output a "Hello World" message during the build and set the default process type to a command that will also emit "Hello World" when the application image is run. Examples of more complex buildpacks can be found in the examples directory.
Modify the project's src/main.rs file to contain the following:
use ;
use ;
use process_type;
use ;
use ;
use ;
pub ;
// Implements the main function and wires up the framework for the given buildpack.
buildpack_main!;
Packaging the Buildpack
Now that our buildpack is written, it's time to package it, so that it can be run. If you followed the steps to setup
your development environment, you have access to the libcnb Cargo command that will handle packaging for you.
In your project directory, run cargo libcnb package to start packaging:
$ cargo libcnb package
🚚 Preparing package directory...
🖥️ Gathering Cargo configuration (for x86_64-unknown-linux-musl)
🏗️ Building buildpack dependency graph...
🔀 Determining build order...
🚚 Building 1 buildpacks...
📦 [1/1] Building libcnb-examples/my-buildpack (./)
# Omitting compilation output...
Finished dev [unoptimized] target(s) in 8.24s
Successfully wrote buildpack directory: packaged/x86_64-unknown-linux-musl/debug/libcnb-examples_my-buildpack (4.09 MiB)
✨ Packaging successfully finished!
💡 To test your buildpack locally with pack, run:
pack build my-image-name \
--buildpack packaged/x86_64-unknown-linux-musl/debug/libcnb-examples_my-buildpack \
--trust-extra-buildpacks \
--path /path/to/application
/Users/example/src/my-buildpack/packaged/x86_64-unknown-linux-musl/debug/libcnb-examples_my-buildpack
If you get errors with hints about how to install required tools to cross-compile from your host platform to the target platform, follow them and try again. These differ from platform to platform, which is why they're not part of this quick start guide.
Running the Buildpack
You might have seen in the output that we're now ready to run our buildpack locally
with pack. Before we can do this, we need an application to build. Since our buildpack does not interact with the
application code at all, we just create an empty directory and use that as our application:
$ mkdir bogus-app
$ pack build my-image --buildpack packaged/x86_64-unknown-linux-musl/debug/libcnb-examples_my-buildpack --trust-extra-buildpacks --path bogus-app --builder heroku/builder:22
...
===> ANALYZING
Image with name "my-image" not found
===> DETECTING
libcnb-examples/my-buildpack 0.1.0
===> RESTORING
===> BUILDING
Hello World!
The build is running on: linux (amd64)!
===> EXPORTING
Adding layer 'buildpacksio/lifecycle:launch.sbom'
Adding 1/1 app layer(s)
Adding layer 'buildpacksio/lifecycle:launcher'
Adding layer 'buildpacksio/lifecycle:config'
Adding layer 'buildpacksio/lifecycle:process-types'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Setting default process type 'web'
Saving my-image...
*** Images (85b067fc926a):
my-image
Successfully built image my-image
Running the image
The newly created Docker image can be run in the same way as you would a Docker image created via docker build.
If all went well, you should see our "Hello World!" message in your terminal:
$ docker run my-image
Hello World!
Next Steps
While the buildpack we've written in this quick start guide is not very useful, it can serve as a starting point for a more useful buildpack. To discover more of the libcnb API, browse the examples directory and the documentation on docs.rs.
Later, when you are ready to write integration tests for your buildpack, see the libcnb-test documentation.