Introduction to ConfigMaps in Kubernetes

In the previous articles of this Kubernetes series we discussed about Pods and Deployments. So I hope you know how to run a simple application in a Kubernetes cluster by now. In this article we are going to look at ConfigMaps in Kubernetes how to use them in Pods.

What are ConfigMaps in Kubernetes?

configmaps in kubernetes
K8s notation for ConfigMap

ConfigMap is another important resource type in Kubernetes. It is used for storing non confidential data as key-value pairs. Once a ConfigMap object is created, we can configure Pods to use the data stored in that ConfigMap. ConfigMaps in Kubernetes allow us to decouple environment specific configurations from container images themselves and mount them to containers as environment variables, volumes or command line arguments.

It is also worth noting that ConfigMaps in Kubernetes are not designed to hold large chunks of data. In fact, we can only store up to 1MiB of data in a ConfigMap. If we need to store large amounts of data, there are other ways to do that.

A simple use case of how we can use ConfigMaps in Kubernetes is providing the database host or the database name to a MySQL container running in a Pod through an environment variable.

Without further ado, let’s see how we can create a ConfigMap object in Kubernetes and then we can see how we can configure a Pod to consume that ConfigMap!

Write a Manifest for a ConfigMap

The manifest for a ConfigMap is pretty simple. You would notice that it is pretty similar to other resource types like Pods and Deployments except that it has a section called data instead of spec.

Following is a manifest of a very simple ConfigMap.

apiVersion: v1
kind: ConfigMap

metadata:
  name: mysql-config

data:
  MYSQL_DATABASE: finance

Let us have a closer look at this ConfigMap.

Version and Kind
  • Line 1 – apiVersion defines the Kubernetes API version. For a ConfigMap, it is v1 at the time of writing this article.
  • Line 2 – kind defines the type of resource we are going to create. In this case the kind is ConfigMap.
Metadata
  • Line 4 – the start of the metadata section.
  • Line 5 – here I have defined a name for my ConfigMap as mysql-config. You can give any name using alpha numeric characters and hyphens. Spaces are not allowed.

If you have been following the previous articles, above two sections are similar to other resource types we discussed. In fact, they are similar for all resource types. However, the next section is different. Instead of spec, we have a section called data here.

Data
  • Line 6 – the start of the data section.
  • Line 7 – a key with the name MYSQL_DATABASE that has finance as the value has been defined.

Pretty simple, right? If you have any other data, you can define them too as key-value pairs under the data section.

Create the ConfigMap Using the Manifest

Now that we have a manifest for the ConfigMap object, creating a resource using that is no different to how you would create any other object in a Kubernetes cluster. Just run the kubectl apply command followed by the manifest file name.

$ kubectl apply -f mysql-config.yaml
configmap/mysql-config created

We would see that the ConfigMap was created in the output if it was successfully created.

If we need to view the ConfigMap we just created, we can simply run the kubectl describe command, like for any other resource type. The output would be like below.

$ kubectl describe configmap mysql-config
Name:         mysql-config
Namespace:    default
Labels:       <none>
Annotations:  <none>

Data
====
MYSQL_DATABASE:
----
finance

BinaryData
====

Events:  <none>

We can see that our key-value pair is there under the Data section. There is another section called BinaryData because we can put binary data as well in ConfigMaps if needed. Since we don’t have any, it is empty.

You might have also noticed that Namespace is default. This is because ConfigMaps in Kubernetes are namespaced, which means they can only be accessed by other resources that are in the same namespace. So in this case, our mysql-config ConfigMap can only be accessed by resources that are in the default namespace.

Other Ways to Create ConfigMaps in Kubernetes

Before we jump into how we can use the ConfigMap we just created in a Pod, let’s see how else we can create ConfigMaps in Kubernetes. It would be nice if we could create a simple ConfigMap using a single command, wouldn’t it? We can do that using imperative kubectl commands as well.

To create the same ConfigMap we created above, we can simply run the following kubectl command.

$ kubectl create configmap mysql-config-imperative --from-literal=MYSQL_DATABASE=finance
configmap/mysql-config-imperative created

Here mysql-config-imperative is the name of the ConfigMap. Using the --from-literal flag, we pass the key-value pairs.

