- Jsonnet overview
- Advantage of data templating over string templating
- Simple example
- Superset of JSON
- Reuse of data across config files
- Merge data fragments into nested fields
- Transform data output
- Std lib
Superset of JSON designed for describing cloud resources
✅ Data is smart, text is dumb
✅ Reuse curated "data models"
✅ More machine readable / writable than YAML (because it's data not text)
✅ Excellent at merging or overriding deeply nested data structures
✅ Create "native" functions easily in Go
✅ JVM bindings (integrate with your build easily)
🛑 Can be a hard sell to colleagues
🛑 It has Json in the name
🛑 Looks a bit like the spawn of JSON & Python
🛑 Ugh... It's Icky
- Plain old, duplicated, hand cranked YAML
- Kustomize
- Helm charts
Command
jsonnet -S output-formats-string.jsonnet
Input
local devData = import "dev-data.json";
std.format("just a string with a value embedded %s",devData.buildPrefix)
Output
just a string with a value embedded snapshot
Command
jsonnet -S output-formats-properties.jsonnet
Input
local devData = import "dev-data.json";
local properties = [
std.format("app.projectName=%s", devData.projectName),
std.format("app.commitSha=%s", devData.commitSha),
std.format("app.minorVersion=%s", devData.minorVersion),
std.format("app.patchVersion=%s", devData.patchVersion),
std.format("app.buildPrefix=%s", devData.buildPrefix)
];
std.lines(properties)
Output
app.projectName=spring-microservice
app.commitSha=f6b4cd
app.minorVersion=3
app.patchVersion=2
app.buildPrefix=snapsho
Lets get a bit fancy and DRY up our Java properties file format output using reflection and list comprehension
Command
jsonnet -S output-formats-properties-list-comprehension-and-reflection.jsonnet
Input
local devData = import "dev-data.json";
local properties = std.mapWithKey(function(k,v) std.format("app.%s=%s", [k, v]), devData);
std.lines(
std.map(
function(jsonKey) properties[jsonKey],
std.objectFields(properties)))
Output
app.projectName=spring-microservice
app.commitSha=f6b4cd
app.minorVersion=3
app.patchVersion=2
app.buildPrefix=snapsho
Command
jsonnet -S output-formats-yaml.jsonnet
Input
local devData = import "dev-data.json";
local myData = devData + {
buildMeta: {
versions: [1,2,3]
}
};
std.manifestYamlDoc(myData)
Output
"buildMeta":
"versions":
- 1
- 2
- 3
"buildPrefix": "snapshot"
"commitSha": "f6b4cd"
"minorVersion": 3
"patchVersion": 2
"projectName": "spring-microservice"
🤷♂️ It's valid YAML but the quotes are annoying! I prefer to use JSON to render the JSON and use yq
to convert to YAML
Let's say we want all teams to provide a build-meta.json
with every release
Each project implements this fragment
local common = import "build-meta.jsonnet.TEMPLATE";
local devData = import "dev-data.json";
local myConfig = common.newAppMetadata(
projectName = devData.projectName,
commitSha = devData.commitSha,
minorVersion = devData.minorVersion,
patchVersion = devData.patchVersion,
buildPrefix = devData.buildPrefix
);
myConfig
Which renders the template build-meta.jsonnet.TEMPLATE by calling it's constructor with the desired values to populate the template
This command will render the template
jsonnet build-meta-myapp.jsonnet
And render the JSON output
{
"projectName": "spring-microservice",
"appMeta": {
"buildInfo": {
"commitSha": "f6b4cd",
"prefix": "SNAPSHOT",
"releaseNumber": "SNAPSHOT-f6b4cd"
},
"versionInfo": {
"humanized": "1.3.2-SNAPSHOT-f6b4cd",
"major": 1,
"minor": 3,
"patch": 2
},
"artifacts": [
"spring-microservice-1.3.2-SNAPSHOT-f6b4cd.src.jar",
"spring-microservice-1.3.2-SNAPSHOT-f6b4cd.javadoc.jar",
"spring-microservice-1.3.2-SNAPSHOT-f6b4cd.bin.jar",
"spring-microservice-1.3.2-SNAPSHOT-f6b4cd.tar.gz"
]
}
}
Jsonnet Bundler allows curated Jsonnet libs to be installed from Github using a jsonnetfile.json.
Install the k8s dependency with command jb install
We will use a Jsonnet library (.libsonnet extension) that provides helpers for building a simple k8s manifest: service-deployment.libsonnet
The Jsonnet file for generating the manifest looks like this
local devData = import "dev-data.json";
local serviceDeployment = import "vendor/service-deployment/service-deployment.libsonnet";
serviceDeployment + {
serviceName:: devData.projectName,
dockerImage:: devData.projectName + ":" + devData.commitSha,
serviceConf:: {
envVarName:: "SPRING_APPLICATION_JSON",
spring: {
application: {
name: devData.projectName
}
}
},
}
To render the kubernetes manifest
jsonnet -J vendor k8s-manifest.jsonnet | yq --prettyPrint r -
the output should be
apiVersion: v1
items:
- kind: Service
metadata:
name: spring-microservice
spec:
selector:
serviceName: spring-microservice
- kind: Deployment
metadata:
name: spring-microservice
spec:
replicas: 1
template:
metadata:
labels:
name: spring-microservice
spec:
containers:
- env:
name: SPRING_APPLICATION_JSON
value: |-
{
"spring": {
"application": {
"name": "spring-microservice"
}
}
}
image: spring-microservice:f6b4cd
name: default
resources:
requests:
cpu: 500m
memory: 250Mi
kind: List