Skip to main content

Deploy a standalone Rust binary to Cloud Foundry using binary buildpack

· 2 min read

For a customer we're managing a Cloud Foundry installation (actually Tanzu Application Service, TAS). I wanted to give the deployment of a simple Rust REST API a try and hit some issues which I'll describe in this blog post.

Tanzu Application Service (or TAS) is the VMware commercial implementation of the open source Cloud Foundry project. A customer of ours is running TAS to enable development teams to focus on building software instead of having to handle a lot of Ops-related tasks. I'm learning how to use Rust and decided to try and deploy a compiled Rust binary onto TAS.

The application itself is a simple REST API, built using Actix Web. I followed this blog post to create a very simple ticket API. The only real change I made was to dynamically assign a port number from the environment:

let port = env::var("PORT").unwrap_or(String::from("8000")).parse::<u16>().unwrap();
println!("Running on port {port}");

HttpServer::new(move || {
App::new()
.app_data(app_state.clone())
.service(post_ticket)
.service(get_tickets)
.service(get_ticket)
.service(update_ticket)
.service(delete_ticket)
})
.bind(("0.0.0.0", port))?
.run()
.await

A simple cargo build produces a binary in the target/debug folder, which in my case is called actix_demo. So let's see what happens when we push that to TAS:

cf push actix_demo -c './actix_demo' -b binary_buildpack

By the way, the reason I'm using a binary buildpack here is because TAS by default doesn't have a Rust buildpack although these do exist.

The result of this first attempt is an error message in the logs:

ERR ./actix_demo: /lib/x86_64-linux-gnu/libc.so.6: version `GLIBC_2.28' not found (required by ./actix_demo)

When you compile Rust, by default it will dynamically link the platform's standard C runtime (CRT). So that library won't be included in the Rust executable but is expected to be provided by the host OS. However, you can tell the Rust compiler to statically link the CRT for a specific target by specifying a target feature. When using cargo, you do this by defining a .cargo/config.toml file with the following contents:

[build]
rustflags = ["-C", "target-feature=+crt-static"]
target = "x86_64-unknown-linux-gnu"

The crt-static flag informs the Rust compiler to statically link the CRT, in this case for the x86_64-unknown-linux-gnu target.

We now get a binary in the folder target/x86_64-unknown-linux-gnu/debug and when we push that, we have a successful deployment of a standalone Rust binary onto TAS.