CKA Study notes - ConfigMaps and Secrets
Overview
Continuing with my Certified Kubernetes Administrator exam preparations I'm now going to take a look at ConfigMaps
and Secrets
.
ConfigMaps are a way to pass configuration to a Pod, or infact other parts of the system. For instance they can be used for configuring parts of a Kubernetes cluster.
The above lists the kube-system configmaps in my Kubernetes cluster.
Secrets are similar to ConfigMaps, but they are designed to hold smaller objects and meant to be used for sensitive data like passwords, tokens etc.
The reason for using ConfigMaps and Secrets is to keeping Configuration data separate from the Application code
Note #1: I'm using documentation for version 1.19 in my references below as this is the version used in the current (jan 2021) CKA exam. Please check the version applicable to your usecase and/or environment
Note #2: This is a post covering my study notes preparing for the CKA exam and reflects my understanding of the topic, and what I have focused on during my preparations.
Config maps
Kubernetes Documentation reference
Where secrets are meant to store sensitive data, ConfigMaps should only hold non-sensitive data. There's no secrecy or encryption offered with ConfigMaps
ConfigMaps are not meant to hold large data objects. The maximum size of a config map is 1 MiB.
As mentioned you can use ConfigMaps for holding Kubernetes configuration, but normally we'll come across or use them to hold data meant for use by Pods. A ConfigMap can for example hold a database host variable which your application code can use to know which database server to connect to in a dev/test/prod scenario.
Data is stored in ConfigMaps as key-value pairs. You can store data as data
fields or binaryData
fields where the data
field are designed to hold UTF-8 byte sequences while the binaryData
field holds binary data.
ConfigMaps can be used by a container inside a Pod in four different ways:
- Command and arguments inside a container(, set at runtime)
- Environment variables
- As a volume mounted for the container to read from
- Through the Kubernetes API
The fourth option requires you to write the logic yourself, but you are in more control of how to respond to any changes to the ConfigMaps. This allows you also to access ConfigMaps from different namespaces, whereas the first three options requires the ConfigMap to belong to the same namespace as the pod. The first three options are pushed to the Pod by the kubelet
at launch.
Create ConfigMaps
Creating a ConfigMap (configmaps can also be created imperatively with the kubectl create configmap
command) through a yaml file:
1apiVersion: v1
2kind: ConfigMap
3metadata:
4 name: configmap-name
5data:
6 configmap-key1: "some value"
7 some-key2: 123
8 some.properties: |
9 some.types: blue,green
10 some.key: 5
Example of a ConfigMap accessed as environment variables in a Pod:
1apiVersion: v1
2kind: Pod
3metadata:
4 name: config-map-demo
5spec:
6 containers:
7 - name: config-map-pod
8 image: nginx
9 env:
10 - name: MY_ENV_VARIABLE #Used inside the container
11 valueFrom:
12 configMapKeyRef:
13 name: configmap-name #Name of an existing configmap
14 key: configmap-key1 #A key from the specified configmap that we should use the value from
Example of a ConfigMap accessed as a volume mount:
1apiVersion: v1
2kind: Pod
3metadata:
4 name: config-map-volume-demo
5spec:
6 containers:
7 - name: config-map-volume
8 image: nginx
9 volumeMounts:
10 - name: my-volume
11 mountPath: "/etc/folder"
12 readOnly: true
13 volumes:
14 - name: my-volume
15 configMap:
16 name: configmap-name
If you want to mount multiple ConfigMaps you must mount multiple volumes. Since volumes are mounted to the pod they can be used by multiple containers inside the pod, but they would all need the volumeMounts to be able to access it.
One important difference between volume mounted ConfigMaps and environment variable mounted ConfigMaps is that the ConfigMaps mounted through a volume will be updated if changed. This happens on periodic syncs so it's not instant, but still, there are an update mechanism there through the kubelet. Environment variables do not update and requires a Pod restart to update. (reference)
Verify ConfigMap in Pod
To verify that our configmaps are available we'll take a look at our created pods
First with the environment variable example
1kubectl exec -it <pod-name> -- sh
2
3#inside shell
4echo $<my-env-variable-name>
And then our configmap mounted as a volume
1kubectl exec -it <pod-name> -- sh
2
3#inside shell
4ls /<path>
5
6cat /<path>/<configmap-key>
Notice since we specified the ConfigMap in the volume created in the pod it brings in all the key-value pairs in the ConfigMap.
Let's also test updating the ConfigMap and see the results inside the pod (again note that the configmaps are updated on a periodic sync and might take some time to reflect inside the pod)
1kubectl edit configmaps <config-map-name> #Ideally you'd edit the yaml file and re-apply that
2
3kubectl describe configmap <config-map-name>
4
5kubectl exec -it <pod-name> -- sh
6
7#inside pod
8cat /<path>/<config-map-key>
Secrets
Kubernetes Documentation reference
Now let's switch over to Secrets
which is a way to store sensitive configuration data.
By default you'll probably have a few secrets already configured in the cluster. Like the following example in the default namespace that refers to a service-account which is used to communicate with the kube-apiserver
1kubectl get secrets
2
3kubectl describe secret <secret-name>
Like a ConfigMap
a Secret is used in a Pod
by mounting it through a volume or specifying it as an environmental variable. A secret is also used by the kubelet
when pulling images for a Pod
The secrets are stored as key-value pairs, as they are in the case of ConfigMaps. We can specify the value as a data
and/or a stringData
field (technically all stringData fields are converted to a data field internally). Values in a data
field has to be a base64 encoded
string, whereas a stringData
field can hold arbitrary strings.
There are a few built-in secret types
available, where the Opaque
type is the default and what is used for arbitrary user-data. We can also specify custom types if needed. There's also types for service-accounts, certificates and more.
Create secret
Let's create a simple secret as an example
1kubectl create secret <secret-type> <secret-name>
We haven't specified any data in the secret so for now it's empty.
Let's recreate the secret with values from the commandline. For that we use the --from-literal
parameter
1kubectl create secret <secret-type> <secret-name> --from-literal=<key>=<value> --from-literal=<key2>=<value>
As we can see the actual values have been base64 encoded. Notice also that the secret-type is set to Opaque which is the default/generic.
Let's try to decode the password value. First we'll examine the yaml output of the secret, and then extract the .data.password
value and pipe it through a base64 decoder
1kubectl get secret my-secret -o yaml
2
3kubectl get secret my-secret -o jsonpath='{.data}'
4
5echo $(kubectl get secret my-secret -o jsonpath='{.data.password}' | base64 --decode )
As this shows, be careful with who can access the secrets in the cluster as it's fairly easy to retrieve the values.
Data can be added from a text file as well. We use the --from-file
parameter instead of the --from-literal
as we saw in the previous example.
1kubectl create secret <secret-type> <secret-name> --from-file=<key>=<value>
Note that in this example, we're only creating the password, but we could create the username as well and add it to the same secret
Secrets can of course also be created from a yaml (or json) file. Note that you have to add the data fields with base64 encoded values
1apiVersion: v1
2kind: Secret
3metadata:
4 name: <my-secret-name>
5type: Opaque
6data:
7 password: <base64-encoded-string>
Use secret in a Pod
Let's see how we can use a secret inside a Pod.
1apiVersion: v1
2kind: Pod
3metadata:
4 name: <my-name>
5spec:
6 containers:
7 - name: <my-name>
8 image: nginx
9 env:
10 name: <my-env-name>
11 valueFrom:
12 secretKeyRef:
13 name: <my-secret-name>
14 key: <key>
Now let's check if we have access to the secret inside our pod
1kubectl exec -it <pod-name> -- sh
We'll only look at an Environment variable example, but we could mount secrets as a volume as we did with our ConfigMaps earlier
ImagePullSecrets
Kubernetes Documentation reference
One very common use case for Secrets is storing the credentials needed to pull container images from registries like DockerHub etc. These can then be referenced in the imagePullSecrets
section in a Pod definition. (reference)
An image pull secret can also be assigned to a service account.(reference)
Summary
ConfigMaps and Secrets is a very important concept in Kubernetes as it allows us to decouple configuration and application code. This allows our applications to be used in many environments and clusters without having to change anything but the references to the configuration objects.
There's more to both ConfigMaps and Secrets than shown in this post. As mentioned in the start of this post I'm using this post as a way to reinforce studying for the CKA exam. Be sure to check out the documentation for more info