By Alwyn Botha, Alibaba Cloud Tech Share Author. Tech Share is Alibaba Cloud's incentive program to encourage the sharing of technical knowledge and best practices within the cloud community.
This tutorial gives you practical experience in creating and using ConfigMaps in Kubernetes Pods. Note the name: ConfigMaps. Let's look at what that means.
Simply put ConfigMaps store configuration maps/dictionaries of key=value data.
ConfigMaps store plain text values unencrypted - do not use if for secrets. Kubernetes has functionality that deals specifically with secrets, which is covered in the article How to Create and Use Secrets in Kubernetes.
ConfigMap values are frequently referenced using Linux environment variables.
This tutorial is written using Windows 10, kubectl, and minikube. If you have a similar setup you are good to go.
All files you create must have Unix (LF) line endings, not Windows ( CR LF ) endings. Read your editor documentation on how to change it to default to LF line endings. There should also be some EOL conversion menu option somewhere to convert to LF.
If you are using a server then you need a running Kubernetes cluster, and your kubectl command-line tool must be able to access your cluster. If you run kubectl get nodes and it shows a list of nodes - even just one - you are good to go.
You need about 2 weeks of basic beginner exposure to Kubernetes to follow these tutorials.
If you have zero Kubernetes experience I suggest you spend a few days reading at https://kubernetes.io/docs/concepts/ Unfortunately these are not step by step how-to tutorials, mostly in-depth theory with snippets assuming you know how to apply it. The https://kubernetes.io/docs/tasks/ are step by step tutorials, but you need to be quite familiar with the theory and concepts.
You need not be a theory expert to follow this tutorial, we will walk you thorough some practical experience of applying Kubernetes.
You should speed-read rush through the first few basic examples. Its very easy to do and understand.
Create file that will be the input to our ConfigMap.
nano config-map-data.txt
key1=value1
key2=23
Create the ConfigMap using our file just created.
kubectl create configmap configmap-example-1 --from-file=./config-map-data.txt
configmap/configmap-example-1 created
Find out what Kubernetes knows about our newly created ConfigMap via kubectl describe .
kubectl describe configmap/configmap-example-1
Name: configmap-example-1
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
config-map-data.txt:
----
key1=value1
key2=23
Events: <none>
Our keys and values are shown at the bottom. ConfigMap successfully created.
This part of the tutorial focus on creating ConfigMaps - we can now delete it since ALL we wanted to learn was how to create a ConfigMap .
kubectl delete configmap/configmap-example-1
configmap "configmap-example-1" deleted
Create a ConfigMap with comments and blank lines in it.
nano config-map-data.txt
key1=value1
key2=23
# comment 1
## comment 2
Create the ConfigMap using our file just created.
kubectl create configmap configmap-example-1 --from-file=./config-map-data.txt
configmap/configmap-example-1 created
Find out what Kubernetes knows about our newly created ConfigMap via kubectl describe .
kubectl describe configmap/configmap-example-1
Name: configmap-example-1
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
config-map-data.txt:
----
key1=value1
key2=23
# comment 1
## comment 2
Events: <none>
Our 2 keys and their values are shown at the bottom.
IMPORTANT : Kubernetes does not have know-how of how to ignore the comments and blank lines if we use --from-file . In section 2 you will see how --from-env-file fixes that automatically.
Alternative way to get Kubernetes to show what it knows about our ConfigMap : kubectl get configmap Note the -o yaml at the end. If you leave that off, all you will get is a simple one-line list of our ConfigMap.
-o yaml specifies the output format to be YAML.
7 lines of metadata removed from kubectl get configmap output throughout this tutorial since it adds no value to the discussions.
kubectl get configmap configmap-example-1 -o yaml
apiVersion: v1
data:
config-map-data.txt: |+
key1=value1
key2=23
# comment 1
## comment 2
kind: ConfigMap
Demo complete, delete the ConfigMap.
kubectl delete configmap/configmap-example-1
configmap "configmap-example-1" deleted
This section shows how to create a ConfigMap using the Docker environment file format.
Create a ConfigMap using the same file from previous example: that file is in Docker environment file format.
kubectl create configmap configmap-example-1 --from-env-file=./config-map-data.txt
configmap/configmap-example-1 created
Note the --from-env-file versus --from-file we used earlier.
kubectl describe configmap/configmap-example-1
Name: configmap-example-1
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
key1:
----
value1
key2:
----
23
Events: <none>
Note that --from-env-file ignores the blank lines and comments perfectly - as it should.
The describe command shows the keys and values perfectly.
Best Practice: have your ConfigMaps in environment file format and use --from-env-file to create your ConfigMaps.
For more information about the Docker environment file format, visit this page. Only the syntax rules at the top are relevant. You just saw Kubernetes interprets those rules perfectly.
Alternative command to show facts about our ConfigMap: kubectl get configmap Note no ugly blank lines or # comments at the top.
kubectl get configmap configmap-example-1 -o yaml
apiVersion: v1
data:
key1: value1
key2: "23"
kind: ConfigMap
Simple example of how to create ConfigMaps from literal values.
--from-literal= syntax specifies our keys and their literal value.
kubectl create configmap literal-config-1 --from-literal=literal-key1=value1 --from-literal=literal-key2=22
configmap/literal-config-1 created
Find out what Kubernetes knows about our newly created ConfigMap via kubectl describe .
kubectl describe configmap/literal-config-1
Name: literal-config-1
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
literal-key1:
----
value1
literal-key2:
----
22
Events: <none>
Our keys and their literal values are shown at the bottom. ConfigMap successfully created using literal values.
Demo done, delete it.
kubectl delete configmap/literal-config-1
configmap "literal-config-1" deleted
Second literal values example.
kubectl create configmap literal-config-1 --from-literal=city=London --from-literal=population=millions
configmap/literal-config-1 created
Use kubectl describe to find out if it got created successfully.
kubectl describe configmap/literal-config-1
Name: literal-config-1
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
city:
----
London
population:
----
millions
Events: <none>
You will now see how to create a ConfigMap that combines the content of all files in a directory.
Run the following in your shell:
mkdir ConfigMap-Folder
nano ./ConfigMap-Folder/file-1.txt
file-1-key-one:1
file-1-key-two:awesome
nano ./ConfigMap-Folder/file-2.txt
file-2-key-one:2
file-2-key-two:cool
Note that --from-file=ConfigMap-Folder refers to our FOLDER.
kubectl create configmap from-folder-configmap --from-file=ConfigMap-Folder
configmap/from-folder-configmap created
Use kubectl describe to find out if it got created successfully.
kubectl describe configmap/from-folder-configmap
Name: from-folder-configmap
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
file-1.txt:
----
file-1-key-one:1
file-1-key-two:awesome
file-2.txt:
----
file-2-key-one:2
file-2-key-two:cool
Events: <none>
It looks OK, but if we use kubectl get configmaps to show the ConfigMap we can see it is not OK.
I edited file-1 and file-2 using Windows line endings. Those r n in the output below should not be there.
kubectl get configmaps from-folder-configmap -o yaml
apiVersion: v1
data:
file-1.txt: "file-1-key-one:1\r\nfile-1-key-two:awesome\r\n"
file-2.txt: "file-2-key-one:2\r\nfile-2-key-two:cool\r\n"
kind: ConfigMap
Delete wrong ConfigMap.
kubectl delete configmaps/from-folder-configmap
configmap "from-folder-configmap" deleted
Use your editor and convert line endings to be Unix format.
Recreate the ConfigMap.
kubectl create configmap from-folder-configmap --from-file=ConfigMap-Folder
configmap/from-folder-configmap created
Use kubectl get configmaps to show details. Perfect, n r all gone.
kubectl get configmaps from-folder-configmap -o yaml
apiVersion: v1
data:
file-1.txt: |
file-1-key-one:1
file-1-key-two:awesome
file-2.txt: |
file-2-key-one:2
file-2-key-two:cool
kind: ConfigMap
You are now familiar with all the ways of creating ConfigMaps. To access these values via environment variables is slightly more complex.
We did not delete ConfigMap literal-config-1. We use it here, this is its content:
kubectl get configmaps literal-config-1 -o yaml
apiVersion: v1
data:
city: London
population: millions
kind: ConfigMap
Create a Pod that references literal-config-1 using configMapKeyRef.
nano ConfigMap-demo-1.yaml
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod-1
spec:
containers:
- name: cm-container-1
image: alpine
imagePullPolicy: IfNotPresent
command: [ "/bin/sh", "-c", "env" ]
env:
- name: ENV_CITY
valueFrom:
configMapKeyRef:
name: literal-config-1
key: city
restartPolicy: Never
ENV_CITY defines the name we want our environment variable to have.
Its value comes from : valueFrom ... literal-config-1
We want the value of the city key to be placed inside ENV_CITY .
kubectl create -f ConfigMap-demo-1.yaml
pod/configmap-pod-1 created
command: [ "/bin/sh", "-c", "env" ] runs a command env to display a list of our environment variables.
We use kubectl logs configmap-pod-1 to show the log of our pod. ENV_CITY shown near the end.
We successfully passed our city key value into the environment variable ENV_CITY.
kubectl logs configmap-pod-1
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
HOSTNAME=configmap-pod-1
SHLVL=1
HOME=/root
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
ENV_CITY=London
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/
You now know how to access ConfigMap data via container environment variables.
Get a list of our Pods. Note its status is completed. It only had to run the command env . The Pod then exited successfully.
kubectl get po
NAME READY STATUS RESTARTS AGE
pod/configmap-pod-1 0/1 Completed 0 2m46s
Here is the complete output of describe . Too much detail, so I edited it below.
kubectl describe pod/configmap-pod-1
Name: configmap-pod-1
Namespace: default
Priority: 0
PriorityClassName: <none>
Node: minikube/10.0.2.15
Start Time: Wed, 02 Jan 2019 11:24:24 +0200
Labels: <none>
Annotations: <none>
Status: Succeeded
IP: 172.17.0.5
Containers:
cm-container-1:
Container ID: docker://791e4ae1f8aad006ee77d81c401cf19221764805952cc9190e16a722d4bb9929
Image: alpine
Image ID: docker-pullable://alpine@sha256:46e71df1e5191ab8b8034c5189e325258ec44ea739bba1e5645cff83c9048ff1
Port: <none>
Host Port: <none>
Command:
/bin/sh
-c
env
State: Terminated
Reason: Completed
Exit Code: 0
Started: Wed, 02 Jan 2019 11:24:25 +0200
Finished: Wed, 02 Jan 2019 11:24:25 +0200
Ready: False
Restart Count: 0
Environment:
ENV_CITY: <set to the key 'city' of config map 'literal-config-1'> Optional: false
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from default-token-gs2wt (ro)
Conditions:
Type Status
Initialized True
Ready False
ContainersReady False
PodScheduled True
Volumes:
default-token-gs2wt:
Type: Secret (a volume populated by a Secret)
SecretName: default-token-gs2wt
Optional: false
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 3m18s default-scheduler Successfully assigned default/configmap-pod-1 to minikube
Normal Pulled 3m17s kubelet, minikube Container image "alpine" already present on machine
Normal Created 3m17s kubelet, minikube Created container
Normal Started 3m17s kubelet, minikube Started container
Normal SandboxChanged 3m15s kubelet, minikube Pod sandbox changed, it will be killed and re-created.
Edited output below:
kubectl describe pod/configmap-pod-1
Name: configmap-pod-1
Start Time: Wed, 02 Jan 2019 11:24:24 +0200
Status: Succeeded
Containers:
cm-container-1:
State: Terminated
Reason: Completed
Exit Code: 0
Started: Wed, 02 Jan 2019 11:24:25 +0200
Finished: Wed, 02 Jan 2019 11:24:25 +0200
Ready: False
Environment:
ENV_CITY: <set to the key 'city' of config map 'literal-config-1'> Optional: false
Conditions:
Type Status
Initialized True
Ready False
ContainersReady False
PodScheduled True
Explains it all: Pod started and finished in a second. It is terminated, since it completed with exit code 0 = success.
Status: Succeeded
State: Terminated
Reason: Completed
Exit Code: 0
Started: Wed, 02 Jan 2019 11:24:25 +0200
Finished: Wed, 02 Jan 2019 11:24:25 +0200
Text below: Pod got initialized and scheduled = true.
It is NOT ready NOW since it terminated.
Type Status
Initialized True
Ready False
ContainersReady False
PodScheduled True
Demo complete, delete Pod.
kubectl delete -f ConfigMap-demo-1.yaml --force --grace-period=0
warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.
pod "configmap-pod-1" force deleted
Let's create another literal ConfigMap so we have 2 ConfigMaps to access in our Pod.
kubectl create configmap literal-config-2 --from-literal=shipping=free --from-literal=region=all
configmap/literal-config-2 created
Check its successfully created. Looks good.
kubectl get configmaps literal-config-2 -o yaml
apiVersion: v1
data:
region: all
shipping: free
kind: ConfigMap
Create a Pod that refers to 2 different ConfigMaps.
nano ConfigMap-demo-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod-2
spec:
containers:
- name: cm-container-2
image: alpine
imagePullPolicy: IfNotPresent
command: [ "/bin/sh", "-c", "env" ]
env:
- name: ENV_CITY
valueFrom:
configMapKeyRef:
name: literal-config-1
key: city
- name: ENV_SHIPPING
valueFrom:
configMapKeyRef:
name: literal-config-2
key: shipping
restartPolicy: Never
The ENV_CITY environment variable gets its value from city key in literal-config-1 ConfigMap.
The ENV_SHIPPING environment variable gets its value from shipping key in literal-config-2 ConfigMap.
kubectl create -f ConfigMap-demo-2.yaml
pod/configmap-pod-2 created
Check the logs: both our environment variables are shown. Success.
You now know how to access ConfigMap data from several ConfigMaps via container environment variables.
kubectl logs configmap-pod-2
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
HOSTNAME=configmap-pod-2
SHLVL=1
HOME=/root
ENV_SHIPPING=free
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
ENV_CITY=London
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_HOST=10.96.0.1
Show the content of both keys in literal-config-1
kubectl get configmaps literal-config-1 -o yaml
apiVersion: v1
data:
city: London
population: millions
To access all the keys in a ConfigMap we just do not refer to any specific key in our spec.
nano ConfigMap-demo-3.yaml
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod-3
spec:
containers:
- name: cm-container-3
image: alpine
imagePullPolicy: IfNotPresent
command: [ "/bin/sh", "-c", "env" ]
envFrom:
- configMapRef:
name: literal-config-1
restartPolicy: Never
Simple spec extract below : syntax to create environment variables from all keys in ConfigMap literal-config-1
envFrom:
- configMapRef:
name: literal-config-1
Create the ConfigMap.
kubectl create -f ConfigMap-demo-3.yaml
pod/configmap-pod-3 created
Show the Pod's log. Both our keys were converted into environment variables.
Note that their names are still lower case: exactly as it is in the original literal-config-1 ConfigMap .
You have to make the names upper case in the original raw file if that is what you need.
kubectl logs configmap-pod-3
KUBERNETES_PORT=tcp://10.96.0.1:443
KUBERNETES_SERVICE_PORT=443
HOSTNAME=configmap-pod-3
population=millions
SHLVL=1
HOME=/root
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/
city=London
To access all the keys in SEVERAL ConfigMaps we just do not refer to any specific key in our spec.
nano ConfigMap-demo-4.yaml
apiVersion: v1
kind: Pod
metadata:
name: configmap-pod-4
spec:
containers:
- name: cm-container-4
image: alpine
imagePullPolicy: IfNotPresent
command: [ "/bin/sh", "-c", "env" ]
envFrom:
- configMapRef:
name: literal-config-1
- configMapRef:
name: literal-config-2
restartPolicy: Never
Create this ConfigMap.
kubectl create -f ConfigMap-demo-4.yaml
pod/configmap-pod-4 created
This is the content of our 2 ConfigMaps :
kubectl get configmaps literal-config-1 -o yaml | head -4
apiVersion: v1
data:
city: London
population: millions
kubectl get configmaps literal-config-2 -o yaml | head -4
apiVersion: v1
data:
region: all
shipping: free
The log of our Pod. Note all the keys from both the ConfigMaps are now live as environment variables.
kubectl logs configmap-pod-4
KUBERNETES_SERVICE_PORT=443
KUBERNETES_PORT=tcp://10.96.0.1:443
HOSTNAME=configmap-pod-4
population=millions
SHLVL=1
HOME=/root
region=all
shipping=free
KUBERNETES_PORT_443_TCP_ADDR=10.96.0.1
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
KUBERNETES_PORT_443_TCP_PORT=443
KUBERNETES_PORT_443_TCP_PROTO=tcp
KUBERNETES_SERVICE_PORT_HTTPS=443
KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443
KUBERNETES_SERVICE_HOST=10.96.0.1
PWD=/
city=London
Get a list of your ConfigMaps :
( Note the age, I created it yesterday when I wrote first part of this tutorial. )
kubectl get cm
NAME DATA AGE
configmap-example-1 1 25h
from-folder-configmap 2 24h
literal-config-1 2 25h
literal-config-2 2 23h
Delete the ConfigMaps ... you may have more to delete.
kubectl delete cm/configmap-example-1
kubectl delete cm/from-folder-configmap
kubectl delete cm/literal-config-1
kubectl delete cm/literal-config-2
Run kubectl get cm again to check you deleted it all.
Run kubectl get po to get list of Pods.
Delete ones you do not need anymore :
For example :
kubectl delete -f ConfigMap-demo-1.yaml --force --grace-period=0
kubectl delete -f ConfigMap-demo-2.yaml --force --grace-period=0
kubectl delete -f ConfigMap-demo-3.yaml --force --grace-period=0
kubectl delete -f ConfigMap-demo-4.yaml --force --grace-period=0
Note: I use --force --grace-period=0 in these tutorials to immediately stop Pods. Otherwise it will take 30 seconds for Pod to gracefully shut down. Using --force in production is a sure way to cause data corruption.
2,599 posts | 762 followers
FollowAlibaba Container Service - February 20, 2023
Alibaba Developer - April 22, 2021
feuyeux - July 6, 2021
Alibaba Clouder - July 16, 2019
Alibaba Cloud Native - March 5, 2024
Alibaba Clouder - April 23, 2019
2,599 posts | 762 followers
FollowAlibaba Cloud Container Service for Kubernetes is a fully managed cloud container management service that supports native Kubernetes and integrates with other Alibaba Cloud products.
Learn MoreA secure image hosting platform providing containerized image lifecycle management
Learn MoreElastic and secure virtual cloud servers to cater all your cloud hosting needs.
Learn MoreMore Posts by Alibaba Clouder