Kubernetes ConfigMaps and Secrets Part 2

Sandeep Dinesh
Aug 8, 2017 · 4 min read

This is a continuation from Part 1.

While environment variables are great for small bits of information, sometimes you might have a lot of data that needs to be passed to your app. A common solution is to group this data into a file, and have your app read from this file.

Kubernetes let’s you mount ConfigMaps and Secrets as files. Unlike environment variables, if these files change the new files will be pushed to the running pods without needing a restart, so they are a lot more powerful. You can also map multiple files to a single ConfigMap or Secret, and mount them all at once as a directory!

Read from a file

Let’s modify our code from Part 1 to read from files instead of environment variables.

First, create a two subdirectories called “config” and “secret”, and config.json and secret.json files with the data we used in part one:

mkdir config && mkdir secretecho '{"LANGUAGE":"English"}' > ./config/config.jsonecho '{"API_KEY":"123-456-789"}' > ./secret/secret.json

Now, edit the code so it reads in these files instead of environment variables.

Image for post
Image for post

Important: This code will re-read the file on every request. If you read the file once when the program starts, updates to the file will not be captured and you will need to restart the container to update the files. A common pattern that is more efficient that re-reading the file every time is to use a file watcher that will reload the file only when it changes.

Mount the files using Docker volumes

The first step is to test everything works by using Docker volumes to simulate the ConfigMaps and Secrets.

Rebuild the container:

docker build -t envtest .

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

docker run -p 3000:3000 -ti \
-v $(pwd)/secret/:/usr/src/app/secret/ \
-v $(pwd)/config/:/usr/src/app/config/ \
envtest

This will run the Docker container, and mount the data folders into the container.

Note: the onbuild container that is used for the base image puts the code into the /usr/src/app directory. That is why the folders are mounted there.

If you visit localhost:3000 the container should be serving traffic.

Image for post
Image for post

Because the file is mounted into the container and the code re-reads the file on every request, you can change the files and see the change without restarting anything!

For example:

echo '{"LANGUAGE":"Spanish"}' > ./config/config.json
Image for post
Image for post

Creating the ConfigMap and Secret

Create the Secret from the file

kubectl create secret generic my-secret \
--from-file=./secret/secret.json

Then create the ConfigMap from the other file

kubectl create configmap my-config --from-file=./config/config.json

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

Using ConfigMaps and Secrets as files

The final step is using creating a deployment that will use the ConfigMap and Secret as a file instead of an environment variable

Note: Remember you need to update and push the Docker image in your registry to use the new code. You can do that with this command if you are using Google Cloud.

gcloud container builds submit --tag gcr.io/$(gcloud config list project --format=text | awk '{print $2}')/envtest:file .

In your deployment YAML, you can use the ConfigMap and Secret as a volume. This will automatically mount them as a directory in your container, just like with Docker.

Image for post
Image for post

Notice that the Secret and ConfigMap are mapped to volumes, and these volumes are used in the volumeMount section of the container spec.

Updating with no downtime!

Unlike Part 1’s environment variables, volumes can be dynamically remounted into running containers. This means that new ConfigMap and Secret values will be available to the container without needed to restart the running processes.

For example, change the language to Klingon and update the ConfigMap.

echo '{"LANGUAGE":"Klingon"}' > ./config/config.jsonkubectl create configmap my-config \
--from-file=./config/config.json \
-o yaml --dry-run | kubectl replace -f -

In a few seconds (up to a minute depending on the cache) the new file will be pushed to the running containers automatically!

Image for post
Image for post

If you want to update the secret, you can follow the same process:

echo '{"API_KEY":"0987654321"}' > ./secret/secret.jsonkubectl create secret generic my-secret \
--from-file=./secret/secret.json \
-o yaml --dry-run | kubectl replace -f -

Note: These updates are eventually consistent. It is possible that some containers get the update before others, creating inconsistencies in your deployments. If this is an issue, do not use the auto-update feature. Instead, create a new ConfigMap or Secret, and update or create a new Deployment to use the new one.

Google Cloud - Community

A collection of technical articles published or curated by…

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

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