Getting Started with Rust and Kubernetes using kube-rs

Last updated: Apr 13, 2025

1. Introduction: Automating Kubernetes with Rust

Kubernetes (k8s) has become the standard for container orchestration, but managing its resources
programmatically often involves interacting with its extensive REST API. While kubectl is
excellent for manual operations, building controllers, operators, or custom automation tools requires a client
library.

Rust, with its performance, safety, and strong typing, is a great choice for building reliable Kubernetes
tooling. The kube-rs crate provides a powerful and idiomatic Rust client for the Kubernetes API.

This guide introduces kube-rs and demonstrates how to set up a client, list resources (like
Pods), and understand the basics of interacting with the Kubernetes API from a Rust application.

2. Thekube-rsCrate

kube-rs is the predominant Rust client for Kubernetes. Key features include:

  • Asynchronous API built on Tokio.

  • Strongly typed representations of Kubernetes API objects (Pods, Deployments, Services, etc.) generated
    from the official OpenAPI spec.

  • Helper functions for common operations (list, get, create, update, delete, watch).

  • Automatic discovery of cluster configuration (from~/.kube/configor in-cluster service
    account).

  • Support for Custom Resource Definitions (CRDs).

It aims to provide a safe, ergonomic, and efficient way to interact with Kubernetes from Rust.

3. Prerequisites

  • Rust and Cargo installed (seeGetting Started with Rust).

  • Access to a Kubernetes cluster. This can be:

    • A local cluster viaMinikube, Kind, k3d, or Docker
      Desktop.

    • A managed cloud cluster (EKS, GKE, AKS).

  • kubectlconfigured to communicate with your cluster (kube-rsuses the same
    configuration). Verify withkubectl cluster-info.

  • Basic understanding of Kubernetes concepts (Pods, Deployments, etc. - seeGetting Started with Kubernetes).

  • Familiarity with Rust’sasync/awaitand Tokio.

4. Project Setup

Create a new Rust binary project:

cargo new rust-k8s-client
cd rust-k8s-client

Add the necessary dependencies to your Cargo.toml:

[package]
name = "rust-k8s-client"
version = "0.1.0"
edition = "2021"

[dependencies]
kube = { version = "0.88", features = ["runtime", "derive"] } # Check crates.io for latest version
k8s-openapi = { version = "0.20.0", features = ["v1_28"] } # Match your cluster API version
tokio = { version = "1", features = ["full"] }
serde = { version = "1.0" }
serde_json = "1.0"
anyhow = "1.0" # For easier error handling in examples

Important:

  • Adjust thekubeversion as needed.

  • Thek8s-openapiversion and feature flag (e.g.,“v1_28”) should ideally match
    the API version of the Kubernetes cluster you are targeting. Usekubectl versionto check your
    cluster version.

  • We addanyhowfor convenient error handling in these examples.

Alternatively, use cargo add:

cargo add kube --features runtime,derive
cargo add k8s-openapi --features v1_28 # Adjust version feature
cargo add tokio --features full
cargo add serde serde_json anyhow

5. Creating a Kubernetes Client

The first step in any interaction is creating a Client instance. kube-rs makes this
easy by automatically inferring the configuration.

Modify src/main.rs:

use kube::{Client, Config};
use anyhow::Result; // Using anyhow for convenient Result type

#[tokio::main]
async fn main() -> Result<()> { // Return anyhow::Result
    println!("Attempting to create Kubernetes client...");

    // Infer the runtime environment and try to create a Kubernetes Client
    let client = Client::try_default().await?; // The '?' propagates errors

    println!("Successfully created Kubernetes client.");

    // We'll add more logic here later...

    Ok(())
}

Client::try_default().await attempts to load configuration from:

In-cluster service account (if running inside a Kubernetes Pod).
Your local kubeconfig file (typically ~/.kube/config).

Run this with cargo run. If your kubectl is configured correctly, it should print
the success message.

6. Listing Resources (Pods Example)

To work with specific Kubernetes resources (like Pods, Deployments, etc.), you use the Api type
from kube-rs, parameterized with the corresponding struct from k8s-openapi.

Let’s list all Pods in the default namespace:

use kube::{Client, Api};
use k8s_openapi::api::core::v1::Pod; // Import the Pod struct definition
use anyhow::Result;

