Writing templates and overlays
This document will use the example CloudFormation YAML template provided here, but you can use your own if you prefer. In this guide we will create one test overlay and one prod overlay.
Step 1: Folder structure
Start your project by defining a base template. First create a folder in your project for templates and overlays:
cd [your project]
mkdir crustomize
mkdir crustomize/base
mkdir -p crustomize/overlays/test
Step 2: Overlays
Place the CloudFormation template in crustomize/base/template-name.yml.
The name doesn’t matter, all YAML files in base/ will be read and
merged into one master base template.
Create a crustomize.yml file in the crustomize/overlays/test folder
with this content:
base: ../../base
Verify it works by running crustomize apply crustomize/overlays/test. The
command should output the template itself.
Next, add an overlay in crustomize/overlays/test/ECSTaskExecutionRole.yml
Here, we will just add a Description property:
Resources:
ECSTaskExecutionRole:
Type: AWS::IAM::Role
Properties:
Description: This is a test execution role
Note that the Resources: property is crucial for crustomize to merge
the overlay.
Add the overlay to crustomize.yml like this:
base: ../../base
overlays:
- ECSTaskExecutionRole.yml
Verify by running crustomize apply crustomize/overlays/test. The outputted
template should contain the added Description property.
Create a prod overlay by creating a crustomize/overlays/prod folder.
Copy the test/crustomize.yml file to that folder along with the
ECSTaskExecutionRole.yml overlay.
Modify the crustomize/overlays/prod/ECSTaskExecutionRole.yml like this:
Resources:
ECSTaskExecutionRole:
Type: AWS::IAM::Role
Properties:
Description: This is a prod execution role
Verify by running crustomize apply crustomize/overlays/prod. There should
now be a different description.
Overlay array merging strategies
When merging overlays, arrays are simply merged, i.e. items from both
arrays are included in the resulting template. However, sometimes you
may want to replace an entire array instead of merging it. To do this,
you can specify an arrayMerge strategy in the overlay definition,
like this:
base: ../../
overlays:
- file: ECSTaskExecutionRole.yml
arrayMerge: replace
For more complex merging strategies, use JSON patch as described below.
Step 3: JSON Patch
Sometimes overlays are not enough, particularly when you need to target
a specific item in an array. In these cases it may be necessary to use
a JSON patch. JSON patch can target specific elements and perform the
operations you define. Here, we will target the ClusterSettings list
and set the name using JSON patch.
Modify test/crustomize.yml like this:
base: ../../
overlays:
- ECSTaskExecutionRole.yml
patches:
- op: replace
path: "/Resources/ECSCluster/Properties/ClusterSettings/0/Name"
value: containerInsightsTest
Run crustomize apply crustomize/overlays/test to verify the cluster
name has been changed to containerInsightsTest.
Repeat the same for the prod overlay and verify your changes.
For more information, consult Javascript Object Notation
Patch
IETF specifications.
Step 4: Template rendering
You can use either EJS or Handlebars as a template rendering engine. Handlebars offers a more strict method of rendering by limiting what sort of in-process commands can be used. EJS is more flexible in that regard. In this example we’ll use Handlebars.
Modify the ECSCluster section in the base template so it looks like this:
ECSCluster:
Type: AWS::ECS::Cluster
Properties:
{{#if values.Description}}
Description: {{values.Description}}
{{/if}}
ClusterSettings:
- Name: containerInsightsTest
Value: enabled
Add a Description value in test/crustomize.yml like this:
base: ../../
overlays:
- ECSTaskExecutionRole.yml
patches:
- op: replace
path: "/Resources/ECSCluster/Properties/ClusterSettings/0/Name"
value: containerInsightsTest
values:
Description: Test cluster
Verify and repeat the process for prod/crustomize.yml but with a different
Description.
You can also add templating instructions in overlays. Modify
test/crustomize.yml and add a Stage value property:
base: ../../
overlays:
- ECSTaskExecutionRole.yml
patches:
- op: replace
path: "/Resources/ECSCluster/Properties/ClusterSettings/0/Name"
value: containerInsightsTest
values:
Description: Test cluster
Stage: test
Modify the test/ECSTaskExecutionRole.yml like this:
Resources:
ECSTaskExecutionRole:
Type: AWS::IAM::Role
Properties:
Description: This is a {{values.Stage}} execution role
When you run crustomize apply crustomize/overlays/test the ``
directive will be replaced with the value defined in the relevant
crustomize.yml file. Now, repeat for overlays/prod/.
In addition to values.Property you can use the helpers documented in
doc/helpers.md, environment variables and, if available
in crustomize.yml any property under stack, accessed like this:
. For example, to access the CloudFormation stack
name, you would type:.
Environment variables are accessed using env.NAME_OF_VARIABLE.
You can also defined common variables in an env.yml file and reference
it using the -e flag. These will also be accessible using the env.NAME
method.
If you have used or created Helm charts, you should be familiar with many
of the helper functions. If you find you need a specific helper, you can
create your own helper functions and expose them to crustomize using the
CRUSTOMIZE_HELPERS environment variable.
A custom helpers is just a Javascript function that returns a helper function, like this:
// Params:
// wd: String: This is the folder of the current overlay/crustomize.yml
// i.e. /path/to/overlay folder
// profile: AWS_PROFILE, default is 'default'
// run: function that runs a shell process
export function cat({ wd, profile, run }) {
return function (filename) {
const cat = run.bind("cat")
return cat([filename])
}
}
One possible use case is to bind run to the aws CLI in order to perform
lookup operations against resources in AWS.