We build an universal deployment tool for Kubernetes that supports rendering and deployment of lightweight Jinja templated k8s manifests as well as complex Helm charts. We’ve added support for easy secret management based on Gopass, running tests in CI/CD pipelines, extending upstream Helm Charts with custom Jinja-templates manifests as well as patching upstream Helm Charts before deploying.


Installation

You can use pip to install adeploy from the Github mirror:

pip install git+https://github.com/awesome-it/adeploy.git
adeploy --version

Please check the help section of adeploy if you need more information:

adeploy --help
adeploy -p <provider> (render|test|deploy) --help

To use adeploy for your deployments, you need to keep the following directory structure in your deployment repository:

├── README.md
├── build/
├── chart/
├── defaults.yml
├── namespaces/<namespace>/<release>.yml
└── templates/
        
  • defaults.yml defines global variables and versions for all releases of your dpeloyment.
  • namespaces contains a subdirectory for each namespaces and a <release>.yml configuration for each release or instance.
  • templates or chart contains your Jinja templates k8s manifests or your Helm chart (if you want to use an offline version).

Variables

One of the most important features is the global deployment configuration file (i.e. defaults.yml) and a per-deployment or per-namespace configuration file in (i.e. namespaces/<namespace>/<release>.yml) that can be used to set parameters for all deployments and for each deployment release respectively.

One common use-case is the versions map. Let’s have a look at the following WordPress deployments. Let’s suppose you have a deployment for your live page (i.e. https://awesome-it.de) and another deployment for your testing page (i.e. https://beta.local.awesome-it.de). So you have a global configuration file:

defaults.yml:

versions:
  wordpress: 5.5.0-fpm
  nginx: 1.16.1

And your have additional configuration files for each deployment release (i.e. prod and test):

namespaces/wp-awe/prod.yml:

versions: {}

database:
  host: mariadb-galera.db-mariadb.svc
  name: wp-ait-prod  	

namespaces/wp-awe/test.yml:

  versions:
  	wordpress: 5.5.2-fpm
  
  database:
    host: mariadb-galera.db-mariadb.svc
    name: wp-ait-test

You can now use these variables in your Jinja templated manifest files or in your Helm values.yml files as follows:

...
containers:
    - name: main
        image: wordpress:{{ version('wordpress') }}
    env:
    	- name: DB_HOST
      	value: {{ deployment.get('database.host') }}
      - name: DB_NAME
      	value: {{ deployment.get('database.name') }}

In doing so, you can configure for example different databases for you instances. This is really useful, if you want to deploy an application severals times i.e. for several customers or use-cases.

Further when doing updates, you can increase versions.wordpress in test.yml to update and check the test instance before you update WordPress in the production instance.

Note that configuration files will be merged, so a versions: {} in prod.yml will not overwrite a versions:wordpress in defaults.yml.

Jinja Deployments

Jina templates in the templates folder can be compiled for each namespace and deployment-release as follows:

$ adeploy -p jinja render <dir> [<dir> ...]

You can do a server-dry-run and apply the manifests as follows:

$ adeploy -p jinja test <dir> [<dir> ...]
$ adeploy -p jinja deploy <dir> [<dir> ...]

adeploy is using kubectl and the current kubectl context including the destination kubernetes cluster and authentication.

The following variables are available for the Jinja templates:

  • name: The deployment name derived from the repo folder name or specified by –name
  • release: Release name derived from file namespaces/mynamespace/<release>.yml
  • namespace: The namespace for the deployment derived from folder namespaces/<namespace>/...
  • deployment: Variables from defaults.yml overwritten by namespaces/mynamespace/prod.yml

Example

Helm Deployments

The Helm chart in the chart folder (default value of --chart-dir) can be rendered with variables for each namespace and deployment-release merged with the variables from defaults.yml as follows:

adeploy -p helm render . [--chart-dir ./chart]

The chart name is given by the containing folder name or you can spsecify a name using the --name parameter.

If no chart folder is given, an upstream chart can be automatically downloaded using --repo-url URL in the render step:

adeploy [--name customer_chart_name] -p helm render . --repo-url https://chart.url

You can now do a server-dry-run and install the Helm chart as follows:

adeploy -p helm test .
adeploy -p helm deploy .  

Chart Version

The chart version can be set in the defaults.yml (or defaults/<release>.yml) for the appropriate deployments:

_chart:
    version: 0.0.0

Hooks

Since adeploy-0.4.X, the render step executes scripts from the /mydeployment/hooks folder as:

cd /mydeployment/hooks
./script.sh /mydeployment/build/helm/charts/<chartname>/

You can use this i.e. to patch Helm Charts without touching upstream repos for quick and dirty fixes before you install them.

Example

Conclusion

This tools introduced a simple and easy way to create k8s manifests using Jinja templates. Further it provides an abstraction for other deployment tools like Helm. We plan to support other deployment tools like Kustomize as well. This abstraction allows to implement really useful features that we hardly require in our daily use in all of these deployment tools. Examples are patching upstream Helm charts without touching or forking the upstream. Secret management, especially in CI/CD pipelines without the need to store secrets in a repo or using complicated secret operators in k8s is another example that we could solve using adepoly. If this also seems useful to you, have a look at https://github.com/awesome-it/adeploy and try it by yourself. We appreciate your feedback and of course we welcome your contributions to this project.