Skip to content

Parameterizing

Deploying using Tanka worked well, but it did not really improve the situation in terms of maintainability and readability.

To do so, the following sections will explore some ways Jsonnet provides us with.

Functions parameters

Defining our deployment in a single block is not the best solution. Luckily with Jsonnet we can split our configuration into smaller, self-contained chunks.

Let’s start by creating a new function in main.jsonnet responsible for creating a Grafana deployment:

envirnoments/default/main.jsonnet
local grafana() = {
deployment: {
apiVersion: 'apps/v1',
kind: 'Deployment',
metadata: {
name: 'grafana',
},
spec: {
selector: {
matchLabels: {
name: 'grafana',
},
},
template: {
metadata: {
labels: {
name: 'grafana',
},
},
spec: {
containers: [
{
image: 'grafana/grafana',
name: 'grafana',
ports: [{
containerPort: 3000,
name: 'ui',
}],
},
],
},
},
},
},
service: {
apiVersion: 'v1',
kind: 'Service',
metadata: {
labels: {
name: 'grafana',
},
name: 'grafana',
},
spec: {
ports: [{
name: 'grafana-ui',
port: 3000,
targetPort: 3000,
}],
selector: {
name: 'grafana',
},
type: 'NodePort',
},
},
};

and let’s use it in our main configuration:

environments/default/main.jsonnet
local grafana() = {
# ...
};
{
grafana: {
# ...
},
grafana: grafana(),
prometheus: #...
};

We can then replace hardcoded values by adding parameters to our function:

environments/default/main.jsonnet
local grafana() = {
local grafana(name, port) = {
deployment: {
apiVersion: 'apps/v1',
kind: 'Deployment',
metadata: {
name: 'grafana',
name: name,
},
spec: {
selector: {
matchLabels: {
name: 'grafana',
name: name,
},
},
template: {
metadata: {
labels: {
name: 'grafana',
name: name,
},
},
spec: {
containers: [
{
image: 'grafana/grafana',
name: 'grafana',
name: name,
ports: [{
containerPort: 3000,
containerPort: port,
name: 'ui',
}],
},
],
},
},
},
},
service: {
apiVersion: 'v1',
kind: 'Service',
metadata: {
labels: {
name: 'grafana',
name: name,
},
name: 'grafana',
name: name,
},
spec: {
ports: [{
name: 'grafana-ui',
port: 3000,
targetPort: 3000,
name: '%s-ui' % name, // printf-style formatting
port: port,
targetPort: port,
}],
selector: {
name: 'grafana',
name: name,
},
type: 'NodePort',
},
},
};

and update the usage accordingly:

environments/default/main.jsonnet
local grafana(name, port) = {
# ...
};
{
grafana: grafana(),
grafana: grafana('grafana', 3000),
prometheus: #...
};

Now we do not only have a single place to change tunables, but also won’t suffer from mismatching labels and selectors anymore, as they are defined in a single place and all changed at once.