×
Community Blog How to Create and Use ConfigMaps in Kubernetes

How to Create and Use ConfigMaps in Kubernetes

This tutorial shows you how to get started with creating and using ConfigMaps in Kubernetes Pods.

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.

  • Config: keeps configuration information.
  • Maps: In computer science, an associative array, map, symbol table, or dictionary is an abstract data type composed of a collection of (key, value) pairs, such that each possible key appears at most once in the collection. Learn more on this Wiki page.

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.

Prerequisites

This tutorial is written using Windows 10, kubectl, and minikube. If you have a similar setup you are good to go.

Important Note for Windows Users

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.

Basic Example: Create ConfigMaps from a file

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

Basic Example: Create ConfigMaps using --from-env-file

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

Basic Example: Create ConfigMaps from Literal Values

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>

Basic Example: Create ConfigMaps from Directories

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.

Access ConfigMap data via container environment variables

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

Access 2 ConfigMap's Data via Container Environment Variables

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

Access All Key-Value Pairs in a ConfigMap as Environment Variables

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

Access All Key-Value Pairs in a 2 ConfigMaps as Environment Variables

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

Clean Up

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.

0 0 0
Share on

Alibaba Clouder

2,599 posts | 762 followers

You may also like

Comments