Configure Environment

In any serious deployment, configuration data has to be passed into a container and often it is necessary to access file-storage. This exercise introduces examples for how to achieve both. Create a new file environment.yml for this exercise.

Provide Configuration in Environment Variables

Configuration options are usually passed into containers via environment variables. Two alternatives exist for how to achieve this, ConfigMap and Secret.

Define ConfigMap

Copy the first example of a ConfigMap from the documentation and add it to your environment.yml file. Our ConfigMap only contains the one field user, however, note that the data field is a key/value store and can contain arbitrary data in YAML format.

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-configmap
data:
  user: John Doe

Define Secret

A Secret is defined in the same way as a ConfigMap, however, values are not stored as plaintext, but need to be Base64 encoded. This can be easily achieved on the terminal, just make sure that you include the -n parameter to suppress a trailing newline character from being added.

$ echo -n bar | base64
YmFy
$ echo bar | base64
YmFyCg==

Apart from the encoding, the definition of a Secret is then very similar to a ConfigMap.

apiVersion: v1
kind: Secret
metadata:
  name: my-secret
data:
  foo: YmFy

Add both the ConfigMap and the Secret to the environment.yml file and do not forget to add the separator ---. Apply the file to the cluster.

$ kubectl apply -f environment.yml
configmap/my-configmap created
secret/my-secret created

Open the Minikube dashboard, find both resources, and explore their contents.

Add ConfigMap and Secret to a Pod

We define a simple Pod that is using the showenv image to make it easy to investigate the defined environment variables. Append the Pod definition to the environment.yml file.

...
---
apiVersion: v1
kind: Pod
metadata:
  name: showenv
spec:
  containers:
  - name: showenv
    image: proksch/showenv
    ports:
    - containerPort: 8080
    env:
    - name: USERNAME
      valueFrom:
        configMapKeyRef:
          name: my-configmap
          key: user
    - name: FOO
      valueFrom:
        secretKeyRef:
          name: my-secret
          key: foo

Please note that the name of the environment variable can differ from the key that is used in the ConfigMap or Secret. Apply the environment.yml file to your cluster and start a port-forward that makes it possible to connect to the Pod.

$ kubectl apply -f environment.yml
configmap/my-configmap unchanged
secret/my-secret unchanged
pod/showenv created
$ kubectl port-forward showenv 1234:8080

Opening localhost:1234 in your browser will show that you both declared enviroment variables exist (FOO: bar and USERNAME: John Doe). A containerized application can now access the provided information in the same way it would access any other environment variable.

Instead of providing information through the environment, you can also define that information from ConfigMaps and Secrets is mounted into the file system. In essence, every key will then be mapped to a file and its value will be the file content.

Use a Volume for Storage

Similar to Docker, Kubernetes has the concept of Volumes that can be mounted into containers. Unlike Docker, however, Kubernetes has a much richer selection of possible Volume types. While Docker was mostly limited to local mount options, skimming the Kubernetes documentation on Volumes will show you various non-local mount options, like storage via NFS or iSCSI. For this exercise, we will use the simplest example though, a host path.

Edit the Pod in your environment.yml file and append the Volume-related configuration. The idea is to map the host path /data_outside into the container file system /data_inside.

...
spec:
  containers:
  - name: showenv
    ...
    volumeMounts:
      - mountPath: /data_inside/
        name: my-volume
  volumes:
    - name: my-volume
      hostPath:
        path: /data_outside/

If you try to simply apply the changed file, Kubernetes will complain that changes cannot be merged with the existing config. To solve this error, delete the config, before applying it again.

$ kubectl delete -f environment.yml
configmap "my-configmap" deleted
secret "my-secret" deleted
pod "showenv" deleted
$ kubectl apply -f environment.yml
configmap/my-configmap created
secret/my-secret created
pod/showenv created

To verify a working volume, create a file in /data_inside and restart the Pod. The file will still exist.

$ kubectl exec -it showenv -- touch /data_inside/i_was_here
$ kubectl delete -f environment.yml
...
$ kubectl apply -f environment.yml
...
$ kubectl exec -it showenv -- ls /data_inside/
i_was_here

You might wonder which host folder is actually mounted on your host. The answer is none. This is again caused by the level of abstraction that Minikube adds. If you want to see the host path, you need to connect to the Minikube node:

$ minikube ssh
(container) $ ls /data_outside
i_was_here

To finish the exercise, delete the resources from the cluster (kubectl delete -f environment.yml).


Last modified on Jun 27, 2023 at 21:59.