04. First cluster from scratch
This content is for the v0.1 version. Switch to the latest version for up-to-date documentation.
In the previous tutorial you read the files that make an example cluster work. Now you will create one small cluster yourself.
You will add a new cluster to your kix-examples checkout, deploy one
echo-server instance to kind, and reach it through kix pf.
Prerequisites
Section titled “Prerequisites”- Work through the project files and flake entry point tutorial.
- Have the
kix-examplesrepo from tutorial 02. If you need a fresh copy, clone it from any parent directory:
❱ git clone https://github.com/kix-ops/kix-examples.git❱ cd kix-examples - Keep the
kix-demokind cluster running, or recreate it with:
❱ kind create cluster --config kind-config.yaml Add A New Cluster File
Section titled “Add A New Cluster File”Create a new tutorial directory:
❱ mkdir -p tutorial-04 Create tutorial-04/cluster.nix:
{ kix, packages }:
kix.buildCluster { name = "04-from-scratch";
modules = [ kix.flavors.kind
{ namespaces = { tutorial-04 = { }; };
instances.tutorial-04 = { hello-world = { package = packages.echo-server; config = { message = "Hello from my first Kix cluster!"; }; }; }; } ];}Most of this should look familiar from the previous tutorial:
{ kix, packages }:says this file receives the Kix helpers and package catalog.kix.buildClusterbuilds one named cluster.kix.flavors.kindsays the target is a local kind cluster.namespaces.tutorial-04 = { };tells Kix to manage one namespace.instances.tutorial-04.hello-worldinstalls one package instance in that namespace.
The new thing is that you wrote the file yourself.
Expose The Cluster In flake.nix
Section titled “Expose The Cluster In flake.nix”Open flake.nix and add one line inside the clusters = { ... }; block:
clusters = { # existing example entries... "04-from-scratch" = ./tutorial-04/cluster.nix;};The left side, "04-from-scratch", is the cluster name you will pass to the
CLI. The right side points at the file you just created.
Because kix-examples is a Git flake, Nix only sees files known to Git. Stage
the new file and the flake edit before running Kix:
❱ git add flake.nix tutorial-04/cluster.nix You do not need to commit. Staging is enough for Nix to include the new file in the flake source.
Check That Kix Can See It
Section titled “Check That Kix Can See It”List the clusters:
❱ kix list clusters
NAME
02-hello-world
04-from-scratch
06-service-dep
08-namespace-deps
09-typed-options
10-reuse-packages
19-scorecards
how-to-adoption
how-to-adoption-takeover
how-to-application
how-to-auto-instantiation
how-to-composition
how-to-fragments
how-to-helm-bridge
how-to-multi-env
how-to-package-cilium
how-to-package-monitoring
how-to-package-python
how-to-package-stackgres
how-to-package-storage
how-to-package-valkey
how-to-package-velero
how-to-package-victoria-metrics
how-to-platform-cloudflare-tunnel
how-to-platform-gateway
how-to-platform-hostpath
how-to-platform-ingress
how-to-platform-monitoring
how-to-platform-network-policy
how-to-platform-secrets
how-to-platform-sops
how-to-stateful-migration You should see 04-from-scratch in the list.
If you do not, check three things:
- you added the line inside the
clusters = { ... };block; - the file path is
./tutorial-04/cluster.nix; - you staged both
flake.nixandtutorial-04/cluster.nix.
Deploy It
Section titled “Deploy It”Deploy the cluster:
❱ kix deploy 04-from-scratch -y Show output
Building cluster '04-from-scratch'...
Cluster 04-from-scratch: 10 manifests
Connecting to cluster...
No previous activation on cluster — first deploy.
Reading live cluster state...
_cluster
~ cluster-level resources (1 added, 1 removed)
tutorial-02
- hello-world 1.27 (3 resources)
tutorial-04
+ hello-world 1.27 (3 resources)
Plan: cluster-level changes, 1 added, 1 removed, 1 unchanged
Resources: 2 real content, 0 dep-affected
5 orphaned (kept; pass --prune to delete)
- Service/hello-world@tutorial-02
- Namespace/tutorial-02
- ConfigMap/hello-world@tutorial-02
- Deployment/hello-world@tutorial-02
- PackageInstance/hello-world@tutorial-02
plan: 10 nodes
+ Namespace/tutorial-04 created
✔ Namespace/tutorial-04 ready
+ ConfigMap/hello-world@tutorial-04 created
✔ ConfigMap/hello-world@tutorial-04 ready
+ Deployment/hello-world@tutorial-04 created
✔ Deployment/hello-world@tutorial-04 ready
+ Service/hello-world@tutorial-04 created
✔ Service/hello-world@tutorial-04 ready
+ PackageInstance/hello-world@tutorial-04 created
✔ PackageInstance/hello-world@tutorial-04 ready
+ Activation/04-from-scratch-m7cpzxzyff67 created
✔ Activation/04-from-scratch-m7cpzxzyff67 ready
prune: 5 orphaned resources kept (warn-only; pass --prune to delete)
- PackageInstance/hello-world@tutorial-02
- Service/hello-world@tutorial-02
- Deployment/hello-world@tutorial-02
- ConfigMap/hello-world@tutorial-02
- Namespace/tutorial-02
• activation '04-from-scratch-m7cpzxzyff67' → Active
Deploy complete: 6 created, 0 configured, 4 unchanged, 0 failed Ask Kubernetes what changed:
❱ kubectl get pods -n tutorial-04
NAME READY STATUS RESTARTS AGE
hello-world-6f4588d4c5-458tf 1/1 Running 0 7s❱ kubectl get svc -n tutorial-04
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-world ClusterIP 10.96.209.101 <none> 80/TCP 5s You should see one Pod and one Service for the hello-world instance.
Reach The Service
Section titled “Reach The Service”Port-forward to the package instance:
❱ kix pf 04-from-scratch hello-world 8080:80 Leave that running. In another terminal:
❱ curl http://localhost:8080/
Hello from my first Kix cluster! Stop the port-forward with Ctrl-C.
Make One More Edit
Section titled “Make One More Edit”Change the message in tutorial-04/cluster.nix:
config = { message = "Kix rebuilt this from my cluster definition.";};Deploy again:
❱ kix deploy 04-from-scratch -y Show output
Building cluster '04-from-scratch'...
Cluster 04-from-scratch: 10 manifests
Connecting to cluster...
Active activation: 04-from-scratch-m7cpzxzyff67 (m7cpzxzy...)
Reading live cluster state...
_cluster
~ cluster-level resources (1 removed)
tutorial-02
- hello-world 1.27 (3 resources)
tutorial-04
~ hello-world 1.27 (1 changed, 3 dep-affected)
Plan: cluster-level changes, 1 updated, 1 removed, 1 unchanged
Resources: 2 real content, 3 dep-affected
5 orphaned (kept; pass --prune to delete)
- Service/hello-world@tutorial-02
- ConfigMap/hello-world@tutorial-02
- Deployment/hello-world@tutorial-02
- Namespace/tutorial-02
- PackageInstance/hello-world@tutorial-02
plan: 10 nodes
~ ConfigMap/hello-world@tutorial-04 configured
✔ ConfigMap/hello-world@tutorial-04 ready
~ Deployment/hello-world@tutorial-04 configured
✔ Deployment/hello-world@tutorial-04 ready
~ Service/hello-world@tutorial-04 configured
✔ Service/hello-world@tutorial-04 ready
~ PackageInstance/hello-world@tutorial-04 configured
✔ PackageInstance/hello-world@tutorial-04 ready
+ Activation/04-from-scratch-qibygg9r95ww created
✔ Activation/04-from-scratch-qibygg9r95ww ready
prune: 5 orphaned resources kept (warn-only; pass --prune to delete)
- PackageInstance/hello-world@tutorial-02
- Service/hello-world@tutorial-02
- Deployment/hello-world@tutorial-02
- ConfigMap/hello-world@tutorial-02
- Namespace/tutorial-02
• activation '04-from-scratch-m7cpzxzyff67' → Superseded
• activation '04-from-scratch-qibygg9r95ww' → Active
Deploy complete: 1 created, 4 configured, 5 unchanged, 0 failed Port-forward and curl again. The response should use your new message.
What You Learned
Section titled “What You Learned”You created the smallest useful Kix cluster from scratch:
- a cluster file that calls
kix.buildCluster; - a kind flavor;
- one managed namespace;
- one package instance;
- one flake entry that gives the cluster a CLI name.
The next tutorial slows down on the deploy loop. You will check, build, diff, and inspect this cluster before applying changes.