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