Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple resources using single HELM template

We had been using single ingress per application(public) by default but with the recent requirement we need to expose (private) endpoint as well for some of the apps. That means we had a single template that looks like this:

templates/ingress.yaml

{{- if .Values.ingress.enabled -}}
{{- $fullName := include "app.fullname" . -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: {{ $fullName }}
  labels:
{{ include "app.labels" . | indent 4 }}
  {{- with .Values.ingress.annotations }}
  annotations:
    {{- toYaml . | nindent 4 }}
  {{- end }}
spec:
{{- if .Values.ingress.tls }}
  tls:
  {{- range .Values.ingress.tls }}
    - hosts:
      {{- range .hosts }}
        - {{ . | quote }}
      {{- end }}
      secretName: {{ .secretName }}
  {{- end }}
{{- end }}
  rules:
  {{- range .Values.ingress.hosts }}
    - host: {{ .host | quote }}
      http:
        paths:
        {{- range .paths }}
          - path: {{ . }}
            backend:
              serviceName: {{ $fullName }}
              servicePort: http
        {{- end }}
  {{- end }}
{{- end }}

templates/cert.yaml

{{- if .Values.ingress.tls -}}
apiVersion: certmanager.k8s.io/v1alpha1
kind: Certificate
metadata:
  name: {{ .Values.ingress.name }}
  namespace: {{ .Values.ingress.namespace }}
spec:
{{- range .Values.ingress.tls }}
  secretName: {{ .secretName }}
  duration: 24h
  renewBefore: 12h
  issuerRef:
    name: {{ .issuerRef.name }}
    kind: {{ .issuerRef.kind }}
  dnsNames: 
    {{- range .hosts }}
        - {{ . | quote }}
    {{- end }}
{{- end -}}
{{- end -}}

And the values.yaml looks like this:

ingress:
  enabled: true
  name: apps-ingress
  namespace: app1-namespace
  annotations:
    kubernetes.io/ingress.class: hybrid-external
    nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
  hosts:
    - host: apps.test.cluster
      paths:
        - /
  tls:
    - secretName: app1-tls
      issuerRef: 
        name: vault-issuer
        kind: ClusterIssuer
      hosts:
        - "apps.test.cluster"

So, to accomodate the new setup. I have added the below block on values.yaml file.

ingress-private:
  enabled: true
  name: apps-ingress-private
  namespace: app1-namespace
  annotations:
    kubernetes.io/ingress.class: hybrid-internal
    nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
  hosts:
    - host: apps.internal.test.cluster
      paths:
        - /
  tls:
    - secretName: app1-tls
      issuerRef: 
        name: vault-issuer
        kind: ClusterIssuer
      hosts:
        - "apps.internal.test.cluster"

And duplicated both templates i.e templates/ingress-private.yaml and templates/certs-private.yaml, and is working fine but my question here is - is there a way using a single template for each ingress and certs and create conditional resource?

As I mentioned above, some apps need internal ingress and some don't. What I want to do is; make public ingress/certs as default and private as optional. i have been using {{- if .Values.ingress.enabled -}} option to validate if ingress is required but in 2 different files.

Also, in values.yaml file, rather than having 2 different block is there a way to use the list if multiple resources are required?

like image 962
raz Avatar asked Mar 24 '20 22:03

raz


2 Answers

There are a couple of ways to approach this problem.

The way you have it now, with one file per resource but some duplication of logic, is a reasonably common pattern. It's very clear exactly what resources are being created, and there's less logic involved. The Go templating language is a little bit specialized, so this can be more approachable to other people working on your project.

If you do want to combine things together there are a couple of options. As @Matt notes in their comment, you can put multiple Kubernetes resources in the same file so long as they're separated by the YAML --- document separator.

{{/* ... arbitrary templating logic ... */}}
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: {{ $fullName }}
...
{{/* ... more logic ... */}}
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: {{ $fullName }}-private
...

The only thing that matters here is that the output of the template is a valid multi-document YAML file. You can use the helm template command to see what comes out without actually sending it to the cluster.

This approach pairs well with having a list of configuration rules in your YAML file

ingresses:
  - name: apps-ingress
    annotations:
      kubernetes.io/ingress.class: hybrid-external
      nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
  - name: apps-ingress-private
    annotations:
      kubernetes.io/ingress.class: hybrid-internal
      nginx.ingress.kubernetes.io/backend-protocol: "HTTP"

You can use the Go template range construct to loop over all of these. Note that this borrows the . special variable, so if you do refer to arbitrary other things in .Values you need to save away the current value of it.

{{- $top := . -}}
{{- range $ingress := .Values.ingresses -}}
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: {{ $ingress.name }}
  annotations: {{- $ingress.annotations.toYaml | nindent 4 }}
...
{{ end }}
like image 177
David Maze Avatar answered Oct 14 '22 11:10

David Maze


Thanks David for getting us started . But it did not work for me. I used following to generate multiple resources in single YAML.

{{- if .Values.nfs }}
{{- $top := . -}}
{{- range $index, $pvc := .Values.nfs }}
{{- if $pvc.persistentClaim }}
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: "{{ $top.Chart.Name }}-{{ $top.Release.Name }}-nfs-{{ $index }}"
  namespace: {{ $top.Release.Namespace }}
....
  resources:
     requests:
       storage: {{ $pvc.persistentClaim.storageRequest }}
{{- end }}
{{- end }}
{{- end }}

helm docs show how to define and use range: https://helm.sh/docs/chart_template_guide/variables/

like image 28
Chetan Avatar answered Oct 14 '22 11:10

Chetan