Skip to content

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.

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

Create a new tutorial directory:

Run in 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:

Run in 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:

Run in 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-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.nix and tutorial-04/cluster.nix.

Deploy the cluster:

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

Port-forward to the package instance:

Run in 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:

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

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.