Technical architectural analysis, practical configuration manifests, and deployment instructions for Jsonnet : Templating Large Kubernetes.
Installation
jsonnet(c build or go build)jsonnet bundlerโ package manager
brew install jsonnet jsonnet-bundler
Set up
# initiate the package manager
jb init
# >> this will create jsonnetfile.json in your repository
# install k8s jsonnet lib
jb install github.com/jsonnet-libs/k8s-libsonnet/1.32@main
# after that you can use `jb install` to install all libs from jsonnetfile.json
your jsonnetfile.json should look like this
{
"version": 1,
"dependencies": [
{
"source": {
"git": {
"remote": "https://github.com/jsonnet-libs/k8s-libsonnet.git",
"subdir": "1.32" #kubernetes version (lib version)
}
},
"version": "main"
}
],
"legacyImports": true
}
and you will also have a new folder named vendor .
run it
you can use jsonnet to generate json output from jsonnet file
create hello.jsonnet file
// hello.jsonnet
{
hello: "jsonnet" // << jsonnet key doesn't have double quote ""
}
the run jsonnet hello.jsonnet , you will get
{
"hello": "jsonnet"
}
next, we will try using k8s jsonnet lib.
Get Supakorn Warodomโs stories in your inbox
Join Medium for free to get updates from this writer.
create deploy.jsonnet file
local k = import "github.com/jsonnet-libs/k8s-libsonnet/1.32/main.libsonnet";
k.apps.v1.deployment.new("hello-deployment", replicas=1, containers=[], podLabels={})
to generate the json output, you will have to use this command
jsonnet -J vendor deploy.jsonnet
# jsonnet -J <LibDirectory> <file>
# result
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "hello-deployment"
},
"spec": {
"replicas": 1,
"selector": {
"matchLabels": {
"name": "hello-deployment"
}
},
"template": {
"metadata": {
"labels": {
"name": "hello-deployment"
}
},
"spec": {
"containers": [ ]
}
}
}
}
Merge syntax
basic
use + to merge jsonnetโs object.
letโs use โ+โ to add labels.app: โhelloโ to metadata, spec.selector.matchLabels and spec.template.metadata
// deploy-merge.jsonnet
local k = import "github.com/jsonnet-libs/k8s-libsonnet/1.32/main.libsonnet";
k.apps.v1.deployment.new("hello-deployment", replicas=1, containers=[], podLabels={})
+{metadata: {
name: "hello-deployment",
labels: {app: "hello"}}}
+{spec: {
selector: {matchLabels: {app: "hello"}},
template: {metadata: {labels: {app: "hello"}}},
}}
the result will look like this
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app": "hello"
},
"name": "hello-deployment"
},
"spec": {
"selector": {
"matchLabels": {
"app": "hello"
}
},
"template": {
"metadata": {
"labels": {
"app": "hello"
}
}
}
}
}
look carefully and you will see that spec.replicas and spec.template.spec is gone.
This is where you will need to use nested merge operator.
nested merge
the operator is +: .
// deploy-merge-nested.jsonnet
local k = import "github.com/jsonnet-libs/k8s-libsonnet/1.32/main.libsonnet";
k.apps.v1.deployment.new("hello-deployment", replicas=1, containers=[], podLabels={})
+{metadata+: {
// don't need to put `name: "hello-deployment"` here anymore
labels+: {app: "hello"}}}
+{spec+: {
selector+: {matchLabels+: {app: "hello"}},
template+: {metadata+: {labels+: {app: "hello"}}},
}}
result
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app": "hello"
},
"name": "hello-deployment"
},
"spec": {
"replicas": 1,
"selector": {
"matchLabels": {
"app": "hello",
"name": "hello-deployment"
}
},
"template": {
"metadata": {
"labels": {
"app": "hello",
"name": "hello-deployment"
}
},
"spec": {
"containers": [ ]
}
}
}
}
You can also do the same thing using the k8s library. (I think) most k8s library functions are implemented with the nested merge operator.
Press Enter or click the image to view full screen.

So we can rewrite it like this
local k = import "github.com/jsonnet-libs/k8s-libsonnet/1.32/main.libsonnet";
k.apps.v1.deployment.new("hello-deployment", replicas=1, containers=[], podLabels={})
+k.apps.v1.deployment.metadata.withNamespace("api")
+k.apps.v1.deployment.metadata.withLabels({app:"hello"})
+k.apps.v1.deployment.spec.selector.withMatchLabels({app:"hello"})
+k.apps.v1.deployment.spec.template.metadata.withLabels({app:"hello"})




Leave a Reply