Kubernetes has resource types that allows to decouple application code from configuration. It makes the applications to be more portable. This chapter will cover how ConfigMap and Secrets can be used to do that.
-
ConfigMap is just a set of key-value pairs. It allow you to decouple configuration artifacts from image content.
-
Secrets allows separating sensitive information such as credentials and keys from an application.
ConfigMap is similar to Secrets, but provides a means of working with strings that don’t contain sensitive information.
This section will explain how to use ConfigMap and Secrets.
A 3 master nodes and 5 worker nodes cluster as explained at ../cluster-install#multi-master-multi-node-multi-az-gossip-based-cluster is used for this chapter.
All configuration files for this chapter are in the config-secrets
directory.
This section will explain:
-
Pass configuration information to a Pod
-
Define environment variables in a Pod using ConfigMap
Create a ConfigMap:
$ kubectl apply -f ./templates/redis-configmap.yaml configmap "redis-config" created
redis-configmap.yaml
is a standard resource configuration file. It defines the configuration information as:
data: redis-config: | maxmemory=2mb maxmemory-policy=allkeys-lru
The configuration data is stored in the main key data
. redis-config
is an attribute inside this key where the configuration information for the Redis pod is defined as key-value pairs.
Get the list of ConfigMaps:
$ kubectl get configmap NAME DATA AGE redis-config 1 14s
Get more details about the created ConfigMap:
$ kubectl get configmap/redis-config -o yaml
apiVersion: v1
items:
- apiVersion: v1
data:
redis-config: |
maxmemory 2mb
maxmemory-policy allkeys-lru
kind: ConfigMap
metadata:
creationTimestamp: 2017-10-22T18:38:27Z
labels:
k8s-app: redis
name: redis-config
namespace: default
resourceVersion: "302238"
selfLink: /api/v1/namespaces/default/configmaps/redis-config
uid: 316309d0-b758-11e7-8c3f-06329c8974cc
kind: List
metadata:
resourceVersion: ""
selfLink: ""
The configuration information is shown as key/value pairs in the data
key.
We created a ConfigMap using a resource configuration file. Other ways to create ConfigMap are listed below:
Note
|
These ConfigMaps are using the exact same name as the one previously created. If you like to try the commands, then you either need to give a different name to the ConfigMap or delete the previously created ConfigMap using the command kubectl delete -f ./templates/redis-configmap.yaml .
|
-
kubectl create configmap --from-literal=<key>:<value>
. Multiple--from-literal=<key>:<value>
options can be used to define different key/value pairs. For example:$ kubectl create configmap redis-config --from-literal=maxmemory=2mb --from-literal=maxmemory-policy=allkeys-lru configmap "redis-config" created
More details about the ConfigMap can be obtained as:
$ kubectl get configmap/redis-config -o yaml apiVersion: v1 data: maxmemory: 2mb maxmemory-policy: allkeys-lru kind: ConfigMap metadata: creationTimestamp: 2017-10-22T15:29:31Z name: redis-config namespace: default resourceVersion: "287452" selfLink: /api/v1/namespaces/default/configmaps/redis-config uid: cccf20b7-b73d-11e7-8c3f-06329c8974cc
-
kubectl create configmap redis-config --from-file=<properties file>
where<properties file>
is a property file with key/value pairs. For example,templates/redis-config
looks like:maxmemory 2mb maxmemory-policy allkeys-lru
And now the ConfigMap can be created as:
$ kubectl create configmap redis-config --from-file=templates/redis-config configmap "redis-config" created
More details about the ConfigMap can be obtained as:
$ kubectl get configmap/redis-config -o yaml apiVersion: v1 data: redis-config: | maxmemory=2mb maxmemory-policy=allkeys-lru kind: ConfigMap metadata: creationTimestamp: 2017-10-22T15:56:08Z name: redis-config namespace: default resourceVersion: "289533" selfLink: /api/v1/namespaces/default/configmaps/redis-config uid: 84901162-b741-11e7-8c3f-06329c8974cc
The filename becomes a key stored in the data section of the ConfigMap. The file contents become the key’s value.
At the end of this section, you’ll have created a ConfigMap redis-config
.
A ConfigMap must be created before referencing it in a Pod specification (unless you mark the ConfigMap as “optional”). If you reference a ConfigMap that doesn’t exist would , the Pod won’t start.
Let’s use redis-config
ConfigMap to create our redis.conf
configuration file in the pod redis-pod
. It maps the ConfigMap to the volume where the configuration resides:
$ kubectl apply -f ./templates/redis-pod.yaml pod "redis-pod" created
Wait for the pod to run:
$ kubectl get pods NAME READY STATUS RESTARTS AGE redis-pod 1/1 Running 0 12m
Check logs from the pod to verify that Redis has started:
$ kubectl logs redis-pod _._ _.-``__ ''-._ _.-`` `. `_. ''-._ Redis 2.8.19 (00000000/0) 64 bit .-`` .-```. ```\/ _.,_ ''-._ ( ' , .-` | `, ) Running in stand alone mode |`-._`-...-` __...-.``-._|'` _.-'| Port: 6379 | `-._ `._ / _.-' | PID: 6 `-._ `-._ `-./ _.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | http://redis.io `-._ `-._`-.__.-'_.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' `-._ `-.__.-' _.-' `-._ _.-' `-.__.-'
[6] 22 Oct 18:39:45.386 # Server started, Redis version 2.8.19 [6] 22 Oct 18:39:45.386 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled. [6] 22 Oct 18:39:45.386 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128. [6] 22 Oct 18:39:45.386 * The server is now ready to accept connections on port 6379
Validate that your redis cluster picked up the appropriate configuration:
$ kubectl exec redis-pod -it redis-cli 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" 127.0.0.1:6379> quit
You should see the same values that were specified in ./templates/redis-configmap.yaml
outputted in the above commands.
Now, changing the pod configuration would involve the following steps:
-
Edit
redis-configmap.yaml
-
Update the ConfigMap using the command:
kubectl apply -f templates/redis-configmap.yaml
-
Wrap the pod in a Deployment
-
Terminate the pod, Deployment will restart the pod and pick up new configuration
The data from ConfigMap can be used to initialize environment variables in a pod. We’ll use arungupta/print-hello
image to print “Hello World” on the console. The number of times this message is printed is defined by an environment variable COUNT
. This value of this variable is defined in the ConfigMap.
-
Create a ConfigMap:
$ kubectl create configmap hello-config --from-literal=COUNT=2 configmap "hello-config" created
-
Get more details about this ConfigMap:
$ kubectl get configmap/hello-config -o yaml apiVersion: v1 data: COUNT: "2" kind: ConfigMap metadata: creationTimestamp: 2017-10-26T21:40:10Z name: hello-config namespace: default resourceVersion: "92516" selfLink: /api/v1/namespaces/default/configmaps/hello-config uid: 3dacb22f-ba96-11e7-ab9c-123f969a2ce2
-
Use this ConfigMap to create a pod:
$ kubectl apply -f templates/app-pod.yaml pod "app-pod" created
The pod configuration file looks like:
apiVersion: v1 kind: Pod metadata: labels: name: app-pod name: app-pod spec: containers: - name: app image: arungupta/print-hello:latest env: - name: COUNT valueFrom: configMapKeyRef: name: hello-config key: COUNT ports: - containerPort: 8080
-
Observe logs from the pod:
$ kubectl logs -f app-pod npm info it worked if it ends with ok npm info using [email protected] npm info using [email protected] npm info lifecycle [email protected]~prestart: [email protected] npm info lifecycle [email protected]~start: [email protected]
> [email protected] start /usr/src/app > node server.js
Running on http://0.0.0.0:8080
-
In a new terminal, expose the pod as a Service:
$ kubectl expose pod app-pod --port=80 --target-port=8080 --name=app service "app" exposed
-
Start Kubernetes proxy:
kubectl proxy
-
In a new terminal, access the service as:
$ curl http://localhost:8001/api/v1/proxy/namespaces/default/services/app/ printed 2 times
The pod logs are refreshed as well:
Hello world 0 Hello world 1
-
Edit the ConfigMap:
$ kubectl edit configmap/hello-config
-
Change the value to
4
-
Terminate the pod:
$ kubectl delete pod/app-pod pod "app-pod" deleted
-
Run the pod again:
kubectl create -f templates/app-pod.yaml pod "app-pod" created
-
Access the service again:
curl http://localhost:8001/api/v1/proxy/namespaces/default/services/app/ printed 4 times
-
Logs from the pod are refreshed:
Hello world 0 Hello world 1 Hello world 2 Hello world 3
In this section we will demonstrate how to place secrets into the Kubernetes cluster and then show multiple ways of retrieving those secretes from within a pod.
First encode the secrets you want to apply, for this example we will use the username admin
and the password password
echo -n "admin" | base64 echo -n "password" | base64
Both of these values are already written in the file ./templates/secret.yaml
. The configuration looks like:
apiVersion: v1
kind: Secret
metadata:
name: mysecret
type: Opaque
data:
username: YWRtaW4=
password: cGFzc3dvcmQ=
You can now insert this secret in the Kubernetes cluster with the following command:
kubectl apply -f ./templates/secret.yaml
The list of created secrets can be seen as:
$ kubectl get secrets NAME TYPE DATA AGE default-token-4cqsx kubernetes.io/service-account-token 3 8h mysecret Opaque 2 6s
The values of the secret are displayed as Opaque
.
Get more details about the secret:
$ kubectl describe secrets/mysecret Name: mysecret Namespace: default Labels: <none> Annotations: <none>
Type: Opaque
Data ==== password: 8 bytes username: 5 bytes
Once again, the values of the secret are not shown.
Deploy the pod:
kubectl apply -f ./templates/pod-secret-volume.yaml
The pod configuration file looks like:
apiVersion: v1 kind: Pod metadata: name: pod-secret-volume spec: containers: - name: pod-secret-volume image: redis volumeMounts: - name: foo mountPath: "/etc/foo" readOnly: true volumes: - name: foo secret: secretName: mysecret
Open a shell to the pod to see the secrets:
kubectl exec -it pod-secret-volume /bin/bash ls /etc/foo cat /etc/foo/username ; echo cat /etc/foo/password ; echo
The above commands should result in the plain text values, the decoding is done for you.
Delete the pod:
kubectl delete -f ./templates/pod-secret-volume.yaml
Deploy the pod:
kubectl apply -f ./templates/pod-secret-env.yaml
The pod configuration file looks like:
apiVersion: v1 kind: Pod metadata: name: pod-secret-env spec: containers: - name: pod-secret-env image: redis env: - name: SECRET_USERNAME valueFrom: secretKeyRef: name: mysecret key: username - name: SECRET_PASSWORD valueFrom: secretKeyRef: name: mysecret key: password restartPolicy: Never
Open a shell to the pod to see the secrets:
kubectl exec -it pod-secret-env /bin/bash echo $SECRET_USERNAME echo $SECRET_PASSWORD
The above commands illustrate how to see the secret values via environment variables.