k8s-operator
A highly-available Kubernetes operator framework using Raft consensus.
Overview
k8s-operator is a Rust library for building Kubernetes operators that run as highly-available clusters. It uses Raft consensus via openraft to ensure only one replica performs reconciliation at a time, with automatic leader election and failover.
Features
- High Availability: Run multiple operator replicas with automatic leader election
- Raft Consensus: Built on openraft for distributed consensus
- Kubernetes Native: Uses kube-rs for Kubernetes API interactions
- Headless Service Discovery: Automatic peer discovery via Kubernetes DNS
- Controller Runtime: Finalizers, event recording, and status management
Installation
[]
= "0.1"
Crate Structure
| Crate | Description |
|---|---|
k8s-operator |
Unified API re-exporting all subcrates |
k8s-operator-core |
Core traits and types (Reconciler, ReconcileResult, etc.) |
k8s-operator-raft |
Raft configuration and peer discovery |
k8s-operator-storage |
Storage layer (memory-backed via openraft-memstore) |
k8s-operator-controller |
Controller components (finalizers, events, status, leader guard) |
k8s-operator-derive |
Procedural macros for CRD definitions |
Quick Start
use *;
use CustomResource;
use JsonSchema;
use ;
use Arc;
;
Leader Election
Only the leader replica performs reconciliation:
use ;
let election = new;
let guard = election.guard;
// Set role based on Raft state
election.set_role;
// Check if this node is the leader
if guard.is_leader
// Or use the guard to gate operations
guard.check?; // Returns Err(ReconcileError::NotLeader) if not leader
Peer Discovery
Discover peers via Kubernetes headless service DNS:
use HeadlessServiceDiscovery;
let discovery = new;
// Get DNS name for the service
let dns = discovery.dns_name;
// => "my-operator-headless.default.svc.cluster.local"
// Discover peers by StatefulSet ordinal
let peers = discovery.discover_by_ordinal;
// => HashMap with nodes 0, 1, 2
Finalizers
Manage Kubernetes finalizers for cleanup:
use ;
use Client;
const FINALIZER: &str = "example.com/cleanup";
// Add finalizer before creating resources
add_finalizer.await?;
// Check if finalizer exists
if has_finalizer
Status Updates
Update resource status with conditions:
use ;
new
.set
.set
.condition
.apply
.await?;
Event Recording
Record Kubernetes events:
use EventRecorder;
let recorder = new;
recorder.normal.await?;
recorder.warning.await?;
Kubernetes Deployment
Deploy as a StatefulSet with a headless service for peer discovery:
apiVersion: v1
kind: Service
metadata:
name: my-operator-headless
spec:
clusterIP: None
selector:
app: my-operator
ports:
- port: 5000
name: raft
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: my-operator
spec:
serviceName: my-operator-headless
replicas: 3
selector:
matchLabels:
app: my-operator
template:
metadata:
labels:
app: my-operator
spec:
containers:
- name: operator
image: my-operator:latest
ports:
- containerPort: 5000
name: raft
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.