Kubernetes Storage

Config Map

Using a resource called Config Map, you can store environment variables and similar data as key-value pairs. Config Map mounts configured environment variables into Pods as volumes. Environment variables can also be configured by adding an env item inside spec in a manifest. However, in that case the variables cannot be reused. This problem can be solved by using Config Map.

Let’s look at how to create one. First, create a Config Map manifest. This can be done by specifying configmap with the kubectl create command. The example below creates a YAML file. In this case, the string Hello_World is stored in an environment variable called TEST_ENV.

kubectl create configmap my-config --from-literal TEST_ENV=Hello_World -o yaml > configmap.yaml 

The YAML file created by running the command above is as follows.
configmap.yaml

apiVersion: v1
data:
  TEST_ENV: Hello_World
kind: ConfigMap
metadata:
  creationTimestamp: "2022-09-08T08:29:59Z"
  name: my-config
  namespace: default
  resourceVersion: "10632"
  uid: 2371e43c-c361-40be-8ab9-5269edfb41c3

In this case, data is written at the first level of the YAML file. This is the field that specifies the data held by the node being created. Here it simply represents key: TEST_ENV and value: Hello_World.

When creating a node with the YAML file written this way through kubectl apply, you can refer to this Config Map when creating a Pod that uses environment variables.

As shown below, Config Map information is reflected by writing it in the YAML file for Pod creation.

pod.yaml

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: helloworld
  name: helloworld
spec:
  containers:
  - env:
    # Specify the environment variable name to use in the Pod
    - name: TEST_ENV_POD
      # Specify what to put into the environment variable named above through valueFrom
      valueFrom:
        # Specify that the value is referenced from configMap
        configMapKeyRef: 
          # Specify the ConfigMap named my-config, created above
          name: my-config
          # Reference the environment variable whose key is TEST_ENV from the ConfigMap specified by name
          key: TEST_ENV
    image: gcr.io/google-samples/hello-app:1.0
    ports:
    - containerPort: 8080

In the pod.yaml above, the YAML file creates a Pod called helloworld, but it specifies that the environment variable TEST_ENV_POD inside helloworld should use the value stored in TEST_ENV from the Config Map called my-config. This style can be used in the same way by other Pods, which improves reusability.

Next, let’s look at how to mount a Volume to a Pod. Earlier, we said that a Pod is the basic unit of management and shares a virtual Network Interface, IP address, and file system. This means that the Pod itself can be considered a virtual host in Kubernetes. Mount a Config Map as a volume to this Pod. Config Map can store not only environment variables but also key-value pairs, and mount that data as files in a volume. The previous example called data stored in Config Map as environment variables.

To do this, modify pod.yaml as follows.
pod.yaml

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: helloworld-configmap-volume
  name: helloworld-configmap-volume
spec:
  containers:
  - image: gcr.io/google-samples/hello-app:1.0
    name: helloworld-configmap-volume
    ports:
    - containerPort: 8080
    resoueces: {}
    volumeMounts:
      # Specify the volume name
    - name:my-config-volume
      # Specify the file path in the container where the volume is mounted
      mountPath: /my-config/TEST_ENV
    volume:
      # Specify the volume name to create
    - name: my-config-volume
      configMap:
        # Specify the Config Map name
        name: my-config
        items:
          # Specify the key name in the Config Map
        - key: TEST_ENV
          path: keys

In this YAML file, the Config Map named my-config is specified as a volume named my-config-volume, that name is used to mount it, and the corresponding path name inside the container is set to /my-config/TEST_ENV. This has the advantage that the data becomes a file and can be changed.

Persistent Volume

Next, let’s look at Persistent Volume.

In containers, data is written by changing a Volume inside the Pod. Therefore, when the Pod disappears, the data also disappears. To prevent this, data is stored in a Persistent Volume on cluster-wide Nodes. In actual operation, a volume that can be shared by each Node in a multi-node cluster is created, and each Node requests only the amount it needs from this common volume, then mounts the received volume to the requesting Node.

For this reason, prepare a YAML file that defines the common volume, pv.yaml, and a YAML file containing the request, pvc.yaml. In the YAML file used when creating the Pod, or Node, pod.yaml, write it so that it references this request. Samples of each file are shown below.

pv.yaml

apiVersion: v1
kind: PersistentVolume
metadata: 
  name: pv
spec:
 storageClassName: manual
 # Specify the volume size
 capacity: 100M
 # Specify the access permission range
 accessModes: ReadWriteOnce
 hostPath:
  # Specify the path on the Node
  path: "/mnt/pvc"

pvc.yaml

apiVersion: v1
kind: PersistentVolumeClaim
metadata: 
  name: pvc
spec:
 storageClassName: manual
 # Specify the access permission range
 accessModes: ReadWriteOnce
 resources:
  # Specify the request
  requests:
    # Specify the desired capacity
    storage: 10M

pod.yaml

apiVersion: v1
kind: Pod
metadata:
  creationTimestamp: null
  labels:
    run: helloworld-pvc
  name: helloworld-pvc
spec:
  containers:
  - image: gcr.io/google-samples/hello-app:1.0
    name: helloworld-pvc
    ports:
    - containerPort: 8080
    resoueces: {}
    volumeMounts:
      # Specify the volume name
    - name:my-pv
      # Specify the file path in the container where the volume is mounted
      mountPath: /mnt/pvc
    volume:
     # Specify the volume name to create
    - name: my-pv
      # Specify the persistent volume claim name
      persistentVolumeClaim:
        name: pvc

When running this, execute the three files above in order with kubectl apply, but before that, you need to create a directory in the cluster. Therefore, if you are using minikube, connect to the cluster with the following commands and create it.

$ minikube ssh
$ sudo mkdir mnt/pvc