Skip to content

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:

Terminal window
# <outputDir> <environment>
tk export promtail/ environments/promtail

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

Filenames

Tanka by default uses the following pattern:

Terminal window
${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:

Terminal window
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

Terminal window
... --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:

Terminal window
# 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:

Terminal window
# 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:

Terminal window
# 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:

Terminal window
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