Config Templates
Config templates are a way to define reusable abstractions for actions or workflows. This provides a powerful yet easy-to-use mechanism to tailor Garden's functionality to your needs, improve governance, reduce boilerplate, and provide higher-level abstractions to application developers.
How do they work? You can create customized templates for actions and workflows, and render them using kind: RenderTemplate
resources. These templates allow you to define your own schemas and abstractions, which are then translated at runtime to one or more resources.
Config templates can be defined within a project, or in a separate repository that can be shared across multiple projects (using remote sources).
This feature has been updated in 0.13
to support actions and workflows, in addition to modules. The ModuleTemplate
resource kind has been renamed to ConfigTemplate
, and instead of templated
Modules, there is now a specific RenderTemplate
kind to render the templates. The older declarations will still work until version 0.14
, and are converted at runtime.
How it works
We'll use the templated-k8s-container example
to illustrate how templates work. This example has a k8s-container
template, that generates one Build
action of type container
for building an image, and one Deploy
action of type kubernetes
for deploying that image. A template like this is useful to customize the Kubernetes manifests for your services, but of course it's just one simple example of what you could do.
The template is defined like this:
And it's used like this:
First off, notice that we have a kind: ConfigTemplate
, which defines the template, and then a kind: RenderTemplate
which references and uses the ConfigTemplate
via the template
field. You can have any number of instances referencing the same template.
The sections below describe the example in more detail.
Defining actions and workflows
Each template can include one or more actions (Build
, Deploy
, Test
or Run
) or workflows (kind: Workflow
) under the configs
key. The schema for each action or workflow is exactly the same as for normal actions or workflows with just a couple of differences:
In addition to any other template strings available when defining modules, you additionally have
${parent.name}
,${template.name}
and${inputs.*}
(more on inputs in the next section). It's important that you use one of these for the names of the actions, so that every generated action has a unique name..You can set a
path
field on each config to any subdirectory relative to the directory where theRenderTemplate
config is placed.
Defining and referencing inputs
It's possible to define a schema to validate inputs given to a ConfigTemplate
. If no schema is defined any inputs are allowed.
On the ConfigTemplate
, the inputsSchemaPath
field points to a standard JSON Schema file, which describes the schema for the inputs
field on every action and module that references the template. In our example, it looks like this:
This schema says that the containerPort
and servicePort
inputs are required, and that you can optionally set a replicas
value as well. Any JSON Schema with "type": "object"
is supported, and users can add any parameters that templated actions and modules should specify. These could be ingress hostnames, paths, or really any flags that need to be customizable per action or module.
These values can then be referenced using ${inputs.*}
template strings, anywhere under the configs
and modules
fields.
Note that special care needs to be taken when using template strings in the inputs
field in a RenderTemplate
config. Fields in the resulting configs from the template may need to be resolvable at different times, and using e.g. action references in input values may not work in all cases.
Escaping template strings
Sometimes you may want to pass template strings through when generating files, instead of having Garden resolve them. This could for example be handy when templating a Terraform configuration file which uses a similar templating syntax.
To do this, simply add an additional $
in front of the template string, e.g. $${var.dont-resolve-me}
.
Action references within a templated action
In many cases, it's important for the different actions in a single template to depend on one another, and to reference outputs from one another. You do this basically the same way as in normal actions, but because action names in a template are generally templated themselves, it's helpful to look at how to use templates in action references.
Here's a section from the manifests in our example:
Notice the image
field above. We use bracket notation to template the action name, whose outputs we want to reference: ${actions.build["${parent.name}"].outputs.deployment-image-id}
. Here we're using that to get the built image ID of the ${parent.name}
Build in the same template.
Note that for a reference like this to work, that action also needs to be specified as a dependency.
Sharing templates
If you have multiple projects it can be useful to have a central repository containing action and module templates, that can then be used in all your projects.
To do that, simply place your ConfigTemplate
configs in a repository (called something like garden-templates
) and reference it as a remote source in your projects:
Garden will then scan that repo when starting up, and you can reference the templates from it across your project.
Defining modules
Modules are deprecated and this feature will be removed in version 0.14
.
Each template can include one or more modules under the modules
key. The schema for each module is exactly the same as for normal Modules with just a couple of differences:
In addition to any other template strings available when defining modules, you additionally have
${parent.name}
,${template.name}
and${inputs.*}
(more on inputs in the next section). It's important that you use one of these for the names of the modules, so that every generated module has a unique name..You can set a
path
field on the module to any subdirectory relative to the templated module directory. The module directory will be created if necessary.
Generating files
You can specify files that should be generated as modules are resolved, using the modules[].generateFiles
field. These files can include any of the same template strings as when defining modules.
Note: It's usually advisable to add the generated files to your .gitignore
, since they'll be dynamically generated.
In our example, we render a set of Kubernetes manifests. Here's the relevant section in the template:
This reads a source file from template/manifests.yml
(the sourcePath
is relative to the location of the template), and writes it to module/.manifests.yml
(targetPath
is relative to the templated module).
Instead of specifying sourcePath
, you can also specify value
to provide the file contents directly as a string.
Module references within a templated module
In many cases, it's important for the different modules in a single template to depend on one another, and to reference outputs from one another. You do this basically the same way as in normal modules, but because module names in a template are generally templated themselves, it's helpful to look at how to use templates in module references.
Here's a section from the manifests file in our example:
Notice the image
field above. We use bracket notation to template the module name, whose outputs we want to reference: ${modules["${parent.name}-image"].outputs.deployment-image-id}
. Here we're using that to get the built image ID of the ${parent.name}-image
module in the same template.
Note that for a reference like this to work, that module also needs to be specified as a build dependency.
Further reading
Next steps
Take a look at our Guides section for more of an in-depth discussion on Garden concepts and capabilities.
Last updated