A Pod is collection of containers running in shared namespace. A container is created from Docker/OCI Image, which is immutable in nature i.e. data bundled into the image cannot be changed later in image.
“While immutable image of application is great for security, but putting configurations & data like security keys is bad for security as well as portability”
There are various ways to pass data to application in containers, without changing the flow of application e.g. by setting environment variables or using volume mount to provide configuration file at the time of container creation.
In Kubernetes, ConfigMaps and Secrets are two objects using which configuration data can be passed to Pods and containers running within them.
In this blog, I will give you a walkthough of how to use ConfigMap and Secrets with a Pod.
ConfigMaps: “It allows you to decouple configuration artifacts from image content to keep containerized applications portable”
- It stores the data as key-value pairs, where value can be a string or entire content of file.
Creating ConfigMap
- Since ConfigMap is standard object of Kubernetes, it can be created using command
kubectl create configmap
as well askubectl apply
with ConfigMap definition file.
e.g. ConfigMap with two key-value pairs log=debug
& environment=test
$ kubectl create configmap testapp-pod-config --from-literal=log=debug --from-literal=environment=test
configmap/testapp-pod-config created
Literal values can be seen using with kubectl describe
command
$ kubectl describe configmap testapp-pod-config
Name: testapp-pod-config
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
environment:
----
test
log:
----
debug
Events: <none>
Simillarly, The ConfigMap can be created using files too.
e.g. creating a config map to store ha-proxy config stored in ./ha-proxy.cfg
file
$ kubectl create configmap ha-proxy-cfg --from-file=ha-proxy-cfg=ha-proxy-config.cfg
configmap/ha-proxy-cfg created
You may go through various examples of ConfigMap creation in Kubernetes documentation
How to use it with Pod?
ConfigMap data can be consumed in Pod broadly either as an environment variable or by mounting them as files in a container. Lets see in detail, how this is done.
1. Import all data as environment variable:
This is simplest form, where we will import all data present in a ConfigMap into the Pod as environment variable.
Use envFrom
& configMapRef
to import all. In the below example, I am importing all the key-value pairs of ConfigMaptestapp-pod-config
which we created above.
apiVersion: v1
kind: Pod
metadata:
name: testapp-pod
spec:
containers:
- name: testapp-container
image: docker.io/library/busybox:latest
command: ["/bin/sh","-c","env"]
envFrom:
- configMapRef:
name: testapp-pod-config
You can see below, both key-value pairs are now part of environment variables of Pod.
$ kubectl apply -f testapp-pod.yaml
pod/testapp-pod created
$ kubectl logs testapp-pod | grep -E -i -w 'log|environment'
environment=test
log=debug
Note
If you are looking at container environment variables first time, don’t get intimidated with list of environment variables list not related to your pod/container.
A list of all services that were running when a Container is created is available to that Container as environment variables.
2. Import selected keys as environment variables:
Sometimes, not all key-value pairs are required to be exposed to container especially when same ConfigMap is used by multiple Pods. In such cases, we can import selected keys to a container.
This can be done using env
, valueFrom
& configMapKeyRef
.
Below is example, where we import only log
key from test-pod-config
apiVersion: v1
kind: Pod
metadata:
name: testapp-pod-single-key
spec:
containers:
- name: testapp-container
image: docker.io/library/busybox:latest
command: ["/bin/sh","-c","env"]
env:
- name: "log-level"
valueFrom:
configMapKeyRef:
name: testapp-pod-config
key: "log"
You can see only log
key is imported and its renamed as log-level
as defined in above yaml file.
Hence while importing key wise, we can even rename the environment variables too.
$ kubectl apply -f example-single-config-pod.yaml
pod/testapp-pod-single-key created
$ kubectl logs testapp-pod-single-key | grep -E -i -w 'log|environment'
log-level=debug
Note
Since, env
and envFrom
are defined as list, environment list from multiple ConfigMaps can be imported.
3. Import as a volume:
This option is helpful, if the application bundled in the container needs to be configured using config file. We can mount the file to specific path within container.
For this, we need to first use ConfigMap as volume of Pod and then mount within the container.
In below example, a pod will mount the ConfigMap ha-proxy-cfg
.
apiVersion: v1
kind: Pod
metadata:
name: testapp-pod-mnt
spec:
volumes:
- name: ha-proxy-volume
configMap:
name: ha-proxy-cfg
containers:
- name: testapp-container
image: docker.io/library/busybox:latest
command: ["/bin/sh","-c","ls -l /etc/config/"]
volumeMounts:
- name: ha-proxy-volume
mountPath: "/etc/config"
You can see below, the key became filename and value assigned to key will be contents of file(not shown)
Using configMap
& just name
items, all the keys defined in ConfigMap will be mounted on provided mountPath
$ kubectl get configmaps
NAME DATA AGE
ha-proxy-cfg 1 20h
$ kubectl apply -f mount-file-example.yaml
pod/testapp-pod-mnt created
$ kubectl logs testapp-pod-mnt
total 0
lrwxrwxrwx 1 root root 19 Jan 29 05:17 ha-proxy-cfg -> ..data/ha-proxy-cfg
4. Import selected keys to volume.
Again similar to #2 case, selected keys can be imported within mounted volume.
This can be done by putting keys in volumes
section of Pod as shown below.
apiVersion: v1
kind: Pod
metadata:
name: testapp-pod-mnt-single
spec:
volumes:
- name: ha-proxy-volume-single
configMap:
name: ha-proxy
items:
- key: "ha-proxy-cfg"
path: ha-proxy.cfg
containers:
- name: testapp-container
image: docker.io/library/busybox:latest
command: ["/bin/sh","-c","ls -l /etc/config/"]
volumeMounts:
- name: ha-proxy-volume-single
mountPath: /etc/config
As you can see, the filename can be chosen in this case.
$ kubectl apply -f mount-single-file-example.yaml
pod/testapp-pod-mnt-single created
$ kubectl logs testapp-pod-mnt-single
total 0
lrwxrwxrwx 1 root root 19 Jan 29 05:48 ha-proxy.cfg -> ..data/ha-proxy.cfg
Note
Any changes to ConfigMap will be refletcted in volumes too. So this is helpful in cases where application bundled in containers can read changes and you dont need to create new pods to propagate the changes in configuration files
Interesting Facts:
Q. One question normally arise how big data can be stored in configMap.
A. Kubernetes do not put any hard limits on ConfigMap size, though it stores configMaps in etcd.
Etcd has hard limit to store value upto 1MB
Ref : https://github.com/kubernetes/kubernetes/issues/19781
That is all for using ConfigMaps in Pod.
Secrets are another object similar to ConfigMaps that is used to store data in encrypted form. Since this blog became quite long, so shall post about using Secrets in Pods in next blog.
Feel free to comment, if you find anything I missed, need to be corrected or can be added as Interesting Facts.