Kubernetes - Using ConfigMap SubPaths to Mount Files
Josh Duffney
Posted on November 13, 2019
What if you want to mount a configuration file from a ConfigMap, but do not want to mount it as a volume? You can accomplish this by using SubPaths. Before I explain how to use a SubPath, let's look at what happens if I don't.
Using a ConfigMap as a Mounted Volume
By default ConfigMaps are shared with Pods in two ways; environment variables or mounted volumes. In this example I have a config map that contains a mysql configuration. Using environment variables for that isn't feasible, which leaves me with using a volume.
What you see here is a manifest for a configMap. The manifest defines the configMap name and associates some labels in the metadata. In the data section it contains a map name mysql_binlog_format.cnf
and the data source which is the content of the file.
configMap
# mysql-configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-configmap
labels:
app: mysql
data:
mysql_binlog_format.cnf: |
[mysqld]
binlog-format=mixed
Deployment Using a configMap Volume
As I mentioned configMaps can be used as volumes. The volumeMounts inside the template.spec are the same as any other volume. However, the volumes section is different. Instead of specifying a persistentVolumeClaim or other volume type you reference the configMap by name. This takes all the map names and data sources of the configMap named mysql-configmap and mounts it as a volume at /etc/mysql/conf.d
# mysql-deployment.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
selector:
app: mysql
clusterIP: None
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: mysql
spec:
selector:
matchLabels:
app: mysql
strategy:
type: Recreate
template:
metadata:
labels:
app: mysql
spec:
containers:
- image: mysql:5.6
name: mysql
env:
# Use secret in real usage
- name: MYSQL_ROOT_PASSWORD
value: password
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-configmap-volume
mountPath: /etc/mysql/conf.d
volumes:
- name: mysql-configmap-volume
configMap:
name: mysql-configmap
Apply the Manifests
#save the above manifests (mysql-configmap.yaml & mysql-deployment.yaml)
kubectl apply -f .
# Use kubctl exec to list /etc/mysql/conf.d contents
kubectl exec -it mysql-59fcc88776-g768b ls /etc/mysql/conf.d
The problem
The screen shot above tells us the volume mount worked. Kubernetes took the map name of mysql_binlog_format.cnf
present it as a file with the contents that were stored in the data source of the configMap. The problem however is it laid that volume on top of the existing directory. The default configuration files for mysql are no longer present. I'd have to create all the mysql configuration files and store them into the configMap. Or, I can use a subPath.
Using a configMap subPath
Nothing needs to change with the actual configMap resources that was created earlier. However, I do have to make a few changes to our deployment manifest to use a subPath. First I'll have to update template.spec.volumeMounts. I need to update the mountPath to include the file name I want it to mount. The mountPath is now /etc/mysql/conf.d/binlog_format.cnf
instead of /etc/mysql/conf.d
. Next I need to add the subPath property. The value for the subPath must match the path specified in template.volumes section.
I also need to update the templates.volumes section. Instead of simply providing the configMap name I now also need to provide and items list of the entries I want to include from the configMap. Under items I've specified the key, which is the map name and the path. The path value must match the subPath value define din template.spec.volumeMounts.
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
ports:
- port: 3306
selector:
app: mysql
clusterIP: None
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: mysql
spec:
selector:
matchLabels:
app: mysql
strategy:
type: Recreate
template:
metadata:
labels:
app: mysql
spec:
containers:
- image: mysql:5.6
name: mysql
env:
# Use secret in real usage
- name: MYSQL_ROOT_PASSWORD
value: password
ports:
- containerPort: 3306
name: mysql
volumeMounts:
- name: mysql-configmap-volume
mountPath: /etc/mysql/conf.d/binlog_format.cnf
subPath: binlog_format.cnf
volumes:
- name: mysql-configmap-volume
configMap:
name: mysql-configmap
items:
- key: mysql_binlog_format.cnf
path: binlog_format.cnf
Re-apply the Manifests
#save the above manifests (mysql-configmap.yaml & mysql-deployment.yaml)
kubectl apply -f .
# Use kubctl exec to list /etc/mysql/conf.d contents
kubectl exec mysql-7848ff5588-d4f6p ls /etc/mysql/conf.d
# cat contents of binlog_format.cnf
kubectl exec mysql-7848ff5588-d4f6p cat /etc/mysql/conf.d/binlog_format.cnf
Disadvantages
SubPaths are not automatically updated when a ConfigMap is modified. Changes to a ConfigMap will need to be a new deployment which would result in the pods being recreated with the updated ConfigMap content.
Sources
run-single-instance-stateful-application
Add ConfigMap data to a specific path in the Volume
Posted on November 13, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.