Developers have used Configuration as Code (CaC) and the Twelve-Factor App Methodology for years given the many benefits these practices have to offer. You can also accomplish this in Kubernetes, if you use an API resource called <terminal inline>ConfigMap<terminal inline> to separate code and configuration.
Using ConfigMaps avoids Kubernetes configuration issues including:
- differing pace between app code development and changes in its configuration
- lack of proper version control for configuration, which prevents reversing changes when necessary
- accidental changes to Pod configuration
This article will explore what ConfigMaps are and how they work, and suggest different ways of creating them.
What Are ConfigMaps?
In simple terms, a ConfigMap is a Kubernetes API object that allows you to store non-sensitive information. Since they are objects, ConfigMaps can be consumed by other API objects such as Pods. This makes them especially useful for storing environment variables, command-line arguments, or any configuration artifact in a file or volume.
How Do They Work?
Unlike other Kubernetes objects, ConfigMaps store data as key-value pairs using <terminal inline>data<terminal inline> and <terminal inline>binaryData<terminal inline> fields instead of <terminal inline>spec<terminal inline> fields. That gives ConfigMaps the flexibility to store UTF-8 byte sequences (<terminal inline>data<terminal inline> field) or binary data as base64-encoded strings (<terminal inline>binaryData<terminal inline> field).
The information stored in ConfigMaps can be used in multiple ways. For example, it can be used within a container to execute command-line arguments or set environment variable values in that container. You can also add a ConfigMap file to a read-only volume and mount it inside as many Pods as required.
Although ConfigMaps are widely used to configure the settings of containers running inside Pods, their flexibility makes them useful for other tasks as well. Since ConfigMaps can be mounted as data volumes, they can be used by other parts of the system as add-ons or operators that conform to the parameters set in the corresponding ConfigMap.
You’ll need to keep the following in mind when creating a ConfigMap:
- The <terminal inline>ConfigMap<terminal inline> object should not be used to store confidential information such as user credentials or certificates, since the information is stored as plain text without encryption.
- The name you assign to the <terminal inline>ConfigMap<terminal inline> object must be a valid DNS subdomain name.
- Since ConfigMaps are intended to store configurations and variables, their file size is limited to 1 MB.
- In the <terminal inline>data<terminal inline> field, values can be stored in two different ways, as key-value pairs or as fragments of a configuration format (such as file-like keys).
- For added security, as of Kubernetes v1.19, you can create immutable ConfigMaps by adding the <terminal inline>immutable<terminal inline> field to their definition.
Here is an example of a ConfigMap from the Kubernetes documentation:
Notice how the ConfigMap stores data both as property-like keys and file-like keys.
How to Create a ConfigMap
You can create ConfigMaps from directories, regular files, files containing environment variables, or directly from the command line using literal values.
For the purposes of this guide, Docker Desktop will be used to run Kubernetes and illustrate how to create ConfigMaps. However, you can also use Katacoda, Play with Kubernetes, K3s, or minikube, among others.
The basic command to create a <terminal inline>ConfigMap<terminal inline> using <terminal inline>kubectl<terminal inline> CLI is as follows:
Let’s go through the components of this command.
- <terminal inline>map-name<terminal inline> - refers to the name of the <terminal inline>ConfigMap<terminal inline>
- <terminal inline>data-source<terminal inline> - can be the path to a file or directory containing the ConfigMap(s)
- <terminal inline>arguments<terminal inline> - specifies whether to use files or directories (<terminal inline>--from-file<terminal inline>), environmental files (<terminal inline>--from-env-file<terminal inline>), or literal values (<terminal inline>--from-literal<terminal inline>)
Here are more details about that last component.
Creating a ConfigMap from an Environmental File
Let’s start by creating a new directory to store the ConfigMaps:
Now, create an <terminal inline>env.properties <terminal inline> file inside the <terminal inline>configmaps <terminal inline> directory and paste the following content:
Save and close the <terminal inline>env.properties <terminal inline> file and execute the following command to create the ConfigMap:
You will see the message <terminal inline>configmap/game-demo <terminal inline> created. To review the ConfigMap’s contents in YAML format, you can use the command:
The output should be something similar to:
Creating a ConfigMap from a File
You can use a similar procedure to create a ConfigMap from a file. Paste the following content into the <terminal inline>game.properties<terminal inline> file inside the <terminal inline>configmaps<terminal inline> directory:
Then create the new ConfigMap using this command:
You can verify the content using the command:
The output should look like this:
Creating a ConfigMap from a Directory
You can combine several files by using the <terminal inline>--from-file<terminal inline> or <terminal inline>--from-env-file<terminal inline> arguments multiple times, indicating each file’s path. However, a more efficient method is to specify a directory where all the files are located, as shown below:
<terminal>kubectl create configmap game-demo-3 --from-file=configmaps<terminal>
When using the command <terminal inline>kubectl get configmap game-demo-3 -o yaml<terminal inline>, the result would be similar to this:
Creating a ConfigMap from the Command Line
You can also create a ConfigMap from literal values. Use the <terminal inline>--from-literal<terminal inline> argument as shown below:
<terminal>kubectl create configmap game-demo-4 --from-literal=terrain.type=continent --from-literal=map.climate=tropical<terminal>
When examining the ConfigMap using the command <terminal inline>kubectl get configmap game-demo-4 -o yaml<terminal inline>, you should see something like this:
Alternative Ways to Create a ConfigMap
Since Kubernetes v1.14, you can also use <terminal inline>kubectl<terminal inline> to manage objects using Kustomize.
Kustomize is designed to customize Kubernetes configurations. Among its features is a <terminal inline>configMapGenerator<terminal inline> that generates ConfigMaps from files or literals.
For more information on Kustomize, read its official documentation here.
Why Do You Want to Use ConfigMaps?
Here are some of the most important reasons to use ConfigMaps in your deployments:
- ConfigMaps enable you to separate the application code from its configuration.
- You won’t have to hardcode the configuration data in the Pod specification.
- As long as the application supports it, you can use ConfigMaps to update your configuration while the application is running.
- ConfigMaps allow you to create complex configurations with ease.
- Segregating the Pod definition from its configuration allows you to reuse the configuration (or part of it) in multiple Pods or objects.
- The separation of the configuration from the rest of the cluster objects allows for better version control.
- As of v1.19 you can create immutable ConfigMaps, so you can protect your deployment from accidental (or intentional) configuration changes.
Using ConfigMaps is not only a Kubernetes configuration best practice but a good way to facilitate and improve cluster management.
You can supercharge the benefits of ConfigMaps with a Kubernetes monitoring platform such as ContainIQ. ContainIQ’s pre-built dashboards automatically collect metrics and events for you, so you can prevent any potential problems before they occur.