Skip to content
kix /docs
Install the CLI

Tutorial 04

First cluster from scratch

Create a minimal Kix cluster file, expose it through the flake, and deploy it locally.

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-ops/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 {
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.buildCluster builds one named 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. 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                     
 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:80

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.