#[tokio::main]
async fn main() -> Result<()> {
    let client = Client::try_default().await?;
    println!("Created Kubernetes client.");

    // Create an API handle for Pods in the default namespace
    let pods: Api = Api::default_namespaced(client.clone()); // Use client.clone() if client is used later

    println!("\nListing Pods in default namespace:");

    // List pods using ListParams (can be customized for label selectors etc.)
    let pod_list = pods.list(&Default::default()).await?;

    if pod_list.items.is_empty() {
         println!("No pods found in the default namespace.");
    } else {
        for p in pod_list.items {
            let pod_name = p.metadata.name.as_deref().unwrap_or("");
            let phase = p.status.and_then(|s| s.phase).unwrap_or_else(|| "Unknown".to_string());
            println!(" - Pod: {}, Status: {}", pod_name, phase);
        }
    }

    Ok(())
}

Key points:

  • use k8s_openapi::api::core::v1::Pod;: Imports the struct representing a Pod.

  • Api::::default_namespaced(client): Creates an API handle specifically for Pod objects
    within the client’s default namespace (as configured in your kubeconfig). UseApi::namespaced(client, “my-namespace”)for specific namespaces orApi::all(client)for cluster-scoped resources.

  • pods.list(&Default::default()).await?: Lists the resources.&Default::default()provides default listing parameters (no filters).

  • The result is anObjectListwhich contains a vectoritemsofPodstructs.

  • We access pod metadata (likename) and status (likephase). Note the use of.as_deref().unwrap_or(…)and.and_then(…).unwrap_or_else(…)for safe
    handling of optional fields.

Run cargo run. It should list the pods running in your default namespace (if any).

7. Basic Operations (Conceptual)

kube-rs provides methods on the Api handle for common CRUD (Create, Read, Update,
Delete) operations.

7.1 Getting a Specific Resource

// Assuming 'pods' is Api for the correct namespace
let pod_name = "my-specific-pod";
match pods.get(pod_name).await {
    Ok(pod) => println!("Found pod: {:?}", pod.spec),
    Err(e) => eprintln!("Error getting pod {}: {}", pod_name, e),
}

7.2 Creating Resources

You typically define the resource using structs from k8s-openapi and then use
api.create().

// Conceptual - Requires more setup with PodSpec, metadata etc.
use k8s_openapi::api::core::v1::PodSpec;
let new_pod: Pod = Pod {
    metadata: ObjectMeta { name: Some("my-new-rust-pod".to_string()), ..Default::default() },
    spec: Some(PodSpec {
        containers: vec![Container {
            name: "nginx".to_string(),
            image: Some("nginx:alpine".to_string()),
            ..Default::default()
        }],
        ..Default::default()
    }),
    ..Default::default()
};
let pp = PostParams::default();
match pods.create(&pp, &new_pod).await {
    Ok(created_pod) => println!("Created pod: {}", created_pod.metadata.name.unwrap()),
    Err(e) => eprintln!("Error creating pod: {}", e),
}

7.3 Updating Resources

Usually involves getting the resource, modifying its spec, and using api.replace() or
api.patch().

7.4 Deleting Resources

// Assuming 'pods' is Api for the correct namespace
let pod_to_delete = "my-new-rust-pod";
let dp = DeleteParams::default();
match pods.delete(pod_to_delete, &dp).await {
    Ok(_) => println!("Pod {} deleted (or deletion started)", pod_to_delete),
    Err(e) => eprintln!("Error deleting pod {}: {}", pod_to_delete, e),
}

8. Error Handling

Most kube-rs API methods return kube::Result (which is an alias for
Result). You should handle these results appropriately using match,
?, or libraries like anyhow.

kube::Error provides detailed information about API errors, including HTTP status codes and
Kubernetes API error responses.

9. Conclusion

kube-rs provides a type-safe, asynchronous, and idiomatic way to interact with the Kubernetes
API from Rust applications. By leveraging the Client for connection and the generic
Api<T> handle for specific resource types defined in k8s-openapi, you can
build powerful controllers, operators, CLIs, and other tools that manage Kubernetes resources reliably.

This guide covered the essentials of setting up a client and listing resources. Exploring creating, updating,
deleting, and watching resources are the next logical steps in building more sophisticated Kubernetes
integrations with Rust.

  • Getting Started with Kubernetes

  • Getting Started with Minikube

  • Getting Started with Rust

  • Writing Concurrent Applications in Rust

  • Error Handling in Rust

  • Docker Commands Guide

  • Docker Compose Guide

  • Infrastructure as Code Explained

  • Common Rust Crates for Web Development

External Resources

  • Kube Documentation