"Separation of configuration from code" is one of the tenets of the 12-factor applications. We externalize things which can change and this in turn helps keep our applications portable. This is critical in the Kubernetes world where our applications are packaged as Docker images. A Kubernetes ConfigMap
allows us to abstract configuration from code and ultimately the Docker image.
This blog post will provide a hands-on guide to app configuration related options available in Kubernetes.
As always, the code is available on GitHub. So let's get started....
To configure your apps in Kubernetes, you can use:
- Good old environment variables
ConfigMap
-
Secret
— this will be covered in a subsequent blog post
You will need a Kubernetes cluster to begin with. This could be a simple, single-node local cluster using minikube
, Docker for Mac
etc. or a managed Kubernetes service from Azure (AKS), Google, AWS etc. To access your Kubernetes cluster, you will need kubectl
, which is pretty easy to install.
e.g. to install kubectl
for Mac, all you need is
curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl && \
chmod +x ./kubectl && \
sudo mv ./kubectl /usr/local/bin/kubectl
Using Environment Variables for configuration
Let’s start off with an easy peasy example to see how to use environment variables by specifying them directly within our Pod
specification.
Notice how we define two variables in spec.containers.env
— ENVVAR1
and ENVVAR2
with values value1
and value2
respectively.
Let’s start off by creating the Pod
using the YAML specified above.
Pod
is just a Kubernetes resource or object. The YAML file is something that describes its desired state along with some basic information - it is also referred to as amanifest
,spec
(shorthand for specification) ordefinition
.
Use the kubectl apply
command to submit the Pod
information to Kubernetes.
To keep things simple, the YAML file is being referenced directly from the GitHub repo, but you can also download the file to your local machine and use it in the same way.
$ kubectl apply -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/configuration/kin-config-envvar-in-pod.yaml
pod/pod1 created
To check the environment variables, we will need to execute a command "inside" of the Pod using kubectl exec
— you should see the ones which were seeded in the Pod
definition.
Here, we have used grep
to filter for the variable(s) we’re interested in
$ kubectl exec pod1 -it -- env | grep ENVVAR
ENVVAR1=value1
ENVVAR2=value2
What's
kubectl exec
? In simple words, it allows you to execute a command in specific container within aPod
. In this case, ourPod
has a single container, so we don't need to specify one
Ok, with that concept out of the way, we can explore ConfigMap
s.
Using a ConfigMap
The way it works is that your configuration is defined in a ConfigMap
object which is then referenced in a Pod
(or Deployment
).
Let’s look at techniques using which you can create a ConfigMap
Using a manifest file
It’s possible to create a ConfigMap
along with the configuration data stored as key-value pairs in the data
section of the definition.
In the above manifest:
- the
ConfigMap
namedsimpleconfig
contains two pieces of (key-value) data —hello=world
andfoo=bar
-
simpleconfig
is referenced by aPod
(pod2
; the keyshello
andfoo
are consumed as environment variablesHELLO_ENV_VAR
andFOO_ENV_VAR
respectively.
Note that we have included the
Pod
andConfigMap
definition in the same YAML separated by a---
Create the ConfigMap
and confirm that the environment variables have been seeded
$ kubectl apply -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/configuration/kin-config-envvar-configmap.yaml
configmap/config1 created
pod/pod2 created
$ kubectl get configmap/config1
NAME DATA AGE
config1 2 18s
$ kubectl exec pod2 -it -- env | grep _ENV_
FOO_ENV_VAR=bar
HELLO_ENV_VAR=world
Shortcut using envVar
We consumed both the config data (foo
and hello
) by referencing them separately, but there is an easier way! We can use envFrom
in our manifest to directly refer to all key-value data in a ConfigMap
.
When using
ConfigMap
data this way, the key is directly used as the environment variable name. That’s why you need to follow the naming convention i.e. Each key must consist of alphanumeric characters, ‘-’, ‘_’ or ‘.’
Just like before, we need to create the Pod
and ConfigMap
and confirm the existence of environment variables
$ kubectl apply -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/configuration/kin-config-envvar-with-envFrom.yaml
configmap/config2 created
pod/pod3 created
$ kubectl get configmap/config2
NAME DATA AGE
config2 2 25s
$ kubectl exec pod3 -it -- env | grep _ENV
HELLO_ENV=world
FOO_ENV=bar
Nice little trick ha? :-)
Configuration data as files
Another interesting way to consume configuration data is by pointing to a ConfigMap
in the spec.volumes
section of your Deployment
or Pod
spec.
If you have no clue what
Volumes
(in Kubernetes) are, don’t worry. They will be covered in upcoming blogs. For now, just understand that volumes are a way of abstracting your container from the underlying storage system e.g. it could be a local disk or in the cloud such as Azure Disk, GCP Persistent Disk etc.
In the above spec, pay attention to the spec.volumes
section — notice that it refers to an existing ConfigMap
. Each key in the ConfigMap
is added as a file to the directory specified in the spec i.e. spec.containers.volumeMount.mountPath
and the value is nothing but the contents of the file.
Note that the files in volumes are automatically updated if the
ConfigMap
changes.
In addition to traditional string based values, you can also include full-fledged files (JSON, text, YAML, etc.) as values in a ConfigMap
spec.
In the above example, we have embedded an entire JSON within the data section of our ConfigMap
. To try this out, create the Pod
and ConfigMap
$ kubectl apply -f https://raw.githubusercontent.com/abhirockzz/kubernetes-in-a-nutshell/master/configuration/kin-config-envvar-json.yaml
configmap/config3 created
pod/pod4 created
$ kubectl get configmap/config3
NAME DATA AGE
config3 1 11s
As an exercise, confirm that the environment variable was seeded into the Pod
. Few pointers:
- the name of the
Pod
ispod4
- double-check the name of the environment variable you should be looking for
You can also use kubectl
CLI to create a ConfigMap
. It might not be suitable for all use cases but it certainly makes things a lot easier
Using kubectl
There are multiple options:
Using --from-literal
to seed config data
We’re seeding the following key-value pairs into the ConfigMap
— foo_env=bar
and hello_env=world
$ kubectl create configmap config4 --from-literal=foo_env=bar --from-literal=hello_env=world
Using --from-file
$ kubectl create configmap config5 --from-file=/config/app-config.properties
This will create a ConfigMap
(config5
) with
- a key with the same name of the file i.e.
app-config.properties
in this case - and, value as the contents of the file
You can choose to use a different key (other than the file name) to override the default behavior
$ kubectl create configmap config6 --from-file=CONFIG_DATA=/config/app-config.properties
In this case, CONFIG_DATA
will be the key
From files in a directory
You can seed data from multiple files (in a directory) at a time into a ConfigMap
$ kubectl create configmap config7 --from-file=/home/foo/config/
You will end up with
- multiple keys which will the same as the individual file name
- the value will be the contents of the respective file
Good to know
Here is a (non-exhaustive) list of things which you should bear in mind when using ConfigMap
s:
- Once you define environment variables
ConfigMap
, you can utilize them in the command section inPod
spec i.e.spec.containers.command
using the$(VARIABLE_NAME)
format - You need to ensure that the
ConfigMap
being referenced in aPod
is already created — otherwise, thePod
will not start. The only way to get around this is to mark theConfigMap
asoptional
. - Another case in which might prevent the
Pod
from starting is when you reference a key that actually does not exist in theConfigMap
.
You can also refer the
ConfigMap API
That's it for this edition of the "Kubernetes in a Nutshell" series. Stay tuned for more!
If you are interested in learning Kubernetes and Containers using Azure, simply create a free account and get going! A good starting point is to use the quickstarts, tutorials and code samples in the documentation to familiarize yourself with the service. I also highly recommend checking out the 50 days Kubernetes Learning Path. Advanced users might want to refer to Kubernetes best practices or watch some of the videos for demos, top features and technical sessions.
I really hope you enjoyed and learned something from this article! Please like and follow if you did. Happy to get feedback via @abhi_tweeter or just drop a comment.