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?
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 isv1
at the time of writing this article. - Line 2 –
kind
defines the type of resource we are going to create. In this case thekind
isConfigMap
.
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 hasfinance
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 ismysql-config
. - Line 6 –
key
is the key in ConfigMap where the value is stored at. In this case the key isMYSQL_DATABASE
. If we look at the ConfigMap, we know the value for this key isfinance
.
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.
- Run
kubectl exec -it mysql-pod -- sh
command to open an interactive terminal inside the Pod. - Run
mysql -u root -p
to login as root user and enter the root password when prompted. In above example I set the value forMYSQL_ROOT_PASSWORD
ascharith
, so that will be the password in this case. - 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!