05. Basic graph and deploy loop
This content is for the v0.1 version. Switch to the latest version for up-to-date documentation.
The last tutorial created a cluster from scratch. This tutorial uses that same cluster to look more closely at the Kix loop:
- check the cluster before deploying;
- inspect what Kix will build;
- preview changes against the live cluster;
- deploy the checked result;
- inspect the package and resource graph.
The goal is not to learn every graph detail yet. The goal is to see that Kix can evaluate a cluster before it touches Kubernetes.
Prerequisites
Section titled “Prerequisites”- Finish the first cluster from scratch tutorial.
- Keep the
04-from-scratchcluster entry inflake.nix. - Make sure the new cluster file is known to Git. New files in a Git flake are invisible to Nix until they are added to the index:
❱ git ls-files --error-unmatch tutorial-04/cluster.nix If that command fails, add the file:
❱ git add tutorial-04/cluster.nix Check Before Deploy
Section titled “Check Before Deploy”Run the Kix checks first:
❱ kix check 04-from-scratch
TOOL RESULT DETAILS
eval pass 10 manifests evaluated
kubeconform pass skipped (this validation tool is not yet integrated with Kix)
pluto pass skipped (this validation tool is not yet integrated with Kix)
kyverno pass skipped (this validation tool is not yet integrated with Kix)
scorecard pass 0 errors, 2 warnings, 1 info This evaluates the cluster and runs validation before anything is applied to Kubernetes. For this tiny cluster, the output should be short. The important part is the habit: check the evaluated cluster before deploying it.
If Kix fails here, fix the cluster file before moving on. A failed check means the deploy step should not run yet.
Inspect The Rendered Result
Section titled “Inspect The Rendered Result”Now render the cluster:
❱ kix build 04-from-scratch Show output
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
kix.run/identity-hash: gvrlspcfgh9a2qnsx5kqxw9f4l3x52jj
kix.run/package: _cluster
kix.run/package-namespace: _cluster
labels:
app.kubernetes.io/managed-by: kix
name: activations.kix.run
spec:
group: kix.run
names:
kind: Activation
listKind: ActivationList
plural: activations
singular: activation
scope: Cluster
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
properties:
apiVersion:
type: string
kind:
type: string
metadata:
type: object
spec:
type: object
x-kubernetes-preserve-unknown-fields: true
status:
type: object
x-kubernetes-preserve-unknown-fields: true
type: object
served: true
storage: true
subresources:
status: {}
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
kix.run/identity-hash: pk4hih6jm4yj336rlaqk2qycz2k46xvs
kix.run/package: _cluster
kix.run/package-namespace: _cluster
labels:
app.kubernetes.io/managed-by: kix
name: packageinstances.kix.run
spec:
group: kix.run
names:
kind: PackageInstance
listKind: PackageInstanceList
plural: packageinstances
singular: packageinstance
scope: Namespaced
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
properties:
apiVersion:
type: string
kind:
type: string
metadata:
type: object
spec:
type: object
x-kubernetes-preserve-unknown-fields: true
status:
type: object
x-kubernetes-preserve-unknown-fields: true
type: object
served: true
storage: true
subresources:
status: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
kix.run/depends-on: h50qnfszgri8ml59sx8qy0sx3zbp79s9,qrh908pfdb2030zrxsp8018aiinicd2w
kix.run/identity-hash: g9737y2gwhk29xrfv4n17g1k0ga65ra7
kix.run/package: hello-world
kix.run/package-namespace: tutorial-04
labels:
app.kubernetes.io/instance: hello-world
app.kubernetes.io/managed-by: kix
app.kubernetes.io/name: hello-world
name: hello-world
namespace: tutorial-04
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/instance: hello-world
app.kubernetes.io/name: hello-world
template:
metadata:
labels:
app.kubernetes.io/instance: hello-world
app.kubernetes.io/name: hello-world
spec:
containers:
- image: nginxinc/nginx-unprivileged:1.27-alpine
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: 8080
periodSeconds: 10
name: nginx
ports:
- containerPort: 8080
name: http
protocol: TCP
readinessProbe:
failureThreshold: 1
httpGet:
path: /healthz
port: 8080
periodSeconds: 5
resources:
limits:
cpu: '100m'
memory: '64Mi'
requests:
cpu: '50m'
memory: '32Mi'
securityContext:
runAsNonRoot: true
volumeMounts:
- mountPath: /etc/nginx/conf.d
name: config
readOnly: true
volumes:
- configMap:
name: hello-world
name: config
---
apiVersion: kix.run/v1alpha1
kind: Activation
metadata:
annotations:
kix.run/built-via: /nix/store/s07zv01j1pqyp7xnlgc2q86zs4cvcddp-k8s-activation-04-from-scratch
kix.run/depends-on: jh345cnnffy1bnj4cz5x0hwq6ibxvkkr,qdhaxrymikrk9yw204k79giz69jc1n0q,requires:gvrlspcfgh9a2qnsx5kqxw9f4l3x52jj
kix.run/identity-hash: m924biqa0b9f2z8x05xh3fpiskngx59g
kix.run/package: _cluster
kix.run/package-namespace: _cluster
labels:
app.kubernetes.io/managed-by: kix
kix.run/cluster: '04-from-scratch'
name: '04-from-scratch-m924biqa0b9f'
spec:
instances:
kube-system:
platform-dns: platform-dns
tutorial-04:
hello-world: hello-world
---
apiVersion: kix.run/v1alpha1
kind: PackageInstance
metadata:
annotations:
kix.run/depends-on: sj0fv5bs2hnh9zcqdh62ph34l2wm0b1m,requires:pk4hih6jm4yj336rlaqk2qycz2k46xvs
kix.run/identity-hash: jh345cnnffy1bnj4cz5x0hwq6ibxvkkr
kix.run/import-apiversion: apps/v1
kix.run/import-fqdn: kube-dns.kube-system.svc.cluster.local
kix.run/import-kind: Deployment
kix.run/import-name: coredns
kix.run/mode: import
kix.run/package: _cluster
kix.run/package-namespace: _cluster
labels:
app.kubernetes.io/instance: platform-dns
app.kubernetes.io/managed-by: kix
name: platform-dns
namespace: kube-system
spec:
instanceName: platform-dns
mode: import
namespaceName: kube-system
---
apiVersion: kix.run/v1alpha1
kind: PackageInstance
metadata:
annotations:
kix.run/depends-on: hkdviynvj8w2207m1ppzymhrcrfh0gsq,qrh908pfdb2030zrxsp8018aiinicd2w,requires:pk4hih6jm4yj336rlaqk2qycz2k46xvs
kix.run/identity-hash: qdhaxrymikrk9yw204k79giz69jc1n0q
kix.run/package: _cluster
kix.run/package-namespace: _cluster
kix.run/root: hello-world
labels:
app.kubernetes.io/instance: hello-world
app.kubernetes.io/managed-by: kix
name: hello-world
namespace: tutorial-04
spec:
instanceName: hello-world
namespaceName: tutorial-04
version: '1.27'
---
apiVersion: v1
data:
default.conf: |
server {
listen 8080;
location / {
default_type text/plain;
return 200 'Hello from my first Kix cluster!\n';
}
location /healthz {
default_type text/plain;
return 200 'ok\n';
}
}
kind: ConfigMap
metadata:
annotations:
kix.run/depends-on: qrh908pfdb2030zrxsp8018aiinicd2w
kix.run/identity-hash: h50qnfszgri8ml59sx8qy0sx3zbp79s9
kix.run/package: hello-world
kix.run/package-namespace: tutorial-04
labels:
app.kubernetes.io/instance: hello-world
app.kubernetes.io/managed-by: kix
name: hello-world
namespace: tutorial-04
---
apiVersion: v1
kind: Namespace
metadata:
annotations:
kix.run/identity-hash: sj0fv5bs2hnh9zcqdh62ph34l2wm0b1m
kix.run/package: _cluster
kix.run/package-namespace: _cluster
labels:
app.kubernetes.io/managed-by: kix
kubernetes.io/metadata.name: kube-system
name: kube-system
---
apiVersion: v1
kind: Namespace
metadata:
annotations:
kix.run/identity-hash: qrh908pfdb2030zrxsp8018aiinicd2w
kix.run/package: _cluster
kix.run/package-namespace: _cluster
labels:
app.kubernetes.io/managed-by: kix
kubernetes.io/metadata.name: tutorial-04
name: tutorial-04
---
apiVersion: v1
kind: Service
metadata:
annotations:
kix.run/depends-on: g9737y2gwhk29xrfv4n17g1k0ga65ra7,qrh908pfdb2030zrxsp8018aiinicd2w
kix.run/identity-hash: hkdviynvj8w2207m1ppzymhrcrfh0gsq
kix.run/package: hello-world
kix.run/package-namespace: tutorial-04
labels:
app.kubernetes.io/instance: hello-world
app.kubernetes.io/managed-by: kix
name: hello-world
namespace: tutorial-04
spec:
ports:
- name: http
port: 80
protocol: TCP
targetPort: 8080
selector:
app.kubernetes.io/instance: hello-world
app.kubernetes.io/name: hello-world
type: ClusterIP This prints the Kubernetes resources Kix built from your cluster definition. You should see familiar objects such as a Namespace, Deployment, and Service.
For now, use kix build as a window into what Kix evaluated. In normal use,
you usually let kix deploy render and apply the checked result for you.
Preview Against The Cluster
Section titled “Preview Against The Cluster”Ask Kix what is different from the live cluster:
❱ kix diff 04-from-scratch Show output
⠁ Fetching live cluster state... Discovering API resources...
Fetching managed resources (60 resource types)...
Fetched 17 resources across 60 resource types
3 packages: 2 unchanged, 0 changed, 0 added, 1 removed
_cluster
~ cluster-level resources (1 removed)
- Namespace/tutorial-02
tutorial-02
- hello-world 1.27 (3 resources)
(exit code: 2) If your live cluster already matches the checked result, the diff should be empty or say there is nothing to change.
Now make a visible edit in tutorial-04/cluster.nix:
config = { message = "Preview this before deploy.";};Check that Git sees the edit:
❱ git status --short Because tutorial-04/cluster.nix is already tracked, Nix can see this dirty
edit. You do not need to commit it.
Run the diff again:
❱ kix diff 04-from-scratch Show output
⠁ Fetching live cluster state... Discovering API resources...
Fetching managed resources (60 resource types)...
Fetched 17 resources across 60 resource types
3 packages: 1 unchanged, 1 changed, 0 added, 1 removed
_cluster
~ cluster-level resources (1 removed)
- Namespace/tutorial-02
tutorial-02
- hello-world 1.27 (3 resources)
tutorial-04
~ hello-world 1.27 (1 changed, 3 dep-affected)
~ ConfigMap/hello-world@tutorial-04
~ $.data.default.conf:
--- old
+++ new
@@ -2,7 +2,7 @@
listen 80;
location / {
default_type text/plain;
- return 200 'Hello from my first Kix cluster!\n';
+ return 200 'Preview this before deploy.\n';
}
location /healthz {
default_type text/plain;
~ Deployment/hello-world@tutorial-04 (via dependency)
~ PackageInstance/hello-world@tutorial-04 (via dependency)
~ Service/hello-world@tutorial-04 (via dependency)
Activation: 04-from-scratch-m7cpzxzyff67 -> 04-from-scratch-qibygg9r95ww
(exit code: 2) This time Kix should show the change before it applies anything. That is the basic preview loop: edit locally, evaluate locally, inspect the change, then deploy.
Deploy The Checked Result
Section titled “Deploy The Checked Result”Deploy the change:
❱ 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 Kix evaluates the cluster, computes what needs to change, and applies the checked result to Kubernetes.
Check the resource status:
❱ kix status 04-from-scratch
NAME NAMESPACE KIND READY STATUS AGE
02-hello-world-ai8hpfnhamfs _cluster Activation True Active 8s
02-hello-world-rh3pdaspsdxk _cluster Activation True Active 13s
04-from-scratch-m7cpzxzyff67 _cluster Activation True Active 5s
04-from-scratch-qibygg9r95ww _cluster Activation True Active 1s
activations.kix.run _cluster CustomResourceDefinition True Active 35s
packageinstances.kix.run _cluster CustomResourceDefinition True Active 35s
kube-system _cluster Namespace True Active 41s
tutorial-02 _cluster Namespace True Active 35s
tutorial-04 _cluster Namespace True Active 7s
platform-dns kube-system PackageInstance True Active 33s
hello-world tutorial-02 ConfigMap True Active 35s
hello-world tutorial-02 Deployment True 1/1 35s
hello-world tutorial-02 PackageInstance True Active 13s
hello-world tutorial-02 Service True Active 13s
hello-world tutorial-04 ConfigMap True Active 7s
hello-world tutorial-04 Deployment True 1/1 7s
hello-world tutorial-04 PackageInstance True Active 5s
hello-world tutorial-04 Service True Active 5s Then port-forward and verify the response:
❱ kix pf 04-from-scratch hello-world 8080:80 In another terminal:
❱ curl http://localhost:8080/
Preview this before deploy. Stop the port-forward with Ctrl-C.
See The First Graph Shape
Section titled “See The First Graph Shape”Run:
❱ kix graph 04-from-scratch --format tree Show output
CustomResourceDefinition/activations.kix.run
└── Activation/04-from-scratch-m924biqa0b9f
CustomResourceDefinition/packageinstances.kix.run
├── PackageInstance/hello-world@tutorial-04
│ └── Activation/04-from-scratch-m924biqa0b9f
└── PackageInstance/platform-dns@kube-system (import)
└── Activation/04-from-scratch-m924biqa0b9f
Namespace/kube-system
└── PackageInstance/platform-dns@kube-system (import)
└── Activation/04-from-scratch-m924biqa0b9f
Namespace/tutorial-04
├── Service/hello-world@tutorial-04
│ └── PackageInstance/hello-world@tutorial-04
│ └── Activation/04-from-scratch-m924biqa0b9f
├── ConfigMap/hello-world@tutorial-04
│ └── Deployment/hello-world@tutorial-04
│ └── Service/hello-world@tutorial-04
│ └── PackageInstance/hello-world@tutorial-04
│ └── Activation/04-from-scratch-m924biqa0b9f
├── PackageInstance/hello-world@tutorial-04
│ └── Activation/04-from-scratch-m924biqa0b9f
└── Deployment/hello-world@tutorial-04
└── Service/hello-world@tutorial-04
└── PackageInstance/hello-world@tutorial-04
└── Activation/04-from-scratch-m924biqa0b9f
10 resources, 13 dependencies For this cluster the graph is still small. You may see Kix’s own activation
resources, the namespace, platform imports, and the hello-world package
resources. The useful habit is to read the graph as “what Kix knows about this
cluster,” not as raw YAML.
Do not worry about the deeper graph mechanics yet. Later tutorials add service dependencies, cross-namespace wiring, generated network policy, and scorecard rules. Each one gives the graph more useful information.
What You Learned
Section titled “What You Learned”You used the same local cluster definition through the main Kix loop:
kix checkcatches problems before deploy;kix buildshows the rendered Kubernetes resources;kix diffpreviews changes against the live cluster;kix deployapplies the evaluated result;kix statusandkix graphinspect what Kix knows afterward.
The next tutorial adds the first real relationship: one local package depends on another service.