In this article, we are going to talk about serveral different ways to create and update ConfigMap in Kubernetes.
Creating ConfigMap
Create from folder
kubectl create folder-cm --from-file <folder_name>
# Create with folder
$ kubectl create folder-cm --from-file config
$ kubectl get cm/folder-cm -o yaml
apiVersion: v1
data:
config.txt: |
Test=test
test.txt: |
DONT=KNOW
kind: ConfigMap
metadata:
creationTimestamp: "2022-05-02T15:53:44Z"
name: folder-cm
namespace: default
resourceVersion: "41428"
uid: 9f71a652-2350-4d55-be6e-5ef468cd45f8
Create from file
💡Can create with multiple files, if create with all the files in the same folder, it’s same with creating from folder:
## Create with file
$ kubectl create cm file-cm --from-file config/config.txt --from-file config/test.txt
$ kubectl get cm/file-cm -o yaml
apiVersion: v1
data:
config.txt: |
Test=test
test.txt: |
DONT=KNOW
kind: ConfigMap
metadata:
creationTimestamp: "2022-05-02T16:03:36Z"
name: file-cm
namespace: default
resourceVersion: "42433"
uid: 17766fc1-cfd5-4b95-b00f-296844f23407
The name of the file will be the key of key-value pair in ConfigMap
while the content of the file will be the value.
If we want some specific keys, we can create the ConfigMap with given key:
$ kubectl create cm key-cm --from-file=key=config.txt
$ kubectl get cm/key-cm -o yaml
apiVersion: v1
data:
key: |
DB_URL=localhost:3306
DB_USERNAME=postgres
kind: ConfigMap
metadata:
creationTimestamp: "2022-05-03T15:16:25Z"
name: key-cm
namespace: default
resourceVersion: "63721"
uid: eb3c93ca-fcfc-42bd-82ce-2d8cddbfc900
Create from key-value pairs
$ kubectl create cm value-cm --from-literal=Test=test
$ kubectl get cm/value-cm -o yaml
apiVersion: v1
data:
Test: test
kind: ConfigMap
metadata:
creationTimestamp: "2022-05-03T15:26:07Z"
name: value-cm
namespace: default
resourceVersion: "64703"
uid: f5431bb3-6276-48e8-85e0-33b0ef1a7243
Create from env file
đź’ˇenv file can be .env
file and .txt
file and so on ..
$ kubectl create cm env-cm --from-env-file=config.txt
$ kubectl get cm/env-cm -o yaml
apiVersion: v1
data:
DB_URL: localhost:3306
DB_USERNAME: postgres
kind: ConfigMap
metadata:
creationTimestamp: "2022-05-03T15:30:49Z"
name: env-cm
namespace: default
resourceVersion: "65184"
uid: 60dba811-8fa9-4bb1-9e7b-9d45a02009eb
Comparing with Create from file
, in which same file is used to create configMap, instead of using filename/given key as key, and file content as value, creating from env file
reads the file first, and uses key-value pairs
in the file to create ConfigMap.
Using configMap
Use ConfigMap as files in pod
Mount configMap
ConfigMap can be mounted to pods as volumes. Here is the yaml file of a pod who mounts all the ComfigMaps we’ve created above (folder-cm, file-cm, value-cm, env-cm):
# file-pod.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
name: file-pod
spec:
containers:
- image: nginx
name: pod
ports:
- containerPort: 80
resources: {}
volumeMounts:
- name: folder
mountPath: "folder"
- name: file
mountPath: "file"
- name: value
mountPath: "value"
- name: env
mountPath: "env"
dnsPolicy: ClusterFirst
restartPolicy: Always
volumes:
- name: folder
configMap:
name: folder-cm
- name: file
configMap:
name: file-cm
- name: value
configMap:
name: value-cm
- name: env
configMap:
name: env-cm
status: {}
Then if we log into the pod and check what is going on inside:
$ kubectl exec -it pod/file-pod -- bash
# Inside pod
$ tree -L 2
...
|-- env
| |-- DB_URL -> ..data/DB_URL
| `-- DB_USERNAME -> ..data/DB_USERNAME
|-- file
| |-- config.txt -> ..data/config.txt
| `-- test.txt -> ..data/test.txt
|-- folder
| |-- config.txt -> ..data/config.txt
| `-- test.txt -> ..data/test.txt
|-- value
| `-- Test -> ..data/Test
...
Apparently, no matter from what we created the ConfigMap
, the pod who mounted them would generate a file for each key-value pairs in ConfigMap
using key as filename and value as content.
đź’ˇMounting ConfigMap to pods as volumes is setting to Read-Only
by default.
Mount ConfigMap with SubPath
It’s mentioned that when we mount a ConfigMap
to a pod, a folder named as what is specified in spec.containers.volumeMounts.mountPath
in the yaml file will be created (if there’s already a folder with same name, the original folder will be covered and the files in this folder cannot been seen anymore.)
But there will be a situation that we only want to create a file based on the ConfigMap
and put it into a folder which already exited.
For example, folder /etc/nginx/conf.d
which already has a file default.conf
for Nginx. Instead of making this file disappear, we only want to add a new file into this folder. Then we need SubPath
:
# file-pod2
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
name: file-pod2
spec:
containers:
- image: nginx
name: pod
ports:
- containerPort: 80
resources: {}
volumeMounts:
- name: folder
mountPath: "folder"
- name: file
mountPath: "/etc/nginx/conf.d/config.txt"
subPath: "config.txt"
- name: value
mountPath: "value"
- name: env
mountPath: "env"
dnsPolicy: ClusterFirst
restartPolicy: Always
volumes:
- name: folder
configMap:
name: folder-cm
- name: file
configMap:
name: file-cm
- name: value
configMap:
name: value-cm
- name: env
configMap:
name: env-cm
status: {}
According to documentation of Kubernetes 1.24
:
TheÂ
volumeMounts.subPath
property specifies a sub-path inside the referenced volume instead of its root.
So, consider each volume is a folder, then for file
volume, it contains config.txt
file and text.txt
file. Then we can use relative path “config.txt” to point to config.txt
file of file volume
in spec.containers.volumeMounts.subPath
property.
If we apply this yaml file again and log into the new pod:
$ ls
... env folder value ...
Other folders are still here but just file
folder is gone. Then we can check /etc/nginx/conf.d
folder.
$ ls /etc/nginx/conf.d
config.txt default.conf
$ cat /etc/nginx/conf.d/config.txt
Test=test
default.conf
file is still here and only config.txt
file which is specified in subPath
is create in this folder.
Update ConfigMap
Now, let’s see what will happen if we try to modify a ConfigMap. We edit two ConfigMaps: file-cm
and value-cm
:
#file-cm
apiVersion: v1
data:
config.txt: |
Test=file-modified
test.txt: |
DONT=KNOW
kind: ConfigMap
metadata:
creationTimestamp: "2022-05-02T16:03:36Z"
name: file-cm
namespace: default
resourceVersion: "281558"
uid: 17766fc1-cfd5-4b95-b00f-296844f23407
#value-cm
apiVersion: v1
data:
Test: value-modified
kind: ConfigMap
metadata:
creationTimestamp: "2022-05-03T15:26:07Z"
name: value-cm
namespace: default
resourceVersion: "317489"
uid: f5431bb3-6276-48e8-85e0-33b0ef1a7243
Then we can log into file-pod2, which we created in previous section, and check what happened after we modified the ConfigMap
:
$ kubectl exec -it pod/file-pod2 -- bash
# Content has been updated
$ cat value/Test
value-modified
# Content remains the same
$ cat /etc/nginx/conf.d/config.txt
Test=test
According to the result, after a ConfigMap
is changed, the container who mounted this ConfigMap
as volume will be updated as well. But there are several exceptions.
One of these exceptions is that if the container uses the ConfigMap
as SubPath
volume, then it won’t receive the update.
đź’ˇConfigMap
can be set immutable, immutable ConfigMap
will not be watched constantly, which can reduce load on kube-apiserver
.
apiVersion: v1
kind: ConfigMap
metadata:
...
data:
...
immutable: true
Use ConfigMap as environment variables in pod
Using specific values in ConfigMap as environment variables
In order to use specific values in ConfigMap as environment variables
in container, we used spec.containers.env.valueFrom.configMapKeyRef
:
# env-pod.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
name: env-pod
spec:
containers:
- image: nginx
name: pod
ports:
- containerPort: 80
resources: {}
env:
- name: FOLDER_KEY
valueFrom:
configMapKeyRef:
name: folder-cm
key: test.txt
- name: ENV_KEY
valueFrom:
configMapKeyRef:
name: env-cm
key: DB_URL
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
Then create a new pod with this yaml file and checke the environment variables of it’s container:
$ kubectl exec pod/env-pod -- env
...
FOLDER_KEY=DONT=KNOW
ENV_KEY=localhost:3306
...
The name of the variables are what we specified with spec.containers.env.name
. Then it will search in the target ConfigMap
which we specified with spec.env.valueFrom.configMapKeyRef.name
in order to find the target key-value pair whose key equals to what we specified in spec.env.valueFrom.configMapKeyRef.key
. The value of this environment variable will be the value of target key-value pair.
Using all values in ConfigMap as environment variables
Here we will use spec.containers.envFrom.configMapRef
to inject all the key-value pairs of a ConfigMap
to a container as environment variables:
# all-env-pod.yaml
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
name: all-env-pod
spec:
containers:
- image: nginx
name: pod
ports:
- containerPort: 80
resources: {}
envFrom:
- configMapRef:
name: env-cm
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
After this yaml file is applied, the environment variables of the new containers are:
$ kubectl exec pod/all-env-pod -- env
...
DB_URL=localhost:3306
DB_USERNAME=postgres
...
All the key-value pairs of ConfigMap
are used as environment variable and their keys are the variable names while their values are the variable values.
Update ConfigMap
Same as what we mentioned in previous section - Use ConfigMap as files in pod
, we are going to modified the ConfigMap and see what will happen to corresponding containers:
## env-cm
data:
DB_URL: localhost:3306_modified
DB_USERNAME: postgres
kind: ConfigMap
metadata:
creationTimestamp: "2022-05-03T15:30:49Z"
name: env-cm
namespace: default
resourceVersion: "65184"
uid: 60dba811-8fa9-4bb1-9e7b-9d45a02009eb
We changed the value of DB_URL
, then environment variables of the previous two containers are:
$ kubectl exec pod/env-pod -- env
...
FOLDER_KEY=DONT=KNOW
ENV_KEY=localhost:3306
...
$ kubectl exec pod/all-env-pod -- env
...
DB_URL=localhost:3306
DB_USERNAME=postgres
...
The environment variables who are created from ConfigMap remain the same. This is the other situation that we talked about before in which corresponding containers will not receive the update of the ConfigMap.