Posted on 12 August 2019, updated on 21 December 2023.
I encountered an issue with the container orchestrator, Kubernetes, where I couldn’t set up a secret as an environment variable: my service only supported passing this variable as a single configuration file along with non-sensitive data. To address this issue, I called Helm to the rescue.
Issue: Kubernetes can't natively merge Secret and ConfigMap in a single file
Let’s say we have this standard yaml configuration file:
Applying Kubernetes concepts we should only store the database password in a Secret and the rest should be in a ConfigMap.
But we wouldn’t be able to merge those two data sources in a single file while using those ConfigMap and Secret as a volume:
Well Kubernetes doesn’t support it and does not aim at supporting it: https://github.com/kubernetes/kubernetes/issues/30716
But with the help of Helm and a little bash trick you can achieve it!
Setup: Creating a Helm chart
First use Helm to create your chart:
helm create templating-inception
Let’s say your config files are at the root directory of your repository here’s the directory setup you’ll need:
Nothing too exciting except for this symbolic link, we’ll come back to that later but it’s a requirement if you want to keep your configuration files that way.
Helm: Templating the template
We are going to use the templating function of Helm during the templating process of our ConfigMap, here’s the configmap.yaml
file you should create:
The instruction in this template reads all files suffixed by .tmpl
and set them up as filename:filecontent
in this ConfigMap.
As you can see we will have to rename our parameters.yaml
file parameters.yaml.tmpl
and use some Helm templating:
This step isn’t required but it helps when working with multiple environments.
Let’s see add our values to the values.yaml
file:
We’re close achieve our goal but for now, we want Helm to template our parameters.yaml
file as follow:
NB: The symlink you created before was only there because Helm uses server-side rendering on Tiller to compute the resources it has to deploy and only the chart directory is uploaded to Tiller. For now, Helm doesn’t support referencing paths higher in the hierarchy but with the 3.0.0 version currently in alpha and the disappearance of Tiller this should be achievable.
Bash: Substitutor of environments
The last part is a mix of the envsubst
command and the concept of initContainer in Kubernetes.
The description of the envsubst
command is as clear as its name: “Substitutes the values of environment variables.”
Let’s use it in our deployment.yaml file:
Here’s the shell command launched by the initContainer:
sh -c for file in $(ls -A /tmpl/ | grep tmpl); do newfile=${file%".tmpl"}; envsubst < /tmpl/$file > /app/config/$newfile; done'
The $DATABASE_PASSWORD
environment variable will be substituted with its value in the parameters.yaml.
Using this template you’ll have to setup those values in your values.yaml
file as well:
Here’s your service getting its configuration /config/paramaeters.yaml
file with both values from a Secret and a ConfigMap.
This setup will work for any file added to the config directory.
Merging a ConfigMap and a Secret in a single file is a complex process that requires knowledge of Helm and Kubernetes if you have any questions or suggestions, don't hesitate to contact us to share your experience with us.
Also, check out our article about Kubernetes productivity tips and tricks to go further on Kubernetes usage.