TankaFlexible, reusable and concise configuration for Kubernetes
Edit page
IntroductionInstallation
Tutorial
Writing Jsonnet
Syntax overviewSyntaxAbstractionStandard libraryConditionalsReferencesmain.jsonnetNative Functions
Libraries
Command-line completionDirectory structureDiff strategiesOutput filteringFrequently asked questionsKnown issues

Language overview

Jsonnet is the data templating language Tanka uses for expressing what shall be deployed to your Kubernetes cluster. Understanding Jsonnet is crucial to using Tanka effectively.

This page covers the Jsonnet language itself. For more information on how to use Jsonnet with Kubernetes, see the tutorial. There's also the official Jsonnet tutorial that provides a more detailed review of language features.

Syntax

Being a superset of JSON, the syntax is very similar:

// Line comment
/* Block comment */

// a local variable (not exported)
local greeting = "hello world!";

// the exported/returned object
{
  foo: "bar", // string
  bar: 5, // int
  baz: false, // bool
  list: [1,2,3], // array
  // object
  dict: {
    nested: greeting, // using the local
  }
  hidden:: "incognito!" // an unexported field
}

Abstraction

Jsonnet has rich abstraction features, which makes it interesting for configuring Kubernetes, as it allows to keep configurations concise, yet readable.

  • Imports
  • Merging
  • Functions

Imports

Just as other languages, Jsonnet allows code to be imported from other files:

local secret = import "./secret.libsonnet";

The exported object (the only non-local one) of secret.libsonnet is now available as a local variable called secret.

When using Tanka, it is also possible to directly import .json and .yaml files, as if they were a .libsonnet.

Make sure to take also take a look on Libraries and Vendoring to learn how to use import to re-use code.

Merging

Deep merging allows you to change parts of an object without touching all of it. Consider the following example:

local secret = {
  kind: Secret,
  metadata: {
    name: "mySecret",
    namespace: "default", // need to change that
  },
  data: {
    foo: std.base64("foo")
  }
};

To change the namespace only, we can use the special merge key +:: like so:

// define the patch:
local patch = {
  metadata+:: {
    namespace: "myApp"
  }
}

The difference between : and +:: is that the former replaces the original data at that key, while the latter applies the new object as a patch on top, meaning that values will be updated if possible but all other stay like they are.
To merge those two, just add (+) the patch to the original:

secret + patch

The output of this is the following JSON object:

{
  "kind": "Secret",
  "metadata": {
    "name": "mySecret",
    "namespace": "myApp"
  },
  "data": {
    "foo": "Zm9vCg=="
  }
}

Functions

Jsonnet supports functions, similar to how Python does. They can be defined in two different ways:

local add(x,y) = x + y;
local mul = (function(x, y) x * y);

Objects can have methods:

{
  greet(who): "hello " + who,
}

Default values, keyword-args and more examples can be found at jsonnet.org.

Standard library

The Jsonnet standard library includes many helper methods ranging from object and array mutation, over string utils to computation helpers.

Documentation is available at jsonnet.org.

Conditionals

Jsonnet supports a conditionals in a fashion similar to a ternary operator:

local tag = if prod then "v1.0" else "latest";

More on jsonnet.org.

References

Jsonnet has multiple options to refer to parts of an object:

{ // this is $
  junk: "foo",
  nested: { // this is self
    app: "Tanka",
    msg: self.app + " rocks!" // "Tanka rocks!"
  },
  children: { // this is also self
    baz: "bar",
    junk: $.junk + self.baz, // "foobar"
  }
}

For more information take a look at jsonnet.org