ALL THINGS KUBERNETES

Configuring Kubernetes Apps Using ConfigMaps

We previously discussed how to use Secrets API to populate containers and pods with sensitive data and enhance the security of your Kubernetes application. Secrets are handy in detaching passwords and other credentials from pod manifests and in preventing bad actors from ever getting them.

Kubernetes ConfigMaps  apply the same approach to configuration data that can be easily detached from pod specs using a simple API.

In this tutorial, we’ll discuss various ways to create and expose ConfigMaps  to your pods and containers. By the end of this article, you’ll be able to inject configuration details into pods and containers without actually exposing them as literal values. This pattern enables better isolation and extensibility of your Kubernetes applications and allows easier maintainability of your deployment code. You’ll see it yourself soon. Let’s get started!

Definition of a ConfigMap

In a nutshell, ConfigMap  is a Kubernetes API object designed to detach configuration from container images. The basic rationale behind using ConfigMaps  is to make Kubernetes applications portable, maintainable, and extensible. A ConfigMap  API resource stores configuration data as key-value pairs. This data can be easily converted to files and environmental variables accessible inside container runtime and/or volumes mounted to the containers.

Unlike Kubernetes Secrets, however, ConfigMap  data is not obfuscated using base64  and is consumed as a plaintext. This is because you are not supposed to store sensitive information in your ConfigMaps . If you need to inject credentials to your Kubernetes application, use Secrets API instead.

There are several ways to create ConfigMaps  in Kubernetes: from literal values, from files, and using ConfigMap manifests. A general pattern for creating ConfigMaps using kubectl  looks like:

where the map-name  is the name of a ConfigMap  and the data-source  corresponds to a key-value pair in the ConfigMap , where

  • Key is the file name of the key you provided on the CLI, and
  • Value is the file contents or the literal value you provided on the CLI.

In what follows, we’ll see how to use this pattern to create ConfigMaps  in Kubernetes.

Tutorial

To complete examples in this tutorial, you’ll need:

  • A running Kubernetes cluster. See Supergiant documentation for more information about deploying a Kubernetes cluster with Supergiant. As an alternative, you can install a single-node Kubernetes cluster on a local system using Minikube.
  • A kubectl command line tool installed and configured to communicate with the cluster. See how to install kubectl here.

Creating ConfigMaps from Files

If you have a lot of configuration settings, the most viable option is storing them in files and creating ConfigMaps  from those files. To illustrate this, let’s first create a text file with some configuration. We came up with a simple front-end configuration that contains the following settings:

Save this configuration in some file (e.g., front-end ) and use --from-file  argument to ship this file to the ConfigMap :

To see a detailed information about a new ConfigMap , you can run:

You should see the following output:

As you see, the name of the file with configuration settings turned into the ConfigMap’s key and the contents of that file (all configuration fields) became the value of that key.

Alternatively, if you want to provide a key name different from the filename, you can use the following pattern:

In this case, the key of the ConfigMap  would be ui-config  instead of front-end .

Creating ConfigMaps from Literal Values

If you plan to use a few configuration settings, you can create a ConfigMap  from the literal value using --from-literal  argument. For example,

will create a ConfigMap with two key-value pairs specified in the --from-literal  arguments. As you see, using this argument, we can pass in multiple key-value pairs.

You can get a detailed description of the new ConfigMap  using the following command:

which will output something like this:

As you see, each key-value pair of your configuration is represented as a separate entry in the data  section of the ConfigMap .

Creating ConfigMaps With a ConfigMap Manifest

Defining a ConfigMap  manifest is useful when you want to create multiple configuration key-value pairs that can be accessed as environmental variables or files in the volumes mounted to the container/s in your pod.

ConfigMap  manifests look similar to API resources we’ve already discussed but have their distinct fields. Below is an example of a simple ConfigMap  that stores three key-value pairs:

As you see, the main difference between this manifest and other API resources is the ConfigMap  kind and special data  field that stores key-value pairs.

Save this spec in the trading-strategy.yaml  and create a ConfigMap  running the following command:

Check if the ConfigMap  was successfully created:

That’s it! A new ConfigMap  can be now used in pods. For example, one option is to expose configuration data in the container’s environmental variables:

Let’s briefly discuss key configuration fields of this pod spec:

  • spec.containers[].env[].name  — the name of the environmental variable to map ConfigMap  key to.
  • spec.containers[].env[].valueFrom.configMapKeyRef.name  — the name of ConfigMap  to use for this environmental variable.
  • spec.containers[].env[].valueFrom.configMapKeyRef.key  — a ConfigMap  key to use for this environmental variable.

