Kubernetes templates made easy.
#keep-it-simple #no-server-component
Features:
- Template flavor of your choice
- $ (
$VAR
/${VAR}
); - go-template (go-template enriched with sprig);
- template-kind (
kind: Template
).
- $ (
- Support for *.env (
<VAR>=<VAL>
) and YAML / JSON config files. - Fail-fast defaults (all variables must be given a value (unless explicitly marked optional)).
- ConfigMap/Secret freezing for easier and less error-prone ConfigMap/Secret rollouts
(something to considerifwhen you hit kubernetes/kubernetes#22368). - ConfigMap/Secret "data-from-file" injection when
kubectl create configmap ... --from-file=... --from-file=... --from-file=... ...
feels like too much typing. image:tag
->image@digest
pinning with the help of dockry
(e.g.kubetpl render -s IMAGE=$(dockry digest --fq user/image:master) ...
to force redeployment of the new build published under the same tag).
curl -sSL https://github.com/shyiko/kubetpl/releases/download/0.9.0/kubetpl-0.9.0-$(
bash -c '[[ $OSTYPE == darwin* ]] && echo darwin || echo linux'
)-amd64 -o kubetpl && chmod a+x kubetpl && sudo mv kubetpl /usr/local/bin/
Verify PGP signature (optional but recommended):
curl -sSL https://github.com/shyiko/kubetpl/releases/download/0.9.0/kubetpl-0.9.0-$(
bash -c '[[ $OSTYPE == darwin* ]] && echo darwin || echo linux'
)-amd64.asc -o kubetpl.asc
curl -sS https://keybase.io/shyiko/pgp_keys.asc | gpg --import
gpg --verify kubetpl.asc /usr/local/bin/kubetpl
macOS:
gpg
can be installed withbrew install gnupg
Download executable from the Releases page.
# create template
echo $'
# kubetpl:syntax:$
apiVersion: v1
kind: Pod
metadata:
name: $NAME-pod
spec:
containers:
- name: $NAME-container
image: $IMAGE
env:
- name: ENV_KEY
value: $ENV_KEY
' > template.yml
# create config file (.env, .yml/.yaml or .json) (optional)
# (you'll probably have a different config file for each cluster/namespace/etc)
echo $'
NAME=sample-app
ENV_KEY=value
' > staging.env
# you might not need a config file if there are only a handful of variables (like in this case)
# -s/--set key=value might be enough
# render template
kubetpl render template.yml -i staging.env -s IMAGE=nginx
# to apply, pipe "render"ed output through kubectl
kubetpl render template.yml -i staging.env -s IMAGE=nginx |
kubectl apply -f -
# you can also apply remote template(s)
kubetpl render https://rawgit.com/shyiko/kubetpl/master/example/nginx.sh.yml \
-s NAME=kubetpl-example-nginx -s MESSAGE="hello $(whoami)" |
kubectl apply -f -
(for more examples see Template flavors)
# bash
source <(kubetpl completion bash)
# zsh
source <(kubetpl completion zsh)
When kubetpl render --freeze ...
is used, kubetpl rewrites ConfigMap
/Secret
's name to include hash of the content
and then updates all the references (in Pod
s / DaemonSet
s / Deployment
s / Job
s / ReplicaSet
s / ReplicationController
s / StatefulSet
s / CronJob
s) with a new value.
For example, executing kubetpl render --freeze example/nginx-with-data-from-file.yml -s NAME=app -s MESSAGE=msg
should produce example/nginx-with-data-from-file.rendered+frozen.yml.
NOTE: this feature can be used regardless of the Template flavor choice (or lack thereof (i.e. on its own)).
[email protected]+ also supports
kubetpl/data-from-env-file
.
Optionally, ConfigMap/Secret|s can be extended with kubetpl/data-from-file
to load "data" from a list of files (relative to a template unless a different -c/--chroot
is specified), e.g.
kind: ConfigMap
kubetpl/data-from-file:
- file
- path/to/another-file
- custom-key=yet-another-file
data:
key: value
...
Upon kubetpl render
the content of file
, another-file
and yet-another-file
(using custom-key
as a key)
will be added to the object's "data" (kubetpl/data-from-file
is automatically striped away).
For example, executing kubetpl render --allow-fs-access example/nginx-with-data-from-file.yml -s NAME=app
should produce example/nginx-with-data-from-file.rendered.yml.
NOTE #1: for security reasons, kubetpl/data-form-file
is not allowed to read files unless --allow-fs-access
or -c/--chroot=<root dir>
is specified (see kubetpl render --help
for more).
NOTE #2: this feature can be used regardless of the Template flavor choice (or lack thereof (i.e. on its own)).
Template syntax is determined by first checking template for # kubetpl:syntax:<$|go-template|template-kind>
comment
and then, if not found, --syntax=<$|go-template|template-kind>
command line option. In the absence of both,
kubetpl assumes that template is a regular resource definition file.
A type of template where all instances of
Use
$$
when you need a literal dollar sign ($$v
is interpreted as$v
string and not'$' + <value_of_v>
).
Let's say we have the following (click to expand):
<project_dir>/k8s/staging.env
NAME=sample-app
REPLICAS=1
<project_dir>/k8s/template.yml
# kubetpl:syntax:$
apiVersion: v1
kind: Service
metadata:
name: $NAME-service
spec:
selector:
app: $NAME
ports:
- protocol: TCP
port: 80
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: $NAME-deployment
spec:
replicas: $REPLICAS
template:
metadata:
labels:
app: $NAME
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
kubetpl render k8s/template.yml -i k8s/staging.env -s REPLICAS=3
should then yield
(click to expand)
apiVersion: v1
kind: Service
metadata:
name: sample-app-service
spec:
selector:
app: sample-app
ports:
- protocol: TCP
port: 80
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: sample-app-deployment
spec:
replicas: 3
template:
metadata:
labels:
app: sample-app
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
[email protected]+ default values can be specified via # kubetpl:set:KEY=VALUE
directive(s), e.g.
# kubetpl:syntax:$
# kubetpl:set:NAME=nginx
# kubetpl:set:REPLICAS=1
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: $NAME
annotations:
version: $VERSION
spec:
replicas: $REPLICAS
...
All functions provided by sprig are available
(with the exception ofenv
andexpandenv
).
A good overview of go-template|s can be found here. You might also want to check official documentation.
Some of the most commonly used expressions:
{{ .VAR }}
- get the value ofVAR
;{{ if isset "VAR" }} ... {{ end }}
- render content between}}
and{{
only if .VAR is set;{{ get "VAR" "default" }}
- get the value ofVAR
, return"default"
if not set (e.g.{{ get "REPLICAS" 1 }}
);{{ .VAR | quote }}
- quote the value of VAR;{{ .VAR | indent 4 }}
- indent value of VAR with 4 spaces;{{ .VAR | b64enc }}
- base64-encode value of VAR.
Let's say we have the following (click to expand):
<project_dir>/k8s/staging.env
NAME=sample-app
REPLICAS=1
<project_dir>/k8s/template.yml
# kubetpl:syntax:go-template
apiVersion: v1
kind: Service
metadata:
name: {{ .NAME }}-service
spec:
selector:
app: {{ .NAME }}
ports:
- protocol: TCP
port: 80
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: {{ .NAME }}-deployment
spec:
replicas: {{ .REPLICAS }}
template:
metadata:
labels:
app: {{ .NAME }}
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
kubetpl render k8s/template.yml -i k8s/staging.env -s REPLICAS=3
should then yield
(click to expand)
apiVersion: v1
kind: Service
metadata:
name: sample-app-service
spec:
selector:
app: sample-app
ports:
- protocol: TCP
port: 80
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: sample-app-deployment
spec:
replicas: 3
template:
metadata:
labels:
app: sample-app
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
aka
kind: Template
.
As described in Templates + Parameterization proposal.
Let's say we have the following (click to expand):
<project_dir>/k8s/staging.env
NAME=sample-app
<project_dir>/k8s/template.yml
# kubetpl:syntax:template-kind
kind: Template
apiVersion: v1
metadata:
name: nginx-template
annotations:
description: nginx template
objects:
- apiVersion: v1
kind: Service
metadata:
name: $(NAME)-service
spec:
selector:
app: $(NAME)
ports:
- protocol: TCP
port: 80
- apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: $(NAME)-deployment
spec:
replicas: $((REPLICAS))
template:
metadata:
labels:
app: $(NAME)
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
parameters:
- name: NAME
description: Application name
required: true
parameterType: string
- name: REPLICAS
description: Number of replicas
value: 1
required: true
parameterType: int
kubetpl render k8s/template.yml -i k8s/staging.env -s REPLICAS=3
should then yield
(click to expand)
apiVersion: v1
kind: Service
metadata:
name: sample-app-service
spec:
selector:
app: sample-app
ports:
- protocol: TCP
port: 80
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: sample-app-deployment
spec:
replicas: 3
template:
metadata:
labels:
app: sample-app
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
PREREQUISITE: go1.9+.
git clone https://github.com/shyiko/kubetpl $GOPATH/src/github.com/shyiko/kubetpl
cd $GOPATH/src/github.com/shyiko/kubetpl
make fetch
go run kubetpl.go
All code, unless specified otherwise, is licensed under the MIT license.
Copyright (c) 2018 Stanley Shyiko.