Generate your first blueprint
By the end of this tutorial you will have compiled the solver, run it against a small bundled cluster, and read the blueprint it produces. It takes about ten minutes, most of which is Rust compiling.
You do not need a Kubernetes cluster. Nothing here touches one.
Before you start
Section titled “Before you start”You need:
- Rust (stable) with
cargo make- A clone of the repository
git clone https://github.com/AlexanderSlokov/kuberina.gitcd kuberinaStep 1: Build the solver
Section titled “Step 1: Build the solver”make solver-buildThe first build downloads and compiles dependencies, so expect a few minutes. Subsequent builds are fast.
Step 2: Run it against the homelab dataset
Section titled “Step 2: Run it against the homelab dataset”The repository ships two datasets. Start with the small one — it solves almost instantly, which makes it a much better first read than the hyperscale benchmark.
make solver-homelabThat target expands to a direct invocation of the solver:
cd solver && cargo run --release -- plan \ --infra testdata/homelab_infra.yaml \ --workloads testdata/homelab_workloads.yamlTwo inputs go in:
--infra— the cluster topology: node capacity, taints, labels.--workloads— the pods to place, with their resource requirements.
The solver prints a stowage plan to the console and writes
solver/kuberina_solution.yaml.
Step 3: Read the blueprint
Section titled “Step 3: Read the blueprint”Open solver/kuberina_solution.yaml. This is the artifact the whole tool
exists to produce — a concrete placement for every pod, with the constraints
needed to pin it there.
This is the file you would review with your team, argue about, regenerate, and eventually apply. It is the point of the exercise. Do not skim past it.
Step 4: Try the hyperscale benchmark
Section titled “Step 4: Try the hyperscale benchmark”Now run the dataset the paper reports on — 186 nodes and 2,714 pods, named
irina after the container ship.
make solver-irinaThis is where the genetic algorithm earns its keep. The solver auto-scales its parameters by problem size: above 500 pods it switches to a population of 1,024 running up to 1,000 generations, and prints a line telling you so.
Datacenter-scale detected (2714 pods) — cranking GA to maximumExpect this to take meaningfully longer than the homelab run.
Applying the Pareto rule
Section titled “Applying the Pareto rule”Real clusters should not be packed to 100% of nominal capacity. The --pareto
flag scales node capacity by a percentage, leaving headroom:
make solver-irina-pareto-80This solves against 80% of each node’s capacity while still reporting the plan against true capacities.
Step 5: Inspect the result visually
Section titled “Step 5: Inspect the result visually”The Python tooling under research/ validates the solution independently and
renders a cluster heatmap.
make research-inspectThis writes kuberina_dashboard.html. Open it in a browser to explore
utilisation node by node.
Step 6: Run the whole pipeline
Section titled “Step 6: Run the whole pipeline”Once the individual pieces make sense, one target chains them together: generate test data, solve, inspect, and run the formal mathematical proof.
make research-full-pipelineThis target uses uv to manage the Python environment, so you need
uv installed for the research steps.
What you have now
Section titled “What you have now”You have compiled the optimiser, produced a blueprint for a small cluster and a hyperscale one, applied a capacity safety margin, and independently validated the result.
Where to go next
Section titled “Where to go next”- Running the solver — the same operations as a task-oriented reference rather than a walkthrough.
- CLI reference — every flag the solver accepts.
- Why offline scheduling — the reasoning behind planning placement in advance.