Helm charts can load ConfigMap data directly from files, bypassing the need for manual templating of every key-value pair.
Let’s see this in action. Suppose you have a settings.conf file with the following content:
[database]
host = localhost
port = 5432
user = admin
[cache]
enabled = true
size = 1024
And you want to deploy this as a ConfigMap in Kubernetes using Helm.
Here’s how you’d define it in your templates/configmap.yaml file:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "mychart.fullname" . }}-settings
data:
{{ .Files.Get "settings.conf" | nindent 2 }}
When Helm renders this template, it will read the content of settings.conf from your chart’s files directory and embed it directly into the data section of the ConfigMap. The nindent 2 ensures proper YAML indentation.
The resulting ConfigMap in Kubernetes will look like this:
apiVersion: v1
kind: ConfigMap
metadata:
name: mychart-settings
data:
[database]
host = localhost
port = 5432
user = admin
[cache]
enabled = true
size = 1024
This mechanism is incredibly powerful for managing configuration files that are already in a usable format, like .ini, .json, .yaml, or even scripts. Instead of manually translating each line into a key-value pair within the data section of your ConfigMap manifest, you let Helm handle the file transfer.
The core concept here is Helm’s Files object. This is a built-in object available within your Helm templates that provides access to files within your chart’s directory structure. The Get method is your primary tool for reading the content of a specific file.
Consider a more complex scenario where you have multiple configuration files. You can use Files.Get for each one:
templates/configmap-multi.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "mychart.fullname" . }}-configs
data:
app.conf: |
{{ .Files.Get "configs/app.conf" | nindent 4 }}
logging.yaml: |
{{ .Files.Get "configs/logging.yaml" | nindent 4 }}
In this case, app.conf and logging.yaml would reside in a configs/ subdirectory within your Helm chart. The | (literal block scalar) in YAML is important here, as it preserves newlines and indentation from the source files, preventing them from being collapsed into a single line.
The Files object also allows you to iterate over files within a directory using Files.Glob. This is useful if you want to include all files from a specific directory into your ConfigMap.
templates/configmap-dir.yaml:
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "mychart.fullname" . }}-configs-dir
data:
{{- range $fileName, $fileContent := .Files.Glob "configs_dir/*" }}
{{ $fileName | base }}: |
{{ $fileContent | nindent 4 }}
{{- end }}
This example would take every file within the configs_dir/ directory of your chart and add it to the ConfigMap, using the filename as the key and the file content as the value. The base function strips the directory path, leaving just the filename.
When you deploy a chart with ConfigMaps that load data from files, Helm packages these files as part of the chart archive. During the helm install or helm upgrade process, the Helm client reads these files from the chart and includes their content in the Kubernetes API request to create or update the ConfigMap resource. This means the actual configuration data is stored within the ConfigMap object in your Kubernetes cluster, not on the Helm client itself after deployment.
A common pitfall is forgetting to include files that are referenced via Files.Get or Files.Glob in your Chart.yaml file’s files section. While Helm often picks them up automatically, explicitly listing them can prevent unexpected issues, especially in CI/CD pipelines where chart packaging might behave differently. If a file is not found, Helm will error out during the template rendering phase, indicating that the specified file doesn’t exist within the chart’s context.
The next step is to understand how to consume this ConfigMap data within your deployed applications, typically by mounting it as volumes or injecting it as environment variables.