Templating Kubernetes Resource Files

Templating Kubernetes Resource Files

When deploying web applications, or any other type of application, it is often needed or at least very useful to have different versions (or stages) of it deployed. Those usually are Dev, Staging, Production and so on. However, it becomes quite a pain to manage different versions of each of your Kubernetes resource files.

Enter kubetpl, a templating engine purpose built for Kubernetes resource files. It works across all major OSes and is super easy to install and use. Here are some of its features:

Let's go through the initial setup and example usage below.

First, you will need to download kubetpl and add it to your $PATH. To download on macOS or Linux you can use the following command, and on Windows you can get the executable here.

$ curl -o kubetpl \
    -sSL https://github.com/shyiko/kubetpl/releases/download/0.7.1/kubetpl-0.7.1-$(
      bash -c '[[ $OSTYPE == darwin* ]] && echo darwin || echo linux'
    )-amd64
$ chmod a+x kubetpl

Once you're done with the steps above you can move kubetpl to a directory that's on your $PATH. One possible location is /usr/local/bin, here's how we can move the program there:

$ mv kubetpl /usr/local/bin/

On Linux you'll most likely need to use sudo to move the file

You should now be able to use kubetpl directly from anywhere.

Now, let's get to the main event, writing our templates and rendering them with kubetpl.

You will want to start by creating your template file(s), let's look at the example below. It defines a Deployment of one redis container, exposed to the cluster via a Service. We will be using the Bash style templating (note the # kubetpl:syntax:$ line at the beginning).

resources.yaml

# kubetpl:syntax:$
---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: $DEPLOYMENT_NAME
  namespace: $STAGE
spec:
  replicas: 1
  selector:
    matchLabels:
      app: $APP_LABEL
  template:
    spec:
      containers:
        - name: $CONTAINER_NAME
          image: redis:$DOCKER_TAG
          ports:
            containerPort: 6379
            protocol: TCP
            name: $PORT_NAME
    metadata:
      labels:
        app: $APP_LABEL

---
kind: Service
apiVersion: v1
metadata:
  name: $SERVICE_NAME
  namespace: $STAGE
spec:
  type: NodePort
  ports:
    - port: $SERVICE_PORT
      targetPort: 6379
      protocol: TCP
  selector: $APP_LABEL

As you can see we can use variables for any value inside the file. Now let's render this template. kubetpl provides the render command to, you guessed it, render a template, we can also pass values for our variables using the -s argument, let's try it:

$ kubetpl render resources.yaml \
    -s DEPLOYMENT_NAME="redis-deployment" \
    -s SERVICE_NAME="redis-service" \
    -s STAGE="staging" \
    -s APP_LABEL="app-redis" \
    -s CONTAINER_NAME="container-redis" \
    -s DOCKER_TAG="5.0-rc" \
    -s PORT_NAME="redis-port" \
    -s SERVICE_PORT=7777

This will output the rendered template to your console, you can use this to validate that your result makes sense. Now, as you can see it becomes quite tedious to enter all those values in the command line every time we have to render a template. A better option is to use the -i argument, which allows you to load a .env file containing your values. It can also be combined with -s for convenience, which allows you to set or override values.

Here's an example of .env file:

base.env

DEPLOYMENT_NAME="redis-deployment"
SERVICE_NAME="redis-service"
STAGE="staging"
APP_LABEL="app-redis"
CONTAINER_NAME="container-redis"
DOCKER_TAG="5.0-rc"
PORT_NAME="redis-port"
SERVICE_PORT=7777

With this we can simply run the command below to achieve the same result as earlier.

$ kubetpl render -i base.env resources.yaml

Or maybe we want to change the SERVICE_PORT and DOCKER_TAG.

$ kubetpl render -i base.env resources.yaml \
    -s SERVICE_PORT=8888 \
    -s DOCKER_TAG="4.0.11"

And then, once you are satisfied with your templates you can pipe the output tu kubectl to apply your changes directly on your cluster.

$ kubetpl render -i base.env resources.yaml | kubectl apply -f -

So that was the introduction to kubetpl basics. Here are some things you might want to try next:

You can find the full example of the above files on the blog's examples repo.