Importing ConfigMap Data into a Container

Configmap contents can be imported into a container in a number of ways, which will mostly be related to how the application is written. This post gives a couple of examples of how to make use of ConfigMaps to populate data within a container.

Creating Environmental Values from a ConfigMap

In this example a ConfigMap will be used to create some environmental values for a container and this will be confirmed using different techniques.

The aim of this exercise is to set 2 environmental values KEY1 and KEY2, which are stored in an existing ConfigMap. Further details of how to create a ConfigMap can be found here

The ConfigMap contents are shown below:

salterje@k8s-master:~/YAML/configmaps$ kubectl describe cm my-test-cm 
Name:         my-test-cm
Namespace:    default
Labels:       app=mytest
Annotations:  <none>

Data
====
KEY1.properties:
----
This is some data that has been inserted into KEY1

KEY2.properties:
----
This is KEY2 from KEY2.properties

This gives two Key-Pair values, KEY1.properties and KEY2.properties which will be imported into a container.

The values are set within the manifest file of a POD within the spec section. As normal the indent level must be correct within the file to allow the creation of the object.

The extract below shows two environmental variables being created KEY1 and KEY2. It can be seen that both of them will be imported from the my-test-cm ConfigMap and use the KEY1.properties and KEY2.properties.

spec:
      containers:
      - image: nginx
        imagePullPolicy: Always
        name: mytest-nginx
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        ports:
        - containerPort: 80
        env:                         # Setting an Environmental value within Container
          - name: KEY1               # The Name of the ENV Value
            valueFrom:
              configMapKeyRef:
                name: my-test-cm     # The Name of the ConfigMap
                key: KEY1.properties # The Name of the value within the ConfigMap
          - name: KEY2               # The Name of the ENV Value
            valueFrom:
              configMapKeyRef:
                name: my-test-cm     # The Name of the ConfigMap
                key: KEY2.properties # The Name of the value with the ConfigMap

There are a number of ways that we will confirm these variables have been created.

The first is by connecting to the container itself and checking directly. This is done by finding the correct POD (in our case the POD is part of a deployment) and executing the env command.

The command has been further narrowed down by piping the output to grep and searching just for the KEY values.

salterje@k8s-master:~/YAML/configmaps$ kubectl get pods 
NAME                                READY   STATUS    RESTARTS   AGE
mytest-deployment-54bbbf5b4-sgsvb   1/1     Running   0          9m47s

#salterje@k8s-master:~/YAML/configmaps$ kubectl exec -it mytest-deployment-54bbbf5b4-sgsvb -- env | grep KEY

KEY1=This is some data that has been inserted into KEY1
KEY2=This is KEY2 from KEY2.properties

An easier way, that doesn't involve connecting to a running container is to describe the deployment and confirm the environmental values.

kubectl describe deployments mytest-deployment


salterje@k8s-master:~/YAML/configmaps$ kubectl describe deployments.apps mytest-deployment

Name:                   mytest-deployment
Namespace:              default
CreationTimestamp:      Fri, 10 Jul 2020 15:20:21 +0000
Labels:                 <none>
Annotations:            deployment.kubernetes.io/revision: 4
Selector:               app=mytest-deployment
Replicas:               1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=mytest-deployment
  Containers:
   mytest-nginx:
    Image:      nginx
    Port:       80/TCP
    Host Port:  0/TCP
    Environment:
      KEY1:  <set to the key 'KEY1.properties' of config map 'my-test-cm'>  Optional: false
      KEY2:  <set to the key 'KEY2.properties' of config map 'my-test-cm'>  Optional: false
    Mounts:  <none>
  Volumes:   <none>
  

It can be seen that this confirms the values have been imported and where from but it doesn't actually confirm what they have been set to. Of course it is a simple matter of looking at the ConfigMap.

Mounting ConfigMap Data into a Container

As well as setting environmental variables it is also possible to directly mount the data into the container. This is particularly useful for application config files that can be mounted directly into /etc.

We will now use the same ConfigMap and mount the values into /etc/config within the container.

This means that a VolumeMount must be created within the container which will define the MountPath as well as linking to a Volume, also defined within the manifest file.

The Volume defines that a ConfigMap will be used and will also link to the ConfigMap itself.

The relevent section of the manifest is shown below.


