Categories
Best Practices DevOps Orchestration

Kubernetes ConfigMaps Demo

Kubernetes ConfigMaps provide Kubernetes Pods with configuration information. How to create and use ConfigMaps? What are Kubernetes ConfigMaps concepts? Keep reading to find out.

Introduction

As we mentioned already, ConfigMaps is a way to inject configuration data into pods containers. Why is it needed? Mainly, for separation of configuration from an app. It allows developers to develop apps on a development environment with a certain configuration (e.g. local dependencies, environment variables). Then we can deploy an app to a staging environment with a different configuration, but the same code. And so on to production. If you are familiar with ConfigMaps you may want to jump to ConfigMaps real-world demo. For introduction to ConfigMaps keep reading.

How to create ConfigMaps

You can create ConfigMaps using:

  • command-line args (using kubectl)
  • ConfigMap manifest

After creation, you can associate ConfigMap to pod containers. The pod and ConfigMap must be in the same namespace.

Note that pods scaled on other nodes in the cluster get the same configuration. It’s because ConfigMap is Kubernetes API object.

How to use ConfigMaps in a Pod

ConfigMaps can be injected to a pod’s containers using:

Of course, you can use ConfigMap inside a container by accessing Kubernetes API. In addition, container command can access it as well.

Kubernetes ConfigMaps Demo

Demo Prerequisites

Install on your machine:

  • minikube
  • kubectl
  • scaffold

ConfigMaps basic kubectl CRUD commands

As always, let’s start Kubernetes cluster using minikube:

minikube start --profile custom

Be aware that you have to run eval $(minikube -p custom docker-env) in every terminal you want to run kubectl against minikube cluster we started.

Creating ConfigMap using kubectl out of environment file

Now, let’s create ConfigMap from .env file. We’ll use one from jenkins-monitoring repository from my GitHub.

$ kubectl create configmap jenkins-monit-env --from-env-file=.env
configmap/jenkins-monit-env created

To view ConfigMap contents run:

$ kubectl get cm jenkins-monit-env -o yaml
apiVersion: v1
data:
  JENKINS_PASSWORD: admin
  JENKINS_USERNAME: admin
kind: ConfigMap
metadata:
  creationTimestamp: "2022-01-04T20:18:16Z"
  name: jenkins-monit-env
  namespace: default
  resourceVersion: "16802"
  uid: b19cee74-cef6-4681-a513-f871ee5c5a79

Creating ConfigMap using kubectl using manifest file

We also can create ConfigMap from manifest files similar to other Kubernetes resources like pods, deployments, services, etc…

For that purpose, copy ConfigMap contents we have just created while copying just metadata name and namespace. Modify name and save it to a file called /tmp/cm.yaml.

Its contents should like like below:

apiVersion: v1
data:
  JENKINS_PASSWORD: admin
  JENKINS_USERNAME: admin
kind: ConfigMap
metadata:
  name: jenkins-monit
  namespace: default
                                                                                                                                                                                                                                                                                               

Now, run $ kubectl apply -f /tmp/cm.yaml and we can see another ConfigMap created.

$ kubectl apply -f /tmp/cm.yaml 
configmap/jenkins-monit created

ConfigMaps real-world demo

Let’s now raise a sample app – Jenkins in Kubernetes. We’ll configure Jenkins credentials using ConfigMap. For that purpose we’ll inject Jenkins credentials as environment variables. First, clone docker_in_jenkins repository from my GitHub and cd into it. We have already seen it in Kubernetes Volumes Introduction.

Next, start minikube cluster, initialize skaffold and run the app.

minikube start --profile custom
skaffold config set --global local-cluster true
# run below in any new terminal to cause kubectl commands be configured to run against minikube cluster
eval $(minikube -p custom docker-env)
# run the app
skaffold run

Use specific ConfigMap key-value pairs in pod environment

Note that we have env-configmap.yaml manifest inside the project folder:

apiVersion: v1
data:
  JENKINS_PASSWORD: admin
  JENKINS_USERNAME: admin
kind: ConfigMap
metadata:
  creationTimestamp: null
  labels:
    io.kompose.service: jenkins-env
  name: env

