0
votes

I want to take an existing Helm chart I get from a public Helm chart repository and tell Helm to alter part of one its templates by adding extra lines to the template file.

Here is an example. There is a Helm chart called basic-app (that I don't control) which is a simple Apache-based web application. Here is one of its template files, one that creates a Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Values.APP_NAMESPACE }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Chart.Name }}
  template:
    metadata:
      labels:
        app: {{ .Chart.Name }}
    spec:
      ## CONTAINERS
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: {{ .Values.apache.port }}
              protocol: TCP
          volumeMounts:
          - name: secrets-yaml
            mountPath: /etc/myapp/secrets.yaml
            subPath: secrets.yaml
      ## VOLUMES
      volumes:
      - name: secrets-yaml
        secret:
          secretName: {{ .Values.APP_NAMESPACE }}-secrets-yaml

the basic-app chart works well for me except that I want to add a new secret. That is, I want the resulting Deployment template to look like the above except I want to add a second volume and volume mount for the new secret:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Values.APP_NAMESPACE }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app: {{ .Chart.Name }}
  template:
    metadata:
      labels:
        app: {{ .Chart.Name }}
    spec:
      ## CONTAINERS
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: {{ .Values.apache.port }}
              protocol: TCP
          volumeMounts:
          - name: secrets-yaml
            mountPath: /etc/myapp/secrets.yaml
            subPath: secrets.yaml
          # This is new.    
          - name: secrets-new-yaml
            mountPath: /etc/myapp/secrets-new.yaml
            subPath: secrets-new.yaml           
      ## VOLUMES
      volumes:
      - name: secrets-yaml
        secret:
          secretName: {{ .Values.APP_NAMESPACE }}-secrets-yaml
      # This is new.
      - name: secrets-new-yaml
        secret:
          secretName: {{ .Values.APP_NAMESPACE }}-secrets-new-yaml        

One way to achieve this would be to make a new chart by copying basic-app and adding the extra secret to the Deployment template. But this approach is undesirable for a number of reasons not least of which is that changes and fixes to basic-app will not appear in the copied chart.

Another approach would be to change basic-app itself by adding the new secret with some conditional code that inserts it only if some value is true. But this means getting the maintainer to make the change and the maintainer, for good reason, might not want to make such site-specific changes to their chart.

Ideally, like a class inheritance in object-oriented programing, I want Helm to simply take the existing basic-app chart and inject this new secret into its Deployment template. Is this possible?

1

1 Answers

0
votes

You can't manipulate or wrap the defined template function in the way you're suggesting. The Go text/template language doesn't provide any mechanism to redefine or modify a template once it's been defined.

Helm does have the concept of post rendering, allowing you to manipulate the YAML after it gets generated. This can be any executable that accepts YAML on stdin and produces YAML on stdout; in practice, it seems like it probably needs to be a script that invokes a more complex tool. The documentation contains a link to a Kustomize-based example.

If you have yq available, you could use that as a post-renderer (untested):

#!/bin/sh
yq -M eval 'select(.Kind == "Deployment") | .spec.template.spec.containers.[0].volumeMounts += {name: secrets-new-yaml, mountPath: /etc/myapp/secrets-new.yaml, subPath: secrets-new.yaml}' -
helm template . --post-renderer ./add-secrets.sh

(Having written this, I'd probably go with Kustomize over yq. You need a complex directory tree and some more settings to use Kustomize, but you'd need to install either yq or Kustomize separately to be able to use them, and there doesn't seem to be a way to pass the yq "script" other than as a single command-line argument; given the amount of structure you're trying to add, it gets unwieldy quickly.)