Kubernetes ConfigMap recursive directory issues

A workaround solution for using Kubernetes Configmap to map a recursive directory.

First, about ConfigMap recursive directory issues, you can find from below topics

or

However, unfortunately, it isn’t possible to build a Kubernetes ConfigMap from a directory, recursively [1] currently.

For example,

conf/
└── integrator
    └── conf
        ├── axis2
        │   └── axis2.xml
        ├── carbon.xml
        ├── datasources
        │   └── master-datasources.xml
        ├── registry.xml
        └── user-mgt.xml

Therefore, we will use a work-around to solve this issue.

Prepare a Helm template

First, let prepare a Helm template for Kubernetes deployment with configmap.yaml for ConfigMap and deployment.yaml for Deployment

$ tree -L 2 helm_templates/your-template
helm_templates/your-template
├── Chart.yaml
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── configmap.yaml  <--- ConfigMap
│   ├── deployment.yaml <--- Deployment
└── values.yaml

For instance, Configmap yaml for you Helm template

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ template "your-template.fullname" . }}-config
data:
# mapping configMaps from values.yml to ConfigMap
{{- range $key, $value := .Values.configMaps }}
  {{ $key }}: |-
{{ $value.content | indent 4 }}
{{- end }}

After that, a Deployment.yaml which mount all configMap data to volume using subPath. Please note that we using path properties for mount path setting.

spec:
      volumes:
        - name: {{ template "your-template.fullname" . }}-config
          configMap: { name: {{ template "your-template.fullname" . }}-config }
      containers:
        - volumeMounts:
            {{- range $key, $value := .Values.configMaps }}
            - name: {{ template "your-template.fullname" $ }}-config
              # note that we using path properties for mount path setting
              mountPath: /config/{{ $value.path }}
              subPath: {{ $key }}
            {{- end }}

Generate your Helm values.yaml by Python code

After that, we will prepare a simple Python code to read recursive directory and pass file’s content to values.yaml. For loading recursive directory from config_dir.

def get_config_maps(config_dir) -> dict:
         config_maps = {}
         filenames = [y for x in os.walk(config_dir) for y in glob.glob(os.path.join(x[0], '*')) if os.path.isfile(y)]

         for filename in filenames:
             # remove parent dir path
             relative_path = filename.replace(config_dir + os.path.sep, "")
             # replace path separator by "__" to prevent Kubernetes syntax error
             # currently file path doesn't validate '[-._a-zA-Z0-9]+'
             key = relative_path.replace(os.path.sep, "__")
             with open(filename, 'r') as file:
                 config_maps[key] = {
                     "path": relative_path, # a path that will be used for mount ConfigMap to Pod's volume
                     "content": file.read()
                 }
         return config_maps

The next step is, saving file’s content to values.yaml

 # load value template
 confif_dir = 'path/to/your/conf'
 with open('helm_templates/your-template/values.yaml', 'r') as file:
      deploy_values = yaml.safe_load(file)
      deploy_values['configMaps'] = get_config_maps(config_dir)

Deploy using your Helm template

helm install [your-helm-template-path] -f values.yaml

In conclusion, we can build a ConfigMap from a recursive directory by using a simple Python code with Helm template. Good luck & happy Kubernetes! :beer:

Additional, Other Kubernetes related topics is here. https://tuantranf.me/tag/kubernetes/

Original work is here https://gist.github.com/tuantranf/1faf61d0864353ed617af1f90f3ee453