We use this ConfigMap to configure Jenkins admin username and password. data key-value pairs become environment variables inside Jenkins container.

To see the actual ConfigMap created in our cluster run kubectl get cm env -o yaml:

apiVersion: v1
data:
  JENKINS_PASSWORD: admin
  JENKINS_USERNAME: admin
kind: ConfigMap
...

Where’s it used? Right. In Deployment manifest – jenkins-deployment.yaml in pod template. We inject ConfigMap values one by one:

        - env:
            - name: JENKINS_PASSWORD
              valueFrom:
                configMapKeyRef:
                  key: JENKINS_PASSWORD
                  name: env
            - name: JENKINS_USERNAME
              valueFrom:
                configMapKeyRef:
                  key: JENKINS_USERNAME
                  name: env

Is it working? Of course! To make sure, first make Jenkins service accessible on localshost using kubectl port-forward svc/jenkins 8080:8080. Next, navigate to https://localhost:8080 and you should see Jenkins UI. Login as admin using admin password.

Moreover you can see container environment in the output of : kubectl describe deployments.apps/jenkins. You should see below output:

    Environment:
      JENKINS_PASSWORD:  <set to the key 'JENKINS_PASSWORD' of config map 'env'>  Optional: false
      JENKINS_USERNAME:  <set to the key 'JENKINS_USERNAME' of config map 'env'>  Optional: false

Inject the whole ConfigMap to pod environment

What if our ConfigMap has a lot of configuration key-value pairs and the app needs all of them. Is there a less verbose way for injecting the whole ConfigMap instead of injecting values one by one. Of course!

Use below syntax instead:

          envFrom:
          - configMapRef:                
              name: env

Run skaffold run to update the deployment, rerun port forwarding. Next, check that you can still login to Jenkins with the same credentials.

What if we need to inject configuration as configuration files? We can use Kuberentes volumes.

Inject Kubernetes ConfigMap to pods using volumes

We have seen in Kubernetes Volumes Introduction to store containers data on Kubernetes node. Here we want to inject configuration data into containers. How to do it? We’ll inject ConfigMap data using volumes.

Let’s add new volume under volumes

        - name: jenkins-credentials
          configMap:
            name: env

And mount it under volumeMounts

            - name: jenkins-credentials
              mountPath: /etc/credentials

Run skaffold run to update the deployment. Now, let’s inspect /etc/credentials inside Jenkins container.

kubectl exec -it pod/jenkins-589499fd74-gcwcp -- bash
[email protected]:/# ls /etc/credentials/
JENKINS_PASSWORD  JENKINS_USERNAME
[email protected]:/# cat /etc/credentials/JENKINS_PASSWORD 
admin

We see that each key in ConfigMap became the file name while the key’s value has become the file contents. Note, that Jenkins doesn’t use /etc/credentials path. I’m showing it for purely demo purposes. Yet, an app that needs to mount configuration and prefers to read it from a file could use this method.

Live reload of Kuberentes ConfigMap values inside the containers

Apps may want to mount ConfigMap using volumes to gain live-reload functionality of configuration. Let’s see this in action.

First modify JENKINS_PASSWORD in env-configmap.yaml to be password instead of admin

Then update env ConfigMap using kubectl apply -f env-configmap.yaml. Use kubectl get cm env -o yaml to make sure it’s updated.

Let’s now inspect the contents of JENKINS_PASSWORD inside Jenkins container:

[email protected]:/# cat /etc/credentials/JENKINS_PASSWORD 
password

Cool! Live reload works!

You may argue that sharing sensitive information like credentials should be done in a more secure way. Right! There are Kubernetes Secrets just for that. I’ll demo them in future posts.

Finally, stop our cluster.

$ minikube stop --profile custom

Summary

That’s it about Kubernetes ConfigMaps. As always, feel free to share and comment.

Bonus:

Recommended Kubernetes courses on Pluralsight:

Sign up using this link to get exclusive discounts like 50% off your first month or 15% off an annual subscription)

Recommended Kubernetes books on Amazon:

Leave a Reply

Your email address will not be published. Required fields are marked *