Motivation
Container images often accept Environment Variables for configuring their environments, for example the redis image accepts REDIS_VERSION
for a specific redis version. Below command starts a redis container, passing a desired REDIS_VERSION
environment variable.
crictl run -t redis -e REDIS_VERSION=7.2 redis
And to start a redis Pod
, imperatively:
kubectl run --image=redis --env=REDIS_VERSION=7.2 redis
And declaratively:
apiVersion: v1
kind: Pod
metadata:
name: redis
label:
app: kv-store
spec:
containers:
- name: redis
image: redis
env:
- name: REDIS_VERSION
value: 7.2
In the case of internal images, custom application can require more than enough environment variables to run and can look unmaintainable even with a Pod
manifest file:
apiVersion: v1
kind: Pod
metadata:
name: redis
label:
app: kv-store
spec:
containers:
- name: redis
image: redis
env:
- name: REDIS_VERSION
value: 7.2
- name: ENV_1
value: VALUE_1
- name: ENV_2
value: VAL_2
A better implementation would be to have a key value pair store for the env section, and that is what config maps are meant for.
ConfigMaps
ConfigMaps stand as an insecure secret storage in Kubernetes. To create a ConfigMap
imparatively run:
# passing the key/value pair directly, this is not neat
kubectl create configmap redis-config \
--from-literal=REDIS_VERSION=7.1 \
--from-literal=ENV_1=VALUE_1 \
--from-literal=ENV_2=VALUE_2
# A neater way is to store the secrets in a file
# having the secrets in a file name redis-config.env
# cat redis-config.env
# > REDIS_VERSION=7.1
# > ENV_1=VALU_1
# > ENV_2=VALUE_2
kubectl create configmap redis-config --from-file redis-config
Below manifest file creates a ConfigMap
declaratively:
apiVersion: v1
kind: ConfigMap
metadata:
name: redis-config
data:
REDIS_VERSION: 7.2
ENV_1=VALUE_1
ENV_2=VALUE_2
To inject all of the secrets from the config map into a Pod
, use a declarative manifest file like below:
apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
- name: redis
image: redis
envFrom:
- configMapRef:
name: redis-config
Below manifest pulls the value of a key from a ConfigMap
and injects it as the value of the MAPPED_REDIS_VERSION
env. This can be useful when pods share the same ConfigMap
but the containers use different names to reference the secret - IMHO this is anti pattern, and unidiomatic.
apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
- name: redis
image: redis
env:
- name: MAPPED_REDIS_VERSION
valueFrom:
configMapKeyRef:
name: redis-config
key: REDIS_VERSION
Dynamic Secrets In Pods
The above methods of injecting ConfigMap
is not dynamic, an update to the ConfigMap
will not reflect in any RUNNING Pod
already using it.
To ensure that a ConfigMap
is dynamic within a Pod, we can inject it as a volume mount in the container.
apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
- name: redis-container
image: redis
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: redis-config
Test this by running:
kubectl exec redis -c redis-container -- /bin/sh env
# > should log all the environment variable attached to the container
Shalom!