ConfigMap
ConfigMap
By the end of this lab, you will be able to
- Create and attach ConfigMaps for pods
Working with ConfigMaps (CM)
A ConfigMap
is a cluster API object used to store non-confidential data in key-value pairs.
A config map can source application configuration data in variety through a variety of methods.
In this lab section, we will examine how the ConfigMap
object can present such data to a containerized application
running in a pod.
ConfigMap Data in a Volume
In the following steps, we will configure NGINX to run as reverse-proxy for our custom web application, which is set to
run on TCP port 5000
. In order to do so, we will need to supply the NGINX container with a custom configuration.
In our case, we will provide the configuration through a custom configuration file to be mounted into the NGINX
container.
Step 1: Make and move to the ~/configMap/
directory:
mkdir ~/configMap ; cd ~/configMap
Step 2: Define the following ConfigMap
in the file ~/configMap/cm-nginx-conf.yaml
:
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-nginx-conf
data:
nginx.conf: |-
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
upstream webapp {
server 127.0.0.1:5000;
}
server {
listen 80;
location / {
proxy_pass http://webapp;
proxy_redirect off;
}
}
}
In this YAML declartion, we specify both the file name and the configuration data of the file to be stored within the
ConfigMap
object.
Step 3: Create the cm-nginx-conf
Config Map:
kubectl create -f cm-nginx-conf.yaml
configmap/cm-nginx-conf created
Step 4: Confirm that the ConfigMap
was created successfully:
kubectl describe configmap cm-nginx-conf
Name: cm-nginx-conf Namespace: default Labels: <none> Annotations: <none> Data ==== nginx.conf: ---- user nginx; worker_processes 1; ....
As we can see from the output, the entire contents of the nginx.conf
is stored in our config map. Our next step is
present this file to our nginx container.
Step 5: Define the following multi-container pod in the file: ~/configMap/mc2.yaml
:
apiVersion: v1
kind: Pod
metadata:
name: mc2
labels:
app: mc2
spec:
containers:
- name: webapp
image: training/webapp
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
volumeMounts:
- name: nginx-proxy-config
mountPath: /etc/nginx/nginx.conf
subPath: nginx.conf
volumes:
- name: nginx-proxy-config
configMap:
name: cm-nginx-conf
Note: Although port
80
for the NGINX container is explicitly defined to be exposed to traffic outside the pod, port 5000 is accessible outside of the pod as well. By default, any port which is listening on the default0.0.0.0
IP address inside a container will be accessible from the pod network.
Step 6: Create the mc2
pod:
kubectl create -f mc2.yaml
pod/mc2 created
Step 7: Check on the status of the pod, specifically ensuring that the config map is mounted correctly:
kubectl describe pod mc2
Name: mc2 Namespace: default Priority: 0 Node: node2/10.10.8.196 .... Containers: .... nginx: .... Mounts:@g@ /etc/nginx/nginx.conf from nginx-proxy-config (rw,path="nginx.conf")@/g@ .... Volumes:@g@ nginx-proxy-config: Type: ConfigMap (a volume populated by a ConfigMap) Name: mc2-nginx-conf@/g@ .....
From our abbreviated output, we can confirm that our ConfigMap
object is mounted as a volume in the nginx container.
As such, we can expect our nginx container to redirect incoming traffic on port 80 to the localhost on port 5000
.
Step 8: Get IP of mc2 pod using this command:
kubectl get pod mc2 -o jsonpath='{.status.podIP}{"\n"}'
Take note of the pod’s IP and try to curl
using a temporary pod:
kubectl run curl --image=radial/busyboxplus:curl --rm -it
Now you’re inside a temporary pod, try to curl
the mc2
pod using its IP:
curl 10.244.107.183 # Use the IP of your pod you got earlier
Hello world!
Well done! If you see Hello world
, it means that your app works correctly and your configMap
is good.
Step 9: Delete the mc2
pod:
kubectl delete pod mc2
pod "mc2" deleted
ConfigMap Data via Environment Variables
In this next lab section, we will configure a redis
pod using a ConfigMap
object that injects configuration data as
environment variables for the redis
application along with supplying command line arguments to the pod startup
script. In the following exercises, we will examine implementing two types of ConfigMap
object data to a pod to
illustrate how containerized application can consume data from a ConfigMap
object.
Step 1: Define the following ConfigMap
in the file ~/configMap/redis-dev-cm.yaml
:
apiVersion: v1
kind: ConfigMap
metadata:
name: redis-dev-config
data:
empty_password: "yes"
maxmemory: 2mb
maxmemory-policy: allkeys-lru
In this ConfigMap
we are setting our values for the redis instance to not require a password for making changes along
with configuring redis to run 2 MB of memory, effectively making it run as a caching server. Let’s configure our pod to
use this ConfigMap
Step 2: Create the redis-dev-config
config map:
kubectl create -f redis-dev-cm.yaml
configmap/redis-dev-config created
With our ConfigMap
created, we can now work on our redis
pod.
Step 3: Define the following redis
pod in the file ~/configMap/redis-dev-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: redis-dev
labels:
env: dev
spec:
containers:
- name: redis
image: bitnami/redis:6.0
command:
- /opt/bitnami/scripts/redis/run.sh
- --maxmemory $(MAX_MEMORY)
- --maxmemory-policy $(MAX_MEMORY_POLICY)
env:
- name: ALLOW_EMPTY_PASSWORDS
valueFrom:
configMapKeyRef:
name: redis-dev-config
key: empty_password
- name: MAX_MEMORY
valueFrom:
configMapKeyRef:
name: redis-dev-config
key: maxmemory
- name: MAX_MEMORY_POLICY
valueFrom:
configMapKeyRef:
name: redis-dev-config
key: maxmemory-policy
Take a moment to review YAML above. In it, we are providing environment variables that are provided to the application
in two different ways. The intialization scripts of the redis container refers to the ALLOW_EMPTY_PASSWORDS
variable
to configure the redis instance with no admin password, which is suitable for testing. However, the MAX_MEMORY
and
MAX_MEMORY_POLICY
variables will need to be supplied to shell script as specfied by the documentation. In this case,
the specfic syntax within the command:
field is how we pass our ConfigMap
data to our application via the command
line.
Step 4: Create the redis-dev
pod:
kubectl create -f redis-dev-pod.yaml
pod/redis-dev created
Step 5: With the pod created, confirm that the ConfigMap
data was injected into the redis instance correctly:
kubectl exec -it redis-dev -- redis-cli
127.0.0.1:6379> CONFIG GET requirepass 1) "requirepass" 2) "" 127.0.0.1:6379> CONFIG GET maxmemory 1) "maxmemory" 2) "2097152" 127.0.0.1:6379> CONFIG GET maxmemory-policy 1) "maxmemory-policy" 2) "allkeys-lru"
From our output, we can see that configuration from our ConfigMap
has configured our redis instance appropriately.
As this type of configuration is suitable for a testing or development environment, a follow-up question might be, what
about production? The response to the question about production is specific to the environment and requirements for
production; however, the key point to emphasize is that the application running in the pod would not have to be
changed. Rather just the configuration parameters would need to be updated. To illustrate this point, we will adjust
the configuration parameters we provided to the redis application, specifically:
- supplying an administrator password
- adjusting the Max Memory size
The way we will provide this configuration data will require changes to our current Kubernetes manifests.
Step 6: Make copies of the existing YAML files replacing dev
with prod
:
cp redis-dev-cm.yaml redis-prod-cm.yaml
cp redis-dev-pod.yaml redis-prod-pod.yaml
Step 7: Modify the redis-prod-cm.yaml
file with the following changes:
apiVersion: v1 kind: ConfigMap metadata: name: redis-prod-config data: redis_password: supersecret maxmemory: 100mb maxmemory-policy: allkeys-lru
Step 8: Modify the redis-prod-pod.yaml
file with the following changes:
apiVersion: v1 kind: Pod metadata: name: redis-prod labels: env: prod spec: containers: - name: redis image: bitnami/redis:6.0 command: - /opt/bitnami/scripts/redis/run.sh - --requirepass $(REDIS_PASSWORD) - --maxmemory $(MAX_MEMORY) - --maxmemory-policy $(MAX_MEMORY_POLICY) env: - name: REDIS_PASSWORD valueFrom: configMapKeyRef: name: redis-prod-config key: redis_password - name: MAX_MEMORY valueFrom: configMapKeyRef: name: redis-prod-config key: maxmemory - name: MAX_MEMORY_POLICY valueFrom: configMapKeyRef: name: redis-prod-config key: maxmemory-policy
As we are supplying a password, we need to amend the startup parameters to configure the password value.
The rest of the changes are in line with specifying the prod
value.
Step 9: With the YAML file changes complete, create the redis
cluster objects:
kubectl create -f redis-prod-cm.yaml -f redis-prod-pod.yaml
configmap/redis-prod-config created pod/redis-prod created
With our cluster objects created, we are ready to test our changes.
Step 10: Verify prod
configuration changes in the redis-prod
instance:
kubectl exec -it redis-prod -- redis-cli
127.0.0.1:6379> auth supersecret OK 127.0.0.1:6379> CONFIG GET requirepass 1) "requirepass" 2) "supersecret" 127.0.0.1:6379> CONFIG GET maxmemory 1) "maxmemory" 2) "104857600" 127.0.0.1:6379> CONFIG GET maxmemory-policy 1) "maxmemory-policy" 2) "allkeys-lru"
From the output, we can see that our configuration changes are in place for the redis-prod
instance.
Delete your two pods:
kubectl delete pod redis-dev redis-prod