How to Use Rust with Kubernetes

You use Rust with Kubernetes primarily by building high-performance custom controllers or CRDs using the `kube-rs` client library, or by compiling your Rust applications into static binaries to run as lightweight, dependency-free containers.

You use Rust with Kubernetes primarily by building high-performance custom controllers or CRDs using the kube-rs client library, or by compiling your Rust applications into static binaries to run as lightweight, dependency-free containers. This approach leverages Rust's safety and performance while integrating seamlessly with the Kubernetes API and container ecosystem.

For building custom controllers, kube-rs is the standard tool. It provides a type-safe, ergonomic client that handles the Kubernetes API, including support for the Operator pattern, leader election, and resource reconciliation. Here is a minimal example of a controller that watches for ConfigMap resources and logs changes:

use kube::{
    api::{Api, ListParams, Patch, PatchParams},
    runtime::{controller, Config, Controller},
    Client, ResourceExt,
};
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize, Clone, Debug)]
struct MyConfigMap {
    data: std::collections::HashMap<String, String>,
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let client = Client::try_default().await?;
    let config_maps: Api<MyConfigMap> = Api::default_namespaced(client);

    let controller = Controller::new(config_maps, ListParams::default())
        .run(
            |cm, _ctx| async move {
                println!("Observed ConfigMap: {}", cm.name_any());
                Ok(())
            },
            Default::default(),
        )
        .await;

    controller.await?;
    Ok(())
}

To run your Rust application as a standard workload, you must compile it as a static binary to avoid needing a complex base image with glibc. Use cross to build for Linux targets from your development machine, then package it in a minimal container like scratch or alpine.

First, ensure your Cargo.toml includes the panic = "abort" setting for smaller binaries and use cross to build:

# Build a static binary for Linux x86_64
cross build --release --target x86_64-unknown-linux-gnu

# Create a minimal Dockerfile
# FROM scratch
# COPY target/x86_64-unknown-linux-gnu/release/my-app /my-app
# CMD ["/my-app"]

This results in a container image under 5MB, significantly reducing attack surface and startup time compared to standard Linux distributions. For more complex scenarios involving CRDs, you can use kubebuilder or controller-gen to generate the necessary Go-based scaffolding, then replace the Go controller logic with your Rust implementation using kube-rs.