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.

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.