Save this spec in the demo-envr.yaml  and create the pod:

Once the pod is ready and running, get a shell to the container:

From within the container, you can access configuration as environmental variables by using printenv  command.

Awesome, isn’t it? Now, you can access environmental variables inside your container. For example, the container’s scripts could use environmental variables defined in the ConfigMap  to set up your application.

If you have many ConfigMap  keys, it might be more viable to define those keys formatted as POSIX environmental variables and expose them to the pod using envFrom  field of the spec. Let’s create a new ConfigMap  to see how it works:

Notice that ConfigMap  keys are now formatted as POSIX environmental variable names. Now, you can save the spec in the ui-config.yaml  and create a ConfigMap  running the following command:

Next, let’s create a new pod that will use this ConfigMap :

Notice that spec.containers[].envFrom[].configMapRef  field takes only the name of our ConfigMap  (i.e., we need not specify all key-value pairs). Save this spec in the demo-from-env.yaml  and create the pod running the following command:

Check if the pod was created:

Once the pod is up and running, get a shell to the active container

And print the environmental variables using env  command from the bash:

As you see, the configuration variables defined in the ConfigMap  were successfully populated into the environmental variables of the container. Using envFrom  is less verbose because you don’t define individual environmental variables. This benefit, however, comes with the requirement of the proper formatting of variable names (see the note below):

Note: In case if you are using envFrom  instead of env  to create environmental variables in the container, the environmental names will be created from the ConfigMap’s keys. If a ConfigMap  key has invalid environment variable name, it will be skipped but the pod will be allowed to start. Kubernetes uses the same conventions as POSIX for checking the validity of environmental variables but that might change. According to POSIX:

Environment variable names used by the utilities in the Shell and Utilities volume of IEEE Std 1003.1-2001 consist solely of uppercase letters, digits, and the ‘_’ (underscore) from the characters defined in Portable Character Set and do not begin with a digit. Other characters may be permitted by an implementation; applications shall tolerate the presence of such names.

If the environmental variable name does not pass the check, the InvalidVariableNames  event will be fired and the message with the list of invalid keys that were skipped will be generated.

Injecting ConfigMaps into the Container’s Volume

As you remember from the previous tutorial, Kubernetes supports a  configMap  volume type that can be used to inject configuration defined in the ConfigMap  object for the use of containers in your pod. This option is useful when you want to populate configuration files inside the container with configuration key-value pairs defined in your ConfigMap .

To illustrate this use case, let’s populate the container’s volume with the ConfigMap  data defined in the example above.

In this pod spec, we define a configMap  volume type for the pod and mount it to the /etc/config  path inside the container.

Save this spec in the demo-config-volume.yaml  and create the pod running the following command:

Once the pod is ready and running, get a shell to the container

and check the /etc/config  folder:

As you see, Kubernetes created three files in that folder. Each file’s name is derived from the key name and the file contents are the key value. You can verify this easily:

If you want to map the ConfigMap  keys to different file names, you can slightly adjust the pod spec above using volumes.configMap.items  field.

Now, the strategy.risk  configuration will be stored under the path /etc/config/risk  instead of /etc/config/strategy.risk  as in the example above. Please note that the default path won’t be used if items are used. Thus, each piece of the ConfigMap desired must be reflected there.  Also, take note that if a wrong ConfigMap  key is specified, the volume will not be created.

Update Note: as soon as our ConfigMap  is consumed by a volume, Kubernetes will be running periodic checks on the configuration. If the ConfigMap  is updated, Kubernetes will ensure that the projected keys are updated as well. The update may take some time, depending on the kubelet  sync period. However, if your container uses a ConfigMap  as a subPath  volume mount, the configuration won’t be updated.

Cleaning Up

Let’s delete all assets and objects created during this tutorial.

Delete ConfigMaps:

Delete pods:

Finally, delete all files with resource manifests if you don’t need them anymore.

Conclusion

One of the main rules of good application development and containerized applications deployment is to separate configuration from the rest of your application. This allows deployments to be easily maintainable and extensible by different developer teams. Keeping configuration in ConfigMaps  and exposing them to your containers when needed embodies this vision for your Kubernetes applications. Instead of injecting configuration directly to container image, you can leverage the power of ConfigMaps  and pods to mount configuration key-value pairs to specific volume paths or environmental variables inside the container’s runtime. This approach will dramatically simplify the management of configuration in your Kubernetes applications ensuring their maintainability and extensibility.