You can add more data to the ConfigMap by adding more --from-literal flags followed by a key-value pair as necessary. If you do a kubectl describe for this object, you would see that it is no different to the one we created using the manifest.

Now that we know how to create a ConfigMap object, let’s see how we can use it in a Pod!

Configure a Pod to Use a ConfigMap

If you have a look at the documentation for MySQL official image in DockerHub, under the environment variables section, you would notice that it accepts an optional environment variable called MYSQL_DATABASE. It allows us to give a name for the default database that will be created at startup. Let’s create a MySQL Pod that uses this environment variable and provide the value using the ConfigMap we created above.

Create a MySQL Pod to Consume the ConfigMap

We can write a simple manifest for the MySQL Pod as below.

apiVersion: v1
kind: Pod

metadata:
  name: mysql-pod
  labels:
    app: mysql

spec:
  containers:
  - name: mysql
    image: mysql
    ports:
    - containerPort: 3306
    env:
    - name: MYSQL_DATABASE
      valueFrom:
        configMapKeyRef:
          name: mysql-config
          key: MYSQL_DATABASE
    - name: MYSQL_ROOT_PASSWORD
      value: charith

What you can see above is the full manifest for the MySQL Pod we are going to create. What we are interested here is the following environment variable section.

    env:
    - name: MYSQL_DATABASE
      valueFrom:
        configMapKeyRef:
          name: mysql-config
          key: MYSQL_DATABASE
    - name: MYSQL_ROOT_PASSWORD
      value: charith

If you look at the environment variable MYSQL_ROOT_PASSWORD I have defined the value directly. But for MYSQL_DATABASE, I have retrieved the value from the ConfigMap previously created.

  • Line 2 – the name of the environment variable.
  • Line 3 and 4 – basically says to fetch the value for MYSQL_DATABASE from a key defined in a ConfigMap.
  • Line 5 – name is the name of the ConfigMap which is mysql-config.
  • Line 6 – key is the key in ConfigMap where the value is stored at. In this case the key is MYSQL_DATABASE. If we look at the ConfigMap, we know the value for this key is finance.

So what this means is, when the MySQL Pod is started from this manifest, a database named finance should be created at startup, as per the documentation for MySQL image in DockerHub. Let’s create a Pod from this manifest and see the outcome!

We can create the pod using kubectl apply command as before.

$ kubectl apply -f mysql-pod.yaml
pod/mysql-pod created

Now if we run a kubectl describe command, we can see that the value for the environment variable is fetched from the ConfigMap.

    Environment:
      MYSQL_DATABASE:       <set to the key 'MYSQL_DATABASE' of config map 'mysql-config'>  Optional: false
      MYSQL_ROOT_PASSWORD:  charith

See If the Finance Database was Created

Let’s try to go inside the container now and see if the finance database is created.

  1. Run kubectl exec -it mysql-pod -- sh command to open an interactive terminal inside the Pod.
  2. Run mysql -u root -p to login as root user and enter the root password when prompted. In above example I set the value for MYSQL_ROOT_PASSWORD as charith, so that will be the password in this case.
  3. Once logged in, run show databases; command to see the available databases.
$ kubectl exec -it mysql-pod -- sh
sh-4.4# mysql -u root -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 8.0.32 MySQL Community Server - GPL

Copyright (c) 2000, 2023, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| finance            |
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
5 rows in set (0.00 sec)

mysql>

Notice that the finance database is there! This means our setup worked as expected.

Conclusion

There are other ways a Pod can consume ConfigMaps. Since environment variables are the most common scenario, for an introduction, this should do. You can read more about this in the Kubernetes Documentation.

In our Pod manifest, we defined the MySQL root password in plain text. This is in no way a good security practice due to many reasons. You might wonder why we didn’t put that as well in the ConfigMap. The reason is, ConfigMaps in Kubernetes are not supposed to hold secret data such as passwords or keys. After all, we stored data in plain text in the ConfigMap as well. There is another resource type called Secrets to store secret data. We will look into Secrets in the next article!

Share this article if it was helpful!

Leave a Reply

Your email address will not be published. Required fields are marked *