Kubernetes Series: Explaining ConfigMaps with Practical Examples
Introduction
This article aims at explaining the Kubernetes ConfigMap objects through a set of practical examples.
ConfigMaps
A ConfigMap is an k8s API object used to store non-confidential data in key-value pairs. It aims at making applications easily portable through decoupling their environment-specific configuration. [1]
A ConfigMap has data and binaryData fields. These fields accept key-value pairs as their values. Both the data field and the binaryData are optional.
The data field is designed to contain UTF-8 strings while the binaryData field is designed to contain binary data as base64-encoded strings.
The keys stored in data must not overlap with the keys in the binaryData field.
Configmaps can be created:
- From literal value
- From a file
- From a directory of files
They are used to configure a container inside a Pod in different ways:
- As environment variables for a container
- As a file in read-only volume, for the application to read
A ConfigMap is not designed to hold large chunks of data. The data stored in a ConfigMap cannot exceed 1 MiB. [1]
If you need to store settings that are larger than this limit, you may want to consider mounting a volume [1]
Practical Examples: Creating ConfigMaps
- Let’s use
kubectl
command to create aConfigMap
from literal value
# check how to create a ConfigMap
kubectl create configmap -h
# create a new config map named game-demo with the following key-values:
# player_initial_lives="3"
# ui_properties_file_name="user-interface.properties"
kubectl create configmap game-demo \
--from-literal=player_initial_lives="3" \
--from-literal=ui_properties_file_name="user-interface.properties"
# describe the created configmap game-demo
kubectl describe configmap game-demo
# OUTPUT:
Name: game-demo #configmap name
Namespace: default
Labels: <none>
Annotations: <none>
Data #configmap data field
====
player_initial_lives: #configmap data key
----
3 #configmap data value
ui_properties_file_name: #configmap data key
----
user-interface.properties #configmap data value
BinaryData #confgimap binarydata field
====
Events: <none>
2. Let’s use kubectl
command to create a ConfigMap
from a file
Let’s say we have an alerts.yml
file that defines alerts for Prometheus.
# alerts.yml
groups:
- name: Nodes Alerts
rules:
- alert: VM Down
expr: up{job="node_exporter"} == 0
for: 10m
labels:
severity: "critical"
annotations:
description: " The VM {{ $labels.instance }} has been down for more than 10 minutes."
Let create a ConfigMap
that will contain the alerts.yml
file. alerts.yml
is the ConfigMap
key and the alerts.yml
file content is the ConfigMap
value.
# create the configmap from file
kubectl create configmap prometheus-alerts --from-file=alerts.yml
# describe the configmap to see its content
kubectl describe configmap prometheus-alerts
# OUTPUT
Name: prometheus-alerts #configmap name
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
alerts.yml: #configmap key
----
groups: #configmap value
- name: Nodes Alerts
rules:
- alert: VM Down
expr: up{job="node_exporter"} == 0
for: 10m
labels:
severity: "critical"
annotations:
description: " The VM {{ $labels.instance }} has been down for more than 10 minutes."
BinaryData
====
Events: <none>
3. Let’s use kubectl
command to create a ConfigMap
from a folder
We have a folder named alerts
that consists of two files : alert-node.yml
and alert-memory.yml
:
# alert-memory.yml
groups:
- name: Memory Alerts
rules:
- alert: High Memory Usage
expr: (node_memory_MemAvailable_bytes * 100) / node_memory_MemTotal_bytes < 15
for: 30m
labels:
severity: warning
annotations:
description: ' The memory of the VM: {{ $labels.instance }} is filling up. The available Memory is only {{ $value | printf "%.2f" }} %.'
# alert-node.yml
- name: Nodes Alerts
rules:
- alert: VM Down
expr: up{job="node_exporter"} == 0
for: 10m
labels:
severity: "critical"
annotations:
description: " The VM {{ $labels.instance }} has been down for more than 10 minutes."
Let create a ConfigMap
that will contain the alerts
folder content (in our case, both files alert-node.yml
and alert-memory.yml
). Files names represent the ConfigMap
keys whereas files content represent the ConfigMap
values.
# Create a new config map named prometheus-alerts based on folder alerts
kubectl create configmap prometheus-alerts --from-file=./alerts/
# Let's describe the configmap to see its content
kubectl describe configmap prometheus-alerts
# OUTPUT:
Name: prometheus-alerts #configmap name
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
alert-memory.yml: #configmap key
----
groups: #configmap value
- name: Memory Alerts
rules:
- alert: High Memory Usage
expr: (node_memory_MemAvailable_bytes * 100) / node_memory_MemTotal_bytes < 15
for: 30m
labels:
severity: warning
annotations:
description: ' The memory of the VM: {{ $labels.instance }} is filling up. The available Memory is only {{ $value | printf "%.2f" }} %.'
alert-node.yml: #configmap key
----
groups: #configmap value
- name: Nodes Alerts
rules:
- alert: VM Down
expr: up{job="node_exporter"} == 0
for: 10m
labels:
severity: "critical"
annotations:
description: " The VM {{ $labels.instance }} has been down for more than 10 minutes."
BinaryData
====
Events: <none>
Note that this article doesn’t concern Prometheus, thus the way we’re creating alerts using ConfigMaps is not the right way to use for Prometheus, These are just examples.
4. Let’s use kubectl
command to create a ConfigMap
from an environment File.
Let’s say we have the following .env
file
#.env
DATABASEHOST=localhost
Let create a ConfigMap
that will contain the .env
environment file content. DATABASEHOST
is the ConfigMap
key and the localhost
is the ConfigMap
value.
# create the configmap
kubectl create configmap database --from-env-file=.env
# describe the created configmap
kubectl describe configmap database
# OUTPUT
Name: database #configmap name
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
DATABASEHOST: #configmap key
----
localhost #configmap value
BinaryData
====
Events: <none>
Practical Examples: Mount ConfigMaps to Containers
- Mounting the
configmap
as a file (or a set of files) in read-only volume
Let’s create a pod
named nginx
to which the configmap
named prometheus-alerts
created previously from a folder will be mounted
# generate the nginx pod yaml file
kubectl run nginx - image=nginx - dry-run=client -o yaml > nginx.yaml
Let’s edit the nginx.yaml
file to mount the prometheus-alerts
configmap
as a file (or a set of files, depending on the configmap
available keys) in read-only volume.
# nginx.yaml
# data defined in the configmap prometheus-alerts will be mounted as files
# to the alerts volume mounted under the /alerts path within
# the nginx container
apiVersion: v1
kind: Pod
metadata:
labels:
run: nginx
name: nginx
spec:
containers:
- image: nginx
name: nginx
# ------ add this lines------
volumeMounts:
- name: alerts
mountPath: /alerts
readOnly: true
# ---------------------------
volumes:
- name: alerts
configMap:
name: prometheus-alerts
# ---------------------------
restartPolicy: Always
# create the nginx pod
kubectl apply -f nginx.yaml
# checkout the mounted files
kubectl exec -it nginx -- sh -c "ls /alerts/"
# OUTPUT
alert-memory.yml alert-node.yml
Instead of mounting all of configmap
data, we can mount only specific data based on keys as files within a container as follows:
# nginx.yaml
# the value of alert-node.yml key defined in the configmap prometheus-alerts
# will be mounted as a file named alert-node.yml
# to the alerts volume mounted under the /alerts path within
# the nginx container
apiVersion: v1
kind: Pod
metadata:
labels:
run: nginx
name: nginx
spec:
containers:
- image: nginx
name: nginx
# ------ add this lines------
volumeMounts:
- name: alerts
mountPath: /alerts
readOnly: true
# ---------------------------
volumes:
- name: alerts
configMap:
name: prometheus-alerts
items:
# configmap selected key
- key: alert-node.yml
# how the file will be named
# (the file contains the value of the selected key)
path: alert-node.yml
# ---------------------------
restartPolicy: Always
# create the nginx pod
kubectl apply -f nginx.yaml
# checkout the mounted files
kubectl exec -it nginx -- sh -c "ls /alerts/"
# OUTPUT
alert-node.yml
2. Mounting the configmap
as environment variables for a container
Let’s create a pod
named nginx
to which the configmap
named database
created previously from an environment file will be mounted.
# generate the nginx pod yaml file
kubectl run nginx - image=nginx - dry-run=client -o yaml > nginx.yaml
# nginx.yaml
apiVersion: v1
kind: Pod
metadata:
labels:
run: nginx
name: nginx
spec:
containers:
- image: nginx
name: nginx
# add these lines ---------
env:
- name: databaseName
valueFrom:
configMapKeyRef:
name: database
key: DATABASEHOST
# --------------------------
# create the pod
kubectl apply -f nginx.yml
# verify if the env variable has been set for the container nginx
kubectl exec -it nginx --sh -c "printenv"
#OUTPUT
..
databaseName=localhost
Mounted ConfigMaps are updated automatically
When a ConfigMap currently consumed in a volume is updated, projected keys are eventually updated as well. The kubelet checks whether the mounted ConfigMap is fresh on every periodic sync.[1]
ConfigMaps consumed as environment variables are not updated automatically and require a pod restart [1]
A container using a ConfigMap as a subPath volume mount will not receive ConfigMap updates. [1]
Immutable ConfigMaps
The Kubernetes feature Immutable ConfigMaps provides an option to set individual ConfigMaps as immutable, preventing changes to their data. This option has the following advantages: [1]
- Protection against unwanted updates that could cause applications outages [1]
- Cluster performance improvement through significantly reducing load on kube-apiserver, by closing watches for ConfigMaps marked as immutable. [1]
An immutable ConfigMap can be created by setting the immutable field to true. For example: [1]
apiVersion: v1
kind: ConfigMap
metadata:
...
data:
...
immutable: true
Conclusion
The primary goal of this article was to provide a good understanding of ConfigMaps k8s objects . This has been accomplished through a brief explanation and a bunch of practical examples.
References
[1] Configmaps (2023) Kubernetes. Available at: https://kubernetes.io/docs/concepts/configuration/configmap/#configmap-immutable (Accessed: 13 June 2023).
[2] AK, S. (2023) Kubernetes configmap examples — how to guide: Devops junction, Middleware Inventory. Available at: https://www.middlewareinventory.com/blog/kubernetes-configmap-examples/ (Accessed: 13 June 2023).