Table of contents
No headings in the article.
Hello folks!
Today, I am going to talk about and implement ConfigMaps and Secrets in Kubernetes.
In this article, I have discussed
ConfigMaps and Secrets in layman language
Created a ConfigMap and set it in the pod at environment variable level
Created a ConfigMap and mounted it in the pod using volume mounts
Created a Secrets file and mounted it in the pod using volume mounts.
Lets dive in straight to the topic:
ConfigMaps
In a Kubernetes cluster, different applications need to talk to each other. For example: There is a backend application that needs to talk to the DB to retrieve information and provide it back to the user.
For retrieving information, the application needs to have certain info such as port, password for DB. This cannot be hardcoded as there is a possibility, it might be changed by DB admins at certain points.
For this reason, all the information for communication must be stored in configMaps or secrets and the configMap needs to be mounted to the pod, so that the pod can retrieve the information from the file.
Secrets
If this is the case, then what is the use of secrets?
Secrets store sensitive information such as ID, passwords in the encrypted format so that this data is secure and not accessible by hackers at the etcd level or using kubectl describe or edit.
Hands-on:
Lets check for any open deployments:
kubectl get deploy
There are no current deployments present.
Lets create a ConfigMap first named cm.yml
vim cm.yml
Type the following in the cm.yml file :
apiVersion: v1
kind: ConfigMap
metadata:
name: test-cm
data:
db-port: "3306"
No need to remember it as you can get the format on kubernetes official documentation website.
Now create it using:
kubectl apply -f cm.yml
ConfigMap file is now created. Check it using
kubectl get cm
test-cm is the congfigmap that we created just now.
You can check the contents using
kubectl describe cm test-cm
This is the configmap that I created.
Now my aim will be to use the fields containing port data from configmap and use them as environment variables inside my Kubernetes pod. For that we will need to create a pod.
We already have a Python Django application that we are using from the public Github Repo: https://github.com/iam-veeramalla/Docker-Zero-to-Hero.git
Lets create a deployment file now
vim deployment.yml
We will just use the deployment format from Kubernetes official documentation and edit the fields according to our app
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-python-app
labels:
app: sample-python-app
spec:
replicas: 2
selector:
matchLabels:
app: sample-python-app
template:
metadata:
labels:
app: sample-python-app
spec:
containers:
- name: python-app
image: abhishekf5/python-sample-app-demo:v1
ports:
- containerPort: 8000
Lets create the deployment for the following
kubectl apply -f deployment.yml
Now, that the pod is up and running lets exec into the pod and check for env variables -
We cannot see any env variables as it does not have information of any database port. But, I want to know the port of db.
For that I have to edit the deployment.yml file and modify it.
We need to provide something called as env so it reads the value as environment variable -
For this, make the following changes in deployment.yml file:
Below image tag, add the following
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-python-app
labels:
app: sample-python-app
spec:
replicas: 2
selector:
matchLabels:
app: sample-python-app
template:
metadata:
labels:
app: sample-python-app
spec:
containers:
- name: python-app
image: abhishekf5/python-sample-app-demo:v1
env:
- name: DB-PORT
valueFrom:
configMapKeyRef:
name: test-cm
key: db-port
ports:
- containerPort: 8000
In this, we have added the env variable in which we have specified -
valueFrom: It will take the required value from
configMapKeyRef: Specify the details of the configmap configured
name: Name of the configmap
key: Inside the configmap, the key to which value is defined.
Now, again re-apply the deployment file so that it is configured.
kubectl apply -f deployment.yml
Now lets check again whether we can find the DB port inside the pod.
kubectl exec -it <pod_name> -- /bin/bash
Once inside the pod -
env | grep DB
Now we can see the port -
But in this case, if we change the port in the cm.yml file, the container will not take the new port but continue using the port specified as containers cannot be given new ports one they are assigned before, which will lead to failure connecting to the DB.
Hence, the approach of Volume Mounts is used.
To implement this open the deployment.yml file again, remove the env mounts and make the following changes:
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-python-app
labels:
app: sample-python-app
spec:
replicas: 2
selector:
matchLabels:
app: sample-python-app
template:
metadata:
labels:
app: sample-python-app
spec:
containers:
- name: python-app
image: abhishekf5/python-sample-app-demo:v1
volumeMounts:
- name: db-connection
mountPath: /opt
ports:
- containerPort: 8000
volumes:
- name: db-connection
configMap:
name: test-cm
kubectl get pods
Now to check whether the defined DB port is present inside the pod -
kubectl exec -it <pod-name> -- /bin/bash
Since, in the volume format, ConfigMap is present inside file systems.
Now lets try to change the port number in the ConfigMap file.
vim cm.yml
We have changed the port to 3307. Now lets re-apply the cm.yml file.
kubectl apply -f cm.yml
Now, lets exec into the pod and without re-running it and check whether the port number has changed.
kubectl exec -it <pod-name> -- /bin/bash
Now when inside the pod,
cat /opt/db-port | more
Thus, the port has changed from 3306 to 3307.
Now lets check how to configure secrets -
Another way of creating config files or secrets is using create command. Lets create a secret using the same -
kubectl create secret generic test-secret --from-literal=db
Since it is a secret and is designed to hold sensitive information, it will not show the info when asked to describe. Lets try to edit the secrets file
kubectl edit secrets test-secret
You can see that the db-port that is specified as a secret is shown in base 64 encrypted format. But base 64 encryption is not that great, so we can encrypt in our own way.
As base 64 encryption can be easily decoded using
echo MzMwNg== | base64 --decode
It will give value as 3306. Hence Kubernetes does not provide great encryption and hence we can use other apps or vaults for encryption.
So for mounting it in the pod, go to the deployment.yml file
Add the secrets to volume and volume mounts as shown below
vim deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-python-app
labels:
app: sample-python-app
spec:
replicas: 2
selector:
matchLabels:
app: sample-python-app
template:
metadata:
labels:
app: sample-python-app
spec:
containers:
- name: python-app
image: abhishekf5/python-sample-app-demo:v1
volumeMounts:
- name: db-connection
mountPath: /opt
- name: db-secrets
readOnly: true
mountPath: /opt/secrets
ports:
- containerPort: 8000
volumes:
- name: db-connection
configMap:
name: test-cm
- name: db-secrets
secret:
secretName: test-secret
As you can see, we have added the db-secrets in volumes and stored the secrets in /opt/secrets.
Lets check whether it is present in /opt/secrets
kubectl exec -it <pod-name> -- /bin/bash
Inside the pod,
cat /opt/secrets/db-port
It will show the secret stored in the pod.