Providing config information to containers in Kubernetes
Secrets and configmaps allow passing information to containers, whether it is regular configuration or sensitive information. They can define individual pieces of information like a password or username, or be used to store more extensive information such as entire configuration files. There are multiple ways to set them up and provide them to the container, so I embraced using them because of the flexibility. Using them also made it easier for me to provide configuration to containers that I would have otherwise had to build a custom image for. With configmaps/secrets I could set up key config files or ENV variables in my deployments instead of baking those into an image.
Setting up a configmap with the help of ansible
I do most of my cluster configuration with ansible, so I will use an ansible configmap setup example, and then demonstrate different variations. The two plays are used to check for a configmap and then set it up if it does not exist.
- name: check if fileBeat configmap has already been created
k8s_facts:
api_version: v1
kind: ConfigMap
namespace: example
name: example-config
register: example_configmap
- name: Set up the configMap to hold my filebeat config
shell: "kubectl create configmap -n example example-config --from-file=/path/example_k8s.yml"
when: example_configmap.resources is not defined
The command for creating the configmap
In this case I am creating the configmap from a file. It is also possible to create them from directories (each file gets mapped to a key) or from multiple files by repeating the —from-file key. There is also a literal value option to do it all on the cli.
Files fed to the configmap are saved as data associated with keys
Configmaps can store multiple pieces of data or files. Each is saved/accessed as a key. In this example configmap, the key to the file would be the same as the name of the file, filebeat_k8s.yml, since no key was specified.
kubectl create configmap -n example example-config --from-file=/path/example_k8s.yml
Specify a key name
This command could also have been written like this to specify a key:
kubectl create configmap configname --from-file=keyname=/path/to/file.name
Creating a configmap with Multiple files constained
Reuse the —from-file argument, specify a different file and key.
kubectl create configmap configname --from-file=keyname=/path/to/file.name --from-file=keyname2=/path/to/otherfile
Using A directory with files in it as the source
The same —from-file argument it used, but it is going to look for all files in the directory, and add them all to the configmap with their names as the key for each.
kubectl create configmap configname --from-file=keyname=/path/to/dir/
You can also use literal values
Configmaps can be created from literal values provided on the cli.
kubectl create configmap configname --from-literal=key.path=value
Attaching the configmap to a deployment uses a volume
You can also use environment variables, but my experience is with using files so I will demonstrate that. You have to be aware of what key you gave to the item you want to attach.
Example of setting up configmap keys using a volume
name: - the name of the configmap you created.
key: - the key to the data you want to access from that configmap.
path: - the path to place the file at, which will be relative to the
path for the entire volume.
// Set up the configmap volume.
volumes:
- name: config
configMap:
defaultMode: 0600
name: example-config
items:
- key: example_k8s.yml
path: example.yml
- key: another_file.txt
path: another.txt
// Attach the configmap volume to a container in a deploy/daemonset/statefulset
volumeMounts:
- name: config
readOnly: true
mountPath: /etc/config
Given the above config, the file contained in the configmap would be mounted at /etc/config/filebeat.yml. I also added another key/path pair just to demonstrate that more than one key can be added. It would be found at /etc/config/another.txt in this example.
Setting up secrets for containers
Base64 format is preferred to avoid any character encoding problems. If you want to pass secrets directly, this will be the method to use.
echo -n 'username' | base64
echo -n 'randompassword' | base64
Creating a secret from a config file
This example uses the values from above base64 encoded as an example.
secret.yml:
apiVersion: v1
kind: Secret
metadata:
name: test-secret
namespace: default
data:
username: dXNlcm5hbWU
password: cmFuZG9tcGFzc3dvcmQ
Then use kubectl apply on this config file
kubectl apply -f /path/to/secret.yaml
Data in secrets is mapped to keys just like in configmaps
So there would be a username and password file in this case, each holding the respective pieces of data.
Secrets can also be created directly on the command line -
kubectl create secret generic test-secret --from-literal=username='nameforuser'
\--from-literal=password='cmFuZG9tcGFzc3dvcmQ'
Copy a secret from one namespace to another
They are namespace specific, so if you should happen to need to transfer them, this is how to go about doing that.
kubectl get secret -n default secretname --export -o yaml | \
kubectl apply -n othernamespace -f
Using secrets within a container
My preferred method is once again a volume and volumemount, but you could also set them up as environment variables. In this example I mount two separate secrets, on which has redis password, and the other which has a database username and password.
# The paths for each secrete are determined based on the volumeMounts.
# I used these paths for docker-compose kubernetes compatibility.
volumeMounts:
- name: db-cred
mountPath: /run/secrets/psdb
- name: redis-cred
mountPath: /run/secrets/redis
# If you don't specify key/path, all the keys in the secret will be mounted
# with filenames matching the keys. In this case I am specifying which
# keys to use and the names for the files that will hold them.
volumes:
- name: db-cred
secret:
secretName: db-cred
items:
- key: username
path: username.txt
- key: password
path: password.txt
- name: redis-cred
secret:
secretName: redis-cred
items:
- key: password
path: password.txt
This is the same as how configmaps are mounted
You might have noticed that this process is the same as for configmaps. These two concepts are very similar. You could potentially use configmaps for secrets and vice versa, but the separate commands are at least a good way to separate out data that is sensitive.