Kubernetes ConfigMaps and Secrets

Sandeep Dinesh
Jul 13, 2017 · 5 min read

Everyone needs to configure applications. You often need to reference “special” bits of data, such as API keys, tokens, and other secrets. Your app may be tunable using configuration settings, for example, a PHP.ini file, or environment variables and flags that change logic in your app.

You may be tempted to hard code these references into your application logic. In a small, standalone application, this might be acceptable, but it quickly becomes unmanageable in any reasonably sized app.

Of course, we have solved this problem. You can use environment variables and configuration files to store this information in a “central location” and reference these from our app. When you want to change the configuration, simply change it in the file or change the environment variable, and you are good to go! No need to hunt down every location where the data is referenced.

This problem becomes exacerbated in the land of containers and microservices. Docker lets you specify environment variables in the Dockerfile, but what if you need to reference the same data in two different containers? If you try to use the host environment, what happens when you are running on a cluster with multiple machines?

Let’s take an app with hardcoded configuration, change it to read from environment variables, and finally set up Kubernetes to manage the configuration for you.

In Part Two, I will use a configuration file instead of environment variables.

All code is located in this Gist: https://gist.github.com/thesandlord/6e297d7ceb807e6f0243255ab7885d83

The Hardcoded App

Here is the app in all its hardcoded glory:

Image for post
Image for post
https://gist.github.com/thesandlord/6e297d7ceb807e6f0243255ab7885d83#file-hardcode-js

If you wanted to change the language or the API key, you would need to touch the code. This can lead to bugs, security leaks, and pollutes the source history.

Let’s move to using environment variables instead.

Step 1: Using Environment Variables

Moving to environment variables is easy. Most programming languages have a built in way to read them.

Image for post
Image for post
https://gist.github.com/thesandlord/6e297d7ceb807e6f0243255ab7885d83#file-envvars-js

That’s all it takes!

Now we can set these environment variables and don’t have to touch our application’s code

In a Unix system (like MacOS and Linux), you can run this command to set environment variables for your current session:

export LANGUAGE=English

For Windows, you can use this command:

setx LANGUAGE “English”

You can set environment variables when starting the server as well.

For example, for this Node.js app, you can run:

LANGUAGE=Spanish API_KEY=0987654 npm start

And these will be exposed to the app.

Step 2: Moving to Docker Environment Variables

When you move to a containerized solution, you can no longer depend on the host’s environment variables. Each container has its own environment, so it is important to make sure the container’s environment is properly configured. Thankfully, Docker makes it easy to build containers with environment variables baked in. In your Dockerfile, you can specify them with the ENV directive.

Image for post
Image for post
https://gist.github.com/thesandlord/6e297d7ceb807e6f0243255ab7885d83#file-dockerfile

Put the Dockerfile in the same directory as your code.

Then build the container:

docker build -t envtest .

After building the container, run it with the following command:

docker run -p 3000:3000 -ti envtest

You can also override the environment variables when running on the command line:

docker run -e LANGUAGE=Spanish -e API_KEY=09876 -p 3000:3000 \
-ti envtest

Step 3: Moving to Kubernetes Environment Variables

When moving from Docker to Kubernetes, things change once again. You might use the same Docker container in multiple kubernetes deployments or you might want to do A/B testing with your deployments where you use the same container with different configurations.

Just like the Dockerfile, you can specify environment variables directly in your Kubernetes Deployment YAML file. This means each deployment can get a customized environment.

Image for post
Image for post
https://gist.github.com/thesandlord/6e297d7ceb807e6f0243255ab7885d83#file-embededenv-yaml

The important section is the env portion of the pod spec. You can specify as many environment variables as you want here. Both environment variables are now set through Kubernetes!

Step 4: Centralized Configuration with Kubernetes Secrets and ConfigMaps

The shortfall of Docker and Kubernetes environment variables is that they are tied to the container or deployment. If you want to change them, you have to rebuild the container or modify the deployment. Even worse, if you want to use the variable with multiple containers or deployments, you have to duplicate the data!

Thankfully, Kubernetes solves this problem with Secrets (for confidential data) and ConfigMaps (for non-confidential data).

The big difference between Secrets and ConfigMaps are that Secrets are obfuscated with a Base64 encoding. There may be more differences in the future, but it is good practice to use Secrets for confidential data (like API keys) and ConfigMaps for non-confidential data (like port numbers).

Let’s save the API key as a Secret:

kubectl create secret generic apikey --from-literal=API_KEY=123–456

And the language as a ConfigMap:

kubectl create configmap language --from-literal=LANGUAGE=English

You can check that these are created with the following commands:

kubectl get secret
Image for post
Image for post

And

kubectl get configmap
Image for post
Image for post

Now, you can modify your Kubernetes deployment to read from these instead of the hardcoded values.

Image for post
Image for post
https://gist.github.com/thesandlord/6e297d7ceb807e6f0243255ab7885d83#file-final-yaml

Updating Secrets and ConfigMaps

As mentioned above, having Kubernetes manage your environment variables for you means you don’t have to change code or rebuild containers when you want to change the value of the variable.

Because pods cache the value of environment variables during startup, this is a two step process.

First, update the values:

kubectl create configmap language --from-literal=LANGUAGE=Spanish \

Then, restart the pods. This can be done is a variety of ways, such as forcing a new deployment. The quick and easy way is to delete the pods manually and have the deployment automatically spin up new ones.

kubectl delete pod -l name=envtest

That’s all it takes! The new values will now be used by your app!

In Part Two, I’ll show you how to use Configuration Files, which are even more powerful in Kubernetes than Environment Variables.

Google Cloud - Community

Google Cloud community articles and blogs

Sandeep Dinesh

Written by

Google Cloud - Community

A collection of technical articles and blogs published or curated by Google Cloud Developer Advocates. The views expressed are those of the authors and don't necessarily reflect those of Google.

Sandeep Dinesh

Written by

Google Cloud - Community

A collection of technical articles and blogs published or curated by Google Cloud Developer Advocates. The views expressed are those of the authors and don't necessarily reflect those of Google.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store