Photo by Kingsley Jebaraj
Today I bumped into a small challenge at work related to a Helm chart and Kubernetes. For future references, let me write about it.
This note assumes you are familiar with the concepts of Kubernetes and Helm.
One of our Helm charts deploys an HTTP server which requires a config file to be provided as a command-line argument. The docker image for the HTTP server only exposes the main command to start the server, so we need to pass the argument to the container command, as well as mount the ConfigMap into the docker container.
kind: Deployment# ...spec:# ...template:metadata:annotations:checksum/config: {{ include (print $.Template.BasePath "/application-config.yaml") . | sha256sum }}# ...spec:volumes:- configMap:name: application-configname: application-configcontainers:- image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"command:- "./bin/start.js"args:- "--config"- "/etc/app/config.json"# ...volumeMounts:- name: application-configmountPath: /etc/appreadOnly: true
The ConfigMap defining the config.json
is somehow manually "crafted" from a bunch of chart values.
kind: ConfigMap# ...data:config.json: |{"name": "{{ .Values.app.name }}"// ...}
However, we recently introduced a new configuration file format, which does not required to pass the --config
command-line argument anymore. Instead, the config file is automatically loaded by the HTTP server following certain naming conventions (see cosmiconfig package).
The config file is now defined in the source code of the project folder and not crafted together within the ConfigMap.
Therefore, the question arises: How can we mount the config file from the filesystem into the running docker container of the Kubernetes pod?
After several trials, I was able to make things work by leveraging the ConfigMap and the --set-file
option of the Helm command.
The ConfigMap is still necessary, as we need to mount the config file into the docker container. The only difference is that we need to mount a single file and that the content of the ConfigMap should be automatically read from the file on disk.
Helm provides a --set-file
option that we can use to read the content of the config file from disk. The content is then assigned to a template variable applicationConfigJson
that we can reference into the ConfigMap:
kind: ConfigMap# ...data:config.json: |{{ .Values.applicationConfigJson | indent 4 }}
Then Helm command to deploy the chart should be updated as following:
helm upgrade --install \--set-file applicationConfigJson="./path/to/application-config.json" \# ...
Finally, the Kubernetes deployment should be updated as well by removing the command
+ args
option and by specifying the subPath
to the single file when mounting the volume:
kind: Deployment# ...spec:# ...template:metadata:annotations:checksum/config: {{ include (print $.Template.BasePath "/application-config.yaml") . | sha256sum }}# ...spec:volumes:- configMap:name: application-configname: application-configcontainers:- image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"# ...volumeMounts:- name: application-configmountPath: /app/application-config.jsonsubPath: application-config.jsonreadOnly: true
It was a bit tricky to find this solution but at the same time I learned a bunch of new things:
mountPath
and subPath
options--set-file
option to assign the content of the file to a template variableHappy Helming and deployments! 🚀