That's my logoGrafana TankaFlexible, reusable and concise configuration for Kubernetes
Edit page
IntroductionInstallation
Tutorial
Writing Jsonnet
Libraries
Advanced features
Garbage collectionHelm supportKustomize supportOutput filteringExporting as YAMLFilenamesMultiple environmentsPerformance featuresInline environmentsServer-Side Apply
References
Frequently asked questionsKnown issues

Exporting as YAML

Tanka provides you with a day-to-day workflow for working with Kubernetes clusters:

  • tk show for quickly checking the YAML representation looks good
  • tk diff to ensure your changes will behave like they should
  • tk apply makes it happen

However sometimes it can be required to integrate with other tooling that does only support .yaml files.

For that case, tk export can be used:

#           <outputDir> <environment>
$ tk export promtail/   environments/promtail

Note: The arguments flipped in v0.14.0, the <outputDir> comes first now.

This will create a separate .yaml file for each Kubernetes resource included in your Jsonnet.

Filenames

Tanka by default uses the following pattern:

${apiVersion}.${kind}-${metadata.name}.yaml

# examples:
apps-v1.Deployment-distributor.yaml
v1.ConfigMap-loki.yaml
v1.Service-ingester.yaml

If that does not fit your need, you can provide your own pattern using the --format flag:

tk export promtail environments/promtail --format='{{.metadata.labels.app}}-{{.metadata.name}}-{{.kind}}'

The syntax is Go text/template. See https://pkg.go.dev/text/template for reference.

This would include the label named app, the name and kind of the resource:

loki-distributor-Deployment
loki-loki-ConfigMap
loki-ingester-Service

You can optionally use the template function lower for lower-casing fields, e.g. in the above example

... --format='{{.metadata.labels.app}}-{{.metadata.name}}-{{.kind | lower}}'

would yield

loki-distributor-deployment

etc.

You can also use a different file extension by providing --extension='yml', for example.

Multiple environments

Tanka can also export multiple inline environments, as showcased in Use case: consistent inline environments. This follows the same principles as describe before with the addition that you can also refer to Environment specific data through the env keyword.

For example an export might refer to data from the Environment spec:

# Format based on environment {{env.<...>}}
$ tk export exportDir environments/dev/ \
  --format '{{env.metadata.labels.cluster}}/{{env.spec.namespace}}//{{.kind}}-{{.metadata.name}}'

Even more advanced use cases allow you to export multiple environments in a single execution:

# Export multiple environments
$ tk export exportDir environments/dev/ environments/qa/
# Recursive export
$ tk export exportDir environments/ --recursive
# Recursive export with labelSelector
$ tk export exportDir environments/ -r -l team=infra

Performance features

When exporting a large amount of environments, jsonnet evaluation can become a bottleneck. To speed up the process, Tanka provides a few optional features.

Partial export (in a GitOps context)

Given multiple environments, one may want to only export the environments that were modified since the last export. This is enabled by passing both the --merge-strategy=replace-envs flags.

When these flags are passed, Tanka will:

  1. Delete the manifests that were previously exported by the environments that are being exported. This is done by looking at the manifest.json file that is generated by Tanka when exporting. The related entries are also removed from the manifest.json file.
  2. Generate the manifests for the targeted environments into the output directory.
  3. Add in the new manifests entries into the manifest.json file and re-export it.

Finding out which environments to export

Tanka provides the tk tool importers command to figure out which main.jsonnet need to be re-exported based on what files were modified in a workspace.

If, for example, the lib/my-lib/main.libsonnet file was modified, you could run the command like this to find which files to export:

# Find out which envs to re-export
$ tk tool importers lib/my-lib/main.libsonnet
my-repo-path/jsonnet/environments/my-env/main.jsonnet

# Re-export the envs
$ tk export myoutputdir my-repo-path/jsonnet/environments/my-env/main.jsonnet --merge-strategy=replace-envs

Note that deleted environments need special consideration when doing this. The tk tool importers utility only works with existing files so deleting an environment will result in stale manifest.json entries and moving an environment will result in manifest conflicts. In order to correctly handle deleted environments, they need to be passed to the export command:

$ tk export myoutputdir my-repo-path/jsonnet/environments/my-new-env-path/main.jsonnet --merge-strategy=replace-envs \
  --merge-deleted-envs my-repo-path/jsonnet/environments/my-old-env-path/main.jsonnet \
  --merge-deleted-envs my-repo-path/jsonnet/environments/other-deleted-env-path/main.jsonnet

Using a memory ballast

Read this blog post for more information about memory ballasts.

For large environments that load lots of data into memory on evaluation, a memory ballast can dramatically improve performance. This feature is exposed through the --mem-ballast-size-bytes flag on the export command.

Anecdotally (Grafana Labs), environments that took around a minute to load were able to load in around 45 secs with a ballast of 5GB (--mem-ballast-size-bytes=5368709120). Decreasing the ballast size resulted in negative impact on performance, and increasing it more did not result in any noticeable impact.

Caching

Tanka can also cache the results of the export. This is useful if you often export the same files and want to avoid recomputing them. The cache key is calculated from the main file and all of its transitive imports, so any change to any file possibly used in an environment will invalidate the cache.

This is configured by two flags:

  • --cache-path: The local filesystem path where the cache will be stored. The cache is a flat directory of json files (one per environment).
  • --cache-envs: If exporting multiple environments, this flag can be used to specify, with regexes, which environments to cache. If not specified, all environments are cached.

Notes:

  • Using the cache might be slower than evaluating jsonnet directy. It is only recommended for environments that are very CPU intensive to evaluate.
  • To use object storage, you can point the --cache-path to a FUSE mount, such as s3fs