Featured image of post Kubernetes volumes

Kubernetes volumes

Mix & match Kubernetes volume mounts.

Context

Assume we are sketching a Kubernetes deployment of a containerized ducktales application. This application both leverages a configuration file, duck.properties, and some data. Because they do not obey the same constraints, we are likely to find them persisted accordingly and thus split in two. This said, during runtime, application expects to have both of them located at the same place, under its /data folder.

ducktales

Here we can imagine data to be 3D models for our duck team while configuration gathers some dynamic settings like the color of the caps.

Stitching

Luckily, Kubernetes comes in with its built-in volumes mounting feature to perform stitching. Here we mount data from a persistentVolumeClaim through mountPath, and configuration from dedicated configMap section combining both mountPath and subPath.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
        - name: ducktales
          image: ducktales:1987
          volumeMounts:
            - name: config-volume
              mountPath: /data/duck.properties
              subPath: duck.properties
            - name: backup-volume
              mountPath: /data
      volumes:
      - name: config-volume
        configMap:
          name: instance-config
      - name: backup-volume
        persistentVolumeClaim:
          claimName: shared-storage
---
apiVersion: v1
kind: ConfigMap
data:
  duck.properties : |
    cap-color-one=red
    cap-color-one=blue
    cap-color-one=green    
---
apiVersion: v1
kind: PersistentVolumeClaim
spec:
  accessModes:
    - ReadWriteMany

Inspecting living ducktales pod confirms setup is as expected:

1
2
3
4
5
6
7
8
ls /data

# => duck.properties huey/ dewey/ louie/

cat duck.properties
# => cap-color-one=red
# => cap-color-one=blue
# => cap-color-one=green

Default

Imagine now we would like to fallback to default for configuration, we can simply remove the matching mount.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
-       - name: ducktales
+       - name: ducktales-origin
          image: ducktales:1987
          volumeMounts:
-           - name: config-volume
-             mountPath: /data/duck.properties
-             subPath: duck.properties
            - name: backup-volume
              mountPath: /data
      volumes:
-       - name: config-volume
-         configMap:
-           name: instance-config
        - name: backup-volume
          persistentVolumeClaim:
            claimName: shared-storage

We can notice that even if duck.properties was previously mounted within ducktales pod /data folder, collocating with persistent data, it appears file content was not persisted in the persistent volume. We can check this by inspecting the brand-new ducktales-origin pod, and see that even if a duck.properties file is still present, it appears to be empty.

1
2
3
4
5
6
ls /data

# => duck.properties huey/ dewey/ louie/

cat duck.properties
# => Ø

Siblings

This also means that two instances can peacefully leverage common data while being customized independently. Let’s introduce a new instance with a new set of settings to check this assertion. This scenario is common, e.g., for canary deployment where we would like to test new settings while working at existing data, or for collaboration purpose where we would like to customize our application according to external context. Here we are. For Halloween, we decided to promote a dedicated color schema instead of the plain old one.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
        - name: ducktales
          image: ducktales:1987
          volumeMounts:
            - name: config-volume
              mountPath: /data/duck.properties
              subPath: duck.properties
            - name: backup-volume
              mountPath: /data
+       - name: ducktales-halloween
+         image: ducktales:1987
+         volumeMounts:
+           - name: config-volume
+             mountPath: /data/duck.properties
+             subPath: duck-halloween.properties
+           - name: backup-volume
+             mountPath: /data
     volumes:
      - name: config-volume
        configMap:
          name: instance-config
      - name: backup-volume
        persistentVolumeClaim:
          claimName: shared-storage
---
apiVersion: v1
kind: ConfigMap
data:
  duck.properties : |
    cap-color-one=red
    cap-color-one=blue
    cap-color-one=green
+ duck-halloween.properties : |
+   cap-color-one=orange
+   cap-color-one=black
+   cap-color-one=purple

Let’s inspect ducktales pod:

1
2
3
4
5
6
7
8
ls /data

# => duck.properties huey/ dewey/ louie/

cat duck.properties
# => cap-color-one=red
# => cap-color-one=blue
# => cap-color-one=green

and do the same for ducktales-halloween one:

1
2
3
4
5
6
7
8
ls /data

# => duck.properties huey/ dewey/ louie/

cat duck.properties
# => cap-color-one=orange
# => cap-color-one=black
# => cap-color-one=purple

Closing

Data is a complex topic and there are a couple of good design pattern to have in mind to streamline their usage. One of them is to ensure we keep persistence and runtime agnostic of each others. By doing so, we need some tooling to translate from one realm to the other. Here we see how we could leverage Kubernetes built-in volume mounting feature to compose heterogenous source to a compelling runtime setup while ensuring we keep enough flexibility to address upcoming scenario.

Licensed under CC BY-NC-SA 4.0
Last updated on Mar 13, 2024 00:00 UTC
comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy