Quick Fix: Mounting a ConfigMap to an Existing Volume in Kubernetes Using Rancher

John O'Connor
Jul 10 · 4 min read
Image for post
Image for post

In this quick fix, I’ll detail how I FINALLY solved an issue that’s been plaguing me for quite some time: Mounting a single file stored in a ConfigMap into an existing directory in a Docker container on Kubernetes.

Introduction

However, many applications deployed with Docker were not originally designed to run in Docker. These applications will often rely on configuration files in a config directory to store and update the configuration of an application.

In this QuickFix, we’ll look at how to use a config map as a configuration file, and how to mount it into an existing config directory without clobbering the directory on the container.

The Problem

As an example, let’s look at a ConfigMap named test that contains two keys, Readme.md and test.txt. The values of those keys are the contents we want in those files.

apiVersion: v1
data:
Readme.md: '# This is a readme, mounted from a config map'
test.txt: This is a text file that was mounted from a config map.
kind: ConfigMap
metadata:
name: test
namespace: default

We can mount these config maps into a container by creating a volume mount. In the example below, we’ve mounted the config map to the /config path in the container.

apiVersion: apps/v1
kind: Deployment
metadata:
name: test
namespace: default
spec:
template:
spec:
containers:
- image: ubuntu:xenial
volumeMounts:
- mountPath: /config
name: vol1
volumes:
- configMap:
name: test
name: vol1

This will create a new directory called /config inside which will be our Readme.md and test.txt files:

root@test:/# ls
bin boot config dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@test:/# cd configroot@test:/config# ls
Readme.md test.txt
root@test:/config# cat Readme.md
# This is a readme, mounted from a config map
root@test:/config# cat test.txt
This is a text file that was mounted from a config map

This works well when the directory we want to mount into is empty or does not exist in the container. However, if the directory exists, the mount will overwrite that directory.

Many applications store their application configuration files in the same directory, and often times the developer will only want to override a small number of them.

For example, let’s say my application looks for database configuration in a file called database.yml in the /config subdirectory of my application. The working directory in the container is /usr/src/app and that I’d like to mount a file called database.yml from a ConfigMap into an existing config directory within that working directory. The config directory already contains a configuration file called default_config.yml which I don’t want to change.

Before mounting, the directory looks like this:

config
└── default_config.yml
└── application.yml

What I’d like to happen after injecting the config maps using a volume mount is this:

config
└── default_config.yml
└── application.yml
└── database.yml

However, since the default ConfigMap volume mount overwrites the directory, I end up with the following:

config
└── database.yml

Since my application relies on default_config.yml and since the application also looks for the database.yml in the same subdirectory, I need to mount the file from the ConfigMap as a volume without overwriting the entire /config directory.

The Solution

We’ll solve this by changing two items in our original file. First, we’ll update the mountPath to point to the specific file location that we want to place the contents of our file into. We’ll also specify that file as a subPath in our mount:

Previously:

volumeMounts:
- mountPath: /config
name: vol1

Now:

volumeMounts:
- mountPath: /usr/src/app/config/database.yml
name: vol1
subPath: database.yml

This will ensure that the database.yml is a file and not a directory.

Next, we’ll update our ConfigMap mount to point to the specific key (with the same name as the subPath) as the file, and use that file name as the path we wish to mount to:

Previously:

volumes:
- configMap:
name: test
name: vol1

Now:

volumes:
- configMap:
items:
- key: database.yml
path: database.yml
name: test
name: vol1

The final result looks like the following:

apiVersion: v1
data:
database.yml: 'credentials-go-here'
kind: ConfigMap
metadata:
name: config
namespace: default
---------------
apiVersion: apps/v1
kind: Deployment
metadata:
name: test
namespace: default
template:
spec:
containers:
image: ubuntu:xenial
name: test
resources: {}
volumeMounts:
- mountPath: /usr/src/app/config/database.yml
name: vol1
subPath: database.yml
volumes:
- configMap:
items:
- key: database.yml
path: database.yml
name: config
name: vol1

Wrap Up

The Startup

Medium's largest active publication, followed by +733K people. Follow to join our community.

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