Blog Deployed With Jsonnet, Grafana Tanka and ArgoCD


It’s been a year since I did the ‘Hello World’ with Jsonnet and Tanka, then I made a simple side-loader container to install Tanka as a plugin to ArgoCD and finally deployed an httpbin container with ArgoCD + Tanka + Jsonnet. However since Jsonnet wasn’t used in my work, those things were shelved afterwards.

Recently I got a new gig where Jsonnet was heavily used for infrastructure as code and configuration as code purposes. So I think it’s a no-brainer to practise Jsonnet again, with my blog as the playground.

The Jsonnet Migration

Here are some tips on how to translate existing YAML/Kustomize manifests to Jsonnet/Tanka combo. To prepare a project for Jsonnet, try tk init in an empty directory like I did in my ‘Hello World’ experiment.

First of all, and the best of all, Jsonnet is a super set of JSON. This means if I put a raw JSON in a Jsonnet file, it should just work. So if I wasn’t sure how to handle a certain type of resource, I’ll just keep it as it is in JSON, eg.

{
  namespace: 
  	{
      "apiVersion": "v1",
      "kind": "Namespace",
      ...
    }
}

If it’s a large JSON block, it can even be imported via import function. By this way I can hide some ugly raw JSON such as SealedSecrets away.

{
	sealed_secret: import 'sealed-secrets.json'
  	...
}

ConfigMap was managed by kustomize and it’s relatively straightforward to use importstr function to import them.

(import 'k.libsonnet') + {
    local cm = $.core.v1.configMap,
  
  	nginx_configmap:
  		cm.new('nginx-config', { 'nginx.conf': importstr 'conf/nginx.conf'}),
	...
}	

To use the super k8s-libsonnet library, The document is quite handy. For instance, according to the namespace object, I can immediately translate the above JSON for a namespace into Jsonnet.

(import 'k.libsonnet') + {
  	local namespace = $.core.v1.namespace,
  
	namespace: namespace.new('wordpress') +
	namespace.mixin.metadata.withLabels({ "istio.io/rev": 'beta' }),
  	...
}

Surprisingly almost all the time a service has same labels, eg. app=wordpress for selectors as the deploy which the service linked to. This is easily done using references started with a $, which is the root element.

(import 'k.libsonnet') + {
	local deploy = $.apps.v1.deployment,
    local svc = $.core.v1.service,
...
	deploy: { ... },
	service:
        svc.new($.deploy.metadata.name, $.deploy.spec.selector.matchLabels, [
            { name: 'http-wp', port: 8080, targetPort: 8080 }
        ]),

So line by line here’s my Jsonnet powered manifest for my blog, you can compare it with the original kustomize version, too. The Jsonnet version is rather plain and without a lot abstractions for now.

🙂