Jsonnet : Templating Large Kubernetes

๐Ÿ’ก Jsonnet : Templating Large Kubernetes โ€” Executive Summary

Technical architectural analysis, practical configuration manifests, and deployment instructions for Jsonnet : Templating Large Kubernetes.

Installation
  1. jsonnet (c build or go build)
  2. jsonnet bundler โ€” package manager
bash
brew install jsonnet jsonnet-bundler
Set up
bash
# 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

json
{
  "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

json
// hello.jsonnet
{
  hello: "jsonnet" // << jsonnet key doesn't have double quote ""
}

the run jsonnet hello.jsonnet , you will get

json
{
   "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

bash
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

bash
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

bash
// 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

json
{
   "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 +: .

bash
// 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

json
{
   "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

bash
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"})

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *