K8s – ConfigMap

The ConfigMap enables us to store non-confidential configuration data. It’s being specific to namespace, we can use it for externalizing environment specific configurations.

By externalizing our environment specific configurations, it makes our container IMAGEs portable across different environments.

Considering the dynamic nature of scheduling of PODs in different Nodes, it provides an elegant solution to share the application configurations.

 

How it holds key-value literals & configuration files ?

The diagram sums up the concept behind the ConfigMaps. It shows how it stores the files and literals as key-value pairs inside the ConfigMap.

The sample ConfigMap represents two literal key-value pairs and two properties files(app.properties and subscription.yaml).

  • Literals : literal-key is used as key; literal-value is stored as its value.
  • Files : The file name is used used as the key and the content as its value.

As we will see we can import each of the keys as separate environment variables or separate linked files using volume.

Create ConfigMap -Using ‘create configmap’

We can edit the ConfigMap API object and apply it the server. Kubectl ‘create configmap’ provides an easier option to create it directly from our local configuration files.

Create ConfigMaps from Files and Literals

Step-1 : Create the below two files on your local system.

app.properties

email=test@spectrums.com
session.timeout=20
max.retry=3

subscription.yaml

maxTeamSize:
- free: 1
- premium: 10

Step-2 : Run the below ‘create configmap’ command on a minikube cluster :

kubectl create configmap app-config \
--from-literal=default.theme=dawn \
--from-literal=premium.theme=awesome \
--from-file=app.properties \
--from-file=SUBSCRIPTION=subscription.yaml

To view the ConfigMap run the below command.

 kubectl get configmaps app-config -o yaml

The output would look similar to :

apiVersion: v1
data:
  default.theme: dawn
  premium.them: awesome
  app.properties: |
    email=test@spectrums.com
    session.timeout=20
    max.retry=3
  SUBSCRIPTION: |
    maxTeamSize:
    - free: 1
    - premium: 10
kind: ConfigMap
metadata:
  creationTimestamp: "2020-06-27T14:16:09Z"
  name: my-app-config
  namespace: default
  resourceVersion: "473"
  selfLink: /api/v1/namespaces/default/configmaps/my-app-config
  uid: 0d7f0e55-8a9c-4937-88dc-44ecf219fe59
  • We can see the generated ConfigMap has two key-value literals and two files.
  • For the first file the file-name, app.properties is the key
  • For the second one the default file name key has been modified with the specified key ‘SUBSCRIPTION

Summary of the ‘create configmap’ data parameters

  • We have used from-literal , from-file in our example and we can also use:
  • from-env-file : For each entry in the file content to create a literal key-value pair.
  • from-directory: Useful to include all the files in a directory, without using form-file multiple times.

 

Importing ConfigMap into a Pod

1. Import ConfigMap as Env Variables

app-config.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: app-config
  namespace: default
data:
  DEFAULT_THEME: dawn
  PREMIUM_THEME: awesome
  test.properties: |
    free.team.size=1
    premium.team.size=10

test-config-pod.yaml

apiVersion: v1
kind: Pod
metadata:
  name: test-config-pod
spec:
  containers:
    - name: test-container
      image: k8s.gcr.io/echoserver:1.4
      envFrom:
      - configMapRef:
          name: app-config

The highlighted lines in test-config-pod.yaml, says to import all data in ‘app-config’ ConfigMap as environment variables.

Step-1 : Create the above two files, start minikube and run the below two commands in sequence.

kubectl apply -f  app-config.yaml
kubectl apply -f  test-config-pod.yaml

Step-2 : Login to container bash and print the environment variables:

kubectl exec -it test-config-one -- /bin/bash

printenv

The output should show the configmap related environment variables as below:

#For literal data : literal-key is set as key and literal-value is set as value 
DEFAULT_THEME=dawn
PREMIUM_THEME=awesome

#For files : file name is the key and file content is set as value
test.properties=free.team.size=1
   premium.team.size=10
Observations from the above test:
  • It imports each literal is as a separate env variable
  • It imports each file as a separate env variable, with its content set as its value.
    • The files content, does not create any environment variable of its own.
How to import a specific key ?

The above example reads all the keys from a configmap. It’s comparison of the syntax to read a specific key is as shown below:

envFrom:
  - configMapRef:
        name:[ConfigMap Name]

env:
  - name: MY_ENV_KEY
    valueFrom:
        configMapKeyRef:
              name: [ConfigMap Name]
              key: [Literal's Key]
2. Import into POD Volume as Linked Files

Let us use the same ConfigMap example file app-config.yaml from the previous section and now import it to a pod using volume as shown below.

apiVersion: v1
kind: Pod
metadata:
  name: test-config-vol-pod
spec:
  containers:
    - name: test-container
      image: k8s.gcr.io/echoserver:1.10
      volumeMounts:
      - name: config-volume
        mountPath: /config
  volumes:
    - name: config-volume
      configMap:
        name: app-config

Deploy the pod and as the pod is running go to the container mount path :

#Deploy the pod
kubectl apply -f pod.yaml

#Once the pod is running , move to the mount path
$ kubectl exec -it test-config-vol-pod -- /bin/bash
root@test-config-vol-pod: cd config
Analysis of the imported linked files

1. The literal-keys and the file-names(or file-name keys) shows up as linked files.

root@test-config-vol-pod:/config# ls
DEFAULT_THEME  PREMIUM_THEME  TEST_FILE_KEY  test.properties

2. For literal-keys, the file has the ‘literal-value’ as its content.

root@test-config-vol-pod:/config# cat DEFAULT_THEME
dawn
root@test-config-vol-pod:/config# cat PREMIUM_THEME
awesome

3. For linked files, the content is the original file content.

root@test-config-vol-pod:/config# cat TEST_FILE_KEY
free.team.size=1
premium.team.size=10

root@test-config-vol-pod:/config# cat test.properties
free.team.size=1
premium.team.size=10
How to import a specific file or a literal ?

If we want to import a specific file or literal, we can use items.key as below:

  volumes:
    - name: config-volume
      configMap:
        name: app-config
        items:
        - key: DEFAULT_THEME
          path: DEFAULT_THEME_PATH

With a mount path as /config , the linked file would be available at:

config/DEFAULT_THEME_PATH

Conclusion

ConfigMap provides an elegant solution to store and share application configurations in a distributed K8s cluster environment.

  • We use this to manage non-confidential configuration data.
  • These are never saved on any external storage and imported configmap get deleted as the Pod or the container is deleted.
  • Secret is the other counter part which works in a similar way to address confidential data.