spec:
      containers:
      - image: nginx
        imagePullPolicy: Always
        name: mytest-nginx2
        resources: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        ports:
        - containerPort: 80
        volumeMounts:   # volumeMount determines where to mount 
        - name: config-volume # Linking to the Volume
          mountPath: /etc/config # Where to mount the Data within Container
      volumes:
        - name: config-volume # Linking to the VolumeMount
          configMap: # This determines the volume is a ConfigMap
            name: my-test-cm # This is the name of the actual ConfigMap
            

Care should be taken with the indentation of the volumes section which should should be the same as the containers section (the volumeMounts is part of the container section so should be indented accordingly).

We'll confirm the success of the operation in a similar manner to before, first logging onto the container and then through describing the deployment.


salterje@k8s-master:~/YAML/configmaps$ kubectl get pods
NAME                                  READY   STATUS    RESTARTS   AGE
mytest-deployment-54bbbf5b4-sgsvb     1/1     Running   0          44m
mytest-deployment2-7cb9d7dfdf-8x7jl   1/1     Running   0          10m
salterje@k8s-master:~/YAML/configmaps$ kubectl exec -it mytest-deployment2-7cb9d7dfdf-8x7jl -- /bin/bash
root@mytest-deployment2-7cb9d7dfdf-8x7jl:/# ls -lh /etc/config
total 0
lrwxrwxrwx 1 root root 22 Jul 10 16:27 KEY1.properties -> ..data/KEY1.properties
lrwxrwxrwx 1 root root 22 Jul 10 16:27 KEY2.properties -> ..data/KEY2.properties

root@mytest-deployment2-7cb9d7dfdf-8x7jl:/# 
root@mytest-deployment2-7cb9d7dfdf-8x7jl:/# cat /etc/config/KEY1.properties 
This is some data that has been inserted into KEY1

root@mytest-deployment2-7cb9d7dfdf-8x7jl:/# cat /etc/config/KEY2.properties 
This is KEY2 from KEY2.properties

root@mytest-deployment2-7cb9d7dfdf-8x7jl:/# 

It can be seen that the data within the ConfigMap has been mounted as two seperate files within the container.

The other way of proving the success is to describe the POD and look at the Volumes mounted.


ame:         mytest-deployment2-7cb9d7dfdf-8x7jl
Namespace:    default
Priority:     0
Node:         k8s-node-2/192.168.56.31
Start Time:   Fri, 10 Jul 2020 16:27:06 +0000
Labels:       app=mytest-deployment2
              pod-template-hash=7cb9d7dfdf
Annotations:  cni.projectcalico.org/podIP: 192.168.140.90/32
              cni.projectcalico.org/podIPs: 192.168.140.90/32
Status:       Running
IP:           192.168.140.90
IPs:
  IP:           192.168.140.90
Controlled By:  ReplicaSet/mytest-deployment2-7cb9d7dfdf
Containers:
  mytest-nginx2:
    Container ID:   docker://7972ad98e575567cf818bfc4ef19a623515dcb556a8356481222a26189683ba6
    Image:          nginx
    Image ID:       docker-pullable://nginx@sha256:21f32f6c08406306d822a0e6e8b7dc81f53f336570e852e25fbe1e3e3d0d0133
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Fri, 10 Jul 2020 16:27:10 +0000
    Ready:          True
    Restart Count:  0
    Environment:    <none>
    Mounts:
      /etc/config from config-volume (rw)  # VolumeMount confirmed
      /var/run/secrets/kubernetes.io/serviceaccount from default-token-jvv47 (ro)
  Conditions:
  Type              Status
  Initialized       True
  Ready             True
  ContainersReady   True
  PodScheduled      True
Volumes:
  config-volume:
    Type:      ConfigMap (a volume populated by a ConfigMap)
    Name:      my-test-cm  # ConfigMap mounted
    Optional:  false
  default-token-jvv47:
    Type:        Secret (a volume populated by a Secret)
    SecretName:  default-token-jvv47
    Optional:    false
QoS Class:       BestEffort
Node-Selectors:  <none>
Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                 node.kubernetes.io/unreachable:NoExecute for 300s
             

It can be seen that the description of the POD shows the mount but the information needs to be combined with the description of the ConfigMap.

Conclusions

The two methods give an indication of how to use ConfigMaps to insert data into containers, rather then hard-coding into the application. This allows the same applications to have different configuration data by the simple modification of ConfigMap objects.

It can also be seen that there are a number of ways of confirming the operation including logging onto a container directly, although this wouldn't always be practical.