Render Docker Compose / Stack files with the power of go templates with dockerize and sprig useful template functions.
Docker Compose / Stack files are very static in nature as you only can use YAML to define them.
Yes, there are several nice tricks to make YAML feels more dynamic like anchors or block merging but in the end, you can't add conditionals, neither iterations, scoped blocks...
This is where kompoze
comes to the rescue!
Download the latest version in your container:
The 41north/kompoze
image is a base image based on alpine linux
. kompoze
is installed in the $PATH
and can be used directly.
FROM 41north/kompoze
...
ENTRYPOINT kompoze ...
RUN apt-get update && apt-get install -y wget
ENV KOMPOZE_VERSION v1.0.0
RUN wget https://github.com/41North/kompoze/releases/download/$KOMPOZE_VERSION/kompoze-linux-amd64--KOMPOZE_VERSION.tar.gz \
&& tar -C /usr/local/bin -xzvf kompoze-linux-amd64-$KOMPOZE_VERSION.tar.gz \
&& rm kompoze-linux-amd64-$KOMPOZE_VERSION.tar.gz
RUN apk add --no-cache openssl
ENV KOMPOZE_VERSION v1.0.0
RUN wget https://github.com/41North/kompoze/releases/download/$KOMPOZE_VERSION/kompoze-alpine-linux-amd64-KOMPOZE_VERSION.tar.gz \
&& tar -C /usr/local/bin -xzvf kompoze-alpine-linux-amd64-$KOMPOZE_VERSION.tar.gz \
&& rm kompoze-alpine-linux-amd64-$KOMPOZE_VERSION.tar.gz
kompoze
relies upon a definition.toml
file (read definition section for more information) that specifies how to render the templates.
By default, if you don't pass anything to kompoze
, it will search for a definition.toml
file in current directory. So:
$ kompoze
is equivalent to:
$ kompoze definition.toml
You can specify multiple definition files by passing their paths directly:
$ kompoze definition.toml another-definition.toml /another/path/definition2.toml
You can tail multiple files to STDOUT
and STDERR
by passing the options multiple times:
$ kompoze -stdout definition.toml
If your file uses {{
and }}
as part of it's syntax, you can change the template escape characters using the -delims
option:
$ kompoze -delims "<%:%>"
By default, the base-path
for rendering will be the one in which you run kompoze
(so any relative paths that are specified inside the definition file can be resolved). You can change it with the following option:
$ kompoze --base-path /another/path
The definition file uses TOML format and tries to be very minimal and concise. It's comprised of two main sections:
- Global vars: Those common variables that will be applied to every template (if any).
- Templates: Where it defines which templates to render and which variables are overridden from the global scope.
Take a look at the example below:
# Example definition file
# defines global variables that will be applied to each template definition (can be null)
[vars]
# you can define the variables directly here (higher priority when merging same entries)
[vars.global]
network_enabled = true
network_name = "net"
network_subnet = "172.25.0.0/16"
# or you can include other global variables files (lower priority when merging same entries)
include = ["vars/global.toml"]
# defines a list of templates to render
[[templates]]
src = "templates/stack.yml.tpl"
dest = "out/stack-1.yml"
include_vars = ["vars/local.toml"]
[templates.local_vars]
mariadb_version = "10.2.21"
mariadb_volume_enabled = true
[[templates]]
src = "templates/stack.yml.tpl"
dest = "out/stack-2.yml"
[templates.local_vars]
mariadb_version = "11"
mariadb_volume_enabled = false
As you can see above the syntax is pretty straightforward. You can define relative paths for src
and dest
and they will be resolved to the defined base-path
option.
The format for including external variables are as follows:
[vars]
this_is_another_var = 'var'
The different sources of variables are merged together in the following order:
- global
vars
- global
include
- template
include_vars
- template
vars
Templates are rendered using Golang's text/template package with the mix of two powerful additions:
You can access environment variables within a template with .Env
like dockerize
or those defined in the definition file with plain .
(like .some_global_var
).
{{ .Env.PATH }} is my path
The set of borrowed functions from dockerize are the following:
exists $path
- Determines if a file path exists or not.{{ exists "/etc/default/myapp" }}
parseUrl $url
- Parses a URL into it's protocol, scheme, host, etc. parts. Alias forurl.Parse
isTrue $value
- Parses a string $value to a boolean value.{{ if isTrue .Env.ENABLED }}
isFalse $value
- Parses a string $value to a boolean value.{{ if isFalse .Env.ENABLED }}
loop
- Create for loops.
On the sprig side, everything is included by default, so you have access to all sprig functions.
Contributions to this project are very welcome and will be fully credited.
Feel free to send a PR to correct any possible bug or improvement you may want to add.
Just make sure you follow these rules:
- Create feature branches: It's important to be concise with your commits, so don't ask us to pull from your master branch.
- Document any change in behaviour: Make sure the
README.md
is kept up-to-date. - One pull request per feature: If you want to do more than one thing, send multiple pull requests.
- Send coherent history: Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting.
Many thanks to:
Both of them for creating dockerize and python-docker-compose-templer respectively, from which this project draws 99% of its inspiration!
kompoze is released under the MIT License. See LICENSE.md for more information.