Skip to content
Install the CLI

Tutorial 04

First cluster from scratch

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.

❱ git clone https://github.com/kix-run/kix-examples.git
❱ cd kix-examples
  • Keep the kix-demo kind cluster running, or recreate it with:
kix-examples/
❱ kind create cluster --config kind-config.yaml

Create a new tutorial directory:

kix-examples/
❱ mkdir -p tutorial-04

Create tutorial-04/cluster.nix:

tutorial-04/cluster.nix
{ kix, packages }:
kix.buildCluster {
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.buildCluster builds one cluster.
  • kix.flavors.kind says the target is a local kind cluster.
  • namespaces.tutorial-04 = { }; tells Kix to manage one namespace.
  • instances.tutorial-04.hello-world installs one package instance in that namespace.

The new thing is that you wrote the file yourself.

Open flake.nix and add one line inside the clusters = { ... }; block:

flake.nix
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. Kix also records it as the cluster’s name, because the file sets no name of its own. 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:

kix-examples/
❱ 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.

List the clusters:

kix-examples/
❱ kix list clusters
 NAME                                
 02-hello-world                      
 04-from-scratch                     
 06-service-dep                      
 08-namespace-deps                   
 09-typed-options                    
 10-reuse-packages                   
 19-scorecards                       
 homelab-kind                        
 homelab-kind-db-resize              
 homelab-kind-env-stamped            
 homelab-kind-env-stamped-dev-change 
 homelab-kind-gateway                
 homelab-kind-gateway-migrate        
 homelab-kind-ns-rename              
 homelab-kind-pg17                   
 homelab-kind-pvc-resize             
 homelab-kind-storage-migrate        
 homelab-kind-tls                    
 homelab-kind-tls-migrate            
 homelab-kind-upgrade-broad          
 homelab-kind-upgrade-small          
 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-monitoring-loki      
 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.nix and tutorial-04/cluster.nix.

Deploy the cluster:

kix-examples/ live capture
❱ kix deploy 04-from-scratch -y
Show outputHide output · 38 lines
Building cluster '04-from-scratch'...
Cluster 04-from-scratch: 10 manifests
Connecting to cluster...
No previous activation on cluster. First deploy.

  _cluster
    ~ cluster-level resources (4 added)
  kube-system
    + platform-dns (0 resources)
  tutorial-04
    + hello-world 1.27 (3 resources)

  Plan: cluster-level changes, 2 added
  Resources: 4 real content, 0 dep-affected
plan: 10 nodes
  + Namespace/tutorial-04 created
  ✔ Namespace/tutorial-04 ready
  ~ CustomResourceDefinition/activations.kix.run configured
  + ConfigMap/hello-world@tutorial-04 created
  ✔ ConfigMap/hello-world@tutorial-04 ready
  + Deployment/hello-world@tutorial-04 created
  ✔ CustomResourceDefinition/activations.kix.run ready
  ~ Namespace/kube-system configured
  ✔ Namespace/kube-system ready
  ~ CustomResourceDefinition/packageinstances.kix.run configured
  ✔ CustomResourceDefinition/packageinstances.kix.run ready
  ~ PackageInstance/platform-dns@kube-system configured
  ✔ PackageInstance/platform-dns@kube-system ready
  ✔ 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-ll6g0k5f2kqm configured
  ✔ Activation/04-from-scratch-ll6g0k5f2kqm ready
  • activation '04-from-scratch-ll6g0k5f2kqm' → Active

Deploy complete: 5 created, 5 configured, 0 unchanged, 0 failed

Ask Kubernetes what changed:

❱ kubectl get pods -n tutorial-04
NAME                          READY   STATUS    RESTARTS   AGE
hello-world-5dfdf5bdd-qlxhx   1/1     Running   0          9s
❱ kubectl get svc -n tutorial-04
NAME          TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
hello-world   ClusterIP   10.96.41.135   <none>        80/TCP    7s

You should see one Pod and one Service for the hello-world instance.

Port-forward to the package instance:

kix-examples/
❱ kix pf 04-from-scratch hello-world 8080:8080

Leave that running. In another terminal:

❱ curl http://localhost:8080/
Hello from my first Kix cluster!

Stop the port-forward with Ctrl-C.

Change the message in tutorial-04/cluster.nix:

tutorial-04/cluster.nix
config = {
message = "Kix rebuilt this from my cluster definition.";
};

Deploy again:

kix-examples/ live capture
❱ kix deploy 04-from-scratch -y
Show outputHide output · 25 lines
Building cluster '04-from-scratch'...
Cluster 04-from-scratch: 10 manifests
Connecting to cluster...
Active activation: 04-from-scratch-ll6g0k5f2kqm (ll6g0k5f...)

  tutorial-04
    ~ hello-world 1.27 (1 changed, 3 dep-affected)

  Plan: 1 updated, 1 unchanged
  Resources: 1 real content, 3 dep-affected
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-6w9czkc51502 configured
  ✔ Activation/04-from-scratch-6w9czkc51502 ready
  • activation '04-from-scratch-ll6g0k5f2kqm' → Superseded
  • activation '04-from-scratch-6w9czkc51502' → Active

Deploy complete: 0 created, 5 configured, 5 unchanged, 0 failed

Port-forward and curl again. The response should use your new message.

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.