- Rust 1.85+ (stable). MSRV is 1.85 due to
edition = "2024"andcargoresolver-3. - A reachable Kubernetes cluster (kind, k3s, Docker Desktop, real cluster).
kubectlconfigured against it.
inferenced-operator/
├── Cargo.toml
├── Dockerfile # multi-stage, distroless
├── README.md
├── LICENSE
├── crds/ # raw CRD YAML (generated; checked in)
│ ├── inferencehost.yaml
│ └── inferencemodel.yaml
├── examples/
│ ├── host-amelia.yaml
│ └── model-qwen-3b.yaml
├── charts/inferenced-operator/ # Helm chart that installs everything
│ ├── Chart.yaml
│ ├── values.yaml
│ ├── crds/ # copied from ../../crds at chart-package time
│ └── templates/
│ ├── _helpers.tpl
│ ├── deployment.yaml
│ ├── rbac.yaml
│ └── serviceaccount.yaml
├── docs/
│ ├── architecture.md
│ ├── installation.md
│ ├── crds.md
│ ├── development.md # ← you are here
│ └── troubleshooting.md
└── src/
├── main.rs # entry, --print-crds, controller wiring
├── crds.rs # CRD types, derive(CustomResource)
├── error.rs # operator-wide Error
├── bridge_client.rs # HTTP client to the inferenced daemon
└── reconcile/
├── mod.rs # Context shared by both controllers
├── host.rs # InferenceHost reconciler
└── model.rs # InferenceModel reconciler
The fastest dev loop is to run the operator out-of-cluster against your
current kubectl context:
cargo run
# In another shell:
kubectl apply -f crds/
kubectl create namespace inferenced
kubectl apply -f examples/host-amelia.yaml
kubectl apply -f examples/model-qwen-3b.yaml
kubectl get im qwen-3b -wThe operator picks up KUBECONFIG (or ~/.kube/config) like any other
client. No image build required.
RUST_LOG=inferenced_operator=debug,kube=info cargo run for verbose
reconcile output.
Whenever you change src/crds.rs:
cargo run -- --print-crds > crds/_all.yaml
# Then split _all.yaml at the `---` separator into the two per-kind files.
# The Helm chart auto-picks up files in charts/inferenced-operator/crds/.
cp crds/inferencehost.yaml crds/inferencemodel.yaml charts/inferenced-operator/crds/docker buildx build \
--platform linux/amd64,linux/arm64 \
-t ghcr.io/dormlab/inferenced-operator:dev \
--push .The Dockerfile uses the distroless/cc-debian12:nonroot base, ~25 MB
final image.
cargo testAdd new unit tests beside the code under mod tests. Integration tests
that need a real cluster live in tests/ (none yet).
error::Erroris the only error type crossing reconcile boundaries. Map every external error into anError::*variant orError::Other(String).- No global mutable state. All shared state lives on
reconcile::Context. - Reconcilers must be idempotent. Use
kube::api::Patch::Applywithforce(true)server-side-apply, neverReplace. - Owner references. Every secondary resource the operator creates
gets an
OwnerReferenceto its parent CRD so deletion cascades cleanly. #[serde(rename_all = "camelCase")]on every CRD struct for K8s-conventional field names.
Pull requests welcome. For larger changes, open an issue first to discuss direction. By contributing you agree to license your work under the project's MIT license.
A handful of targeted small wins:
- Add
kube::runtime::leader_electionso >1 replica is safe. - Add Prometheus metrics (the dependency is already in
Cargo.toml). - Add an admission webhook for spec validation.
- Add structured
Eventemission on reconcile errors. - Watch
InferenceHostfrom the model reconciler for instant placement on host changes.