Skip to content
Do you want to pick up from where you left of?
Take me there

Self-paced lab

Learn Helm

Package, configure, and release Kubernetes applications with Helm charts and practical deployment patterns.

HelmKubernetesChartsDeployments
  1. 1
    Read the conceptBuild the mental model first.
  2. 2
    Try the commandsUse a disposable environment.
  3. 3
    Keep the notesReturn when you need a refresher.
Before you start: Read commands before running them, and avoid using a production cluster for experimentation.

git clone

Install Helm 3

  ~ curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 11679  100 11679    0     0  32332      0 --:--:-- --:--:-- --:--:-- 32262
Downloading https://get.helm.sh/helm-v3.14.3-darwin-arm64.tar.gz
Verifying checksum... Done.
Preparing to install helm into /usr/local/bin
Password:
helm installed into /usr/local/bin/helm

Creating the chart

(base) ➜  helm-workshop git:(main) helm create application-1 
Creating application-1

Structure of the chart

(base) ➜  application-1 git:(main) ✗ tree
.
├── Chart.yaml
├── charts
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── service.yaml
│   ├── serviceaccount.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml

4 directories, 10 files
(base) ➜  application-1 git:(main) ✗ 

deleted unwanted files

base) ➜  application-1 git:(main) ✗ tree
.
├── Chart.yaml
├── charts
├── templates
│   ├── deployment.yaml
│   ├── service.yaml
│   └── tests
└── values.yaml

Configuration the yamls files from scratch

create ngnix deployment with 3 replicas and use nodeport to expose ports

how to deploy the chart

(base) ➜  application-1 git:(main) ✗ helm install chart-1 .
W0323 05:55:21.671543    6164 warnings.go:70] unknown field "spec.ports[0].nodeport"
NAME: chart-1
LAST DEPLOYED: Sat Mar 23 05:55:21 2024
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

view the chart

(base) ➜  application-1 git:(main) ✗ kubectl get deploy,svc
NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/my-deployememt   0/1     1            0           49s

NAME                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
service/kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP        23m
service/my-service   NodePort    10.102.58.218   <none>        80:31492/TCP   49s
(base) ➜  application-1 git:(main) ✗ kubectl get nodes -o wide 
NAME       STATUS   ROLES           AGE   VERSION   INTERNAL-IP    EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION    CONTAINER-RUNTIME
minikube   Ready    control-plane   24m   v1.28.3   192.168.49.2   <none>        Ubuntu 22.04.3 LTS   6.6.16-linuxkit   docker://24.0.7


ip addess + port a

(base) ➜  application-1 git:(main) ✗ helm list 
NAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
chart-1 default         1               2024-03-23 05:55:21.559484 +0530 IST    deployed        application-1-0.1.0     1.16.0   

delete the chart

(base) ➜  application-1 git:(main) ✗ helm uninstall chart-1
release "chart-1" uninstalled

Deep Dive into Charts

create new chart

(base) ➜  helm-workshop git:(main) ✗ cd new-chart 
(base) ➜  new-chart git:(main) ✗ ls
Chart.yaml  charts      templates   values.yaml
(base) ➜  new-chart git:(main) ✗ 

charts

if you see your file structure you don't see charts folder

.
├── Chart.yaml
├── charts
├── templates
│   ├── NOTES.txt
│   ├── _helpers.tpl
│   ├── deployment.yaml
│   ├── hpa.yaml
│   ├── ingress.yaml
│   ├── service.yaml
│   ├── serviceaccount.yaml
│   └── tests
│       └── test-connection.yaml
└── values.yaml

Notes.txt

its container notes for user how to run this helm charts

1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
  {{- range .paths }}
  http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
  {{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
  export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "new-chart.fullname" . }})
  export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
  echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
     NOTE: It may take a few minutes for the LoadBalancer IP to be available.
           You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "new-chart.fullname" . }}'
  export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "new-chart.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
  echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
  export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "new-chart.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
  export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
  echo "Visit http://127.0.0.1:8080 to use your application"
  kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
{{- end }}

_helper

this file nothing to do with kubernetes resource its just variable

{{/*
Expand the name of the chart.
*/}}
{{- define "new-chart.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "new-chart.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "new-chart.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "new-chart.labels" -}}
helm.sh/chart: {{ include "new-chart.chart" . }}
{{ include "new-chart.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "new-chart.selectorLabels" -}}
app.kubernetes.io/name: {{ include "new-chart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Create the name of the service account to use
*/}}
{{- define "new-chart.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "new-chart.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

chart.yaml

This file contains the Helm chart metadata and version.

apiVersion: v2
name: new-chart
description: A Helm chart for Kubernetes

# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application

# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0

# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.16.0"

Working with Multiple Values

create another values file

# Default values for application-1.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
deployment:
  replicaCount: 1
  name: new-deployememt
  image:
    app: ngnix 
    version: latest

service:
  name: my-service
  type: NodePort
  port: 80
  targetPort: 80
  nodePort: 32046
  selector:
    app: ngnix   

just chamged nortport value here

install chart again

base) ➜  application-1 git:(main) ✗ helm install chart-1 .
W0325 04:26:44.306101    7525 warnings.go:70] unknown field "spec.ports[0].nodeport"
NAME: chart-1
LAST DEPLOYED: Mon Mar 25 04:26:44 2024
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None


(base) ➜  application-1 git:(main) ✗ helm list  
NAME    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                     APP VERSION
chart-1 default         1               2024-03-25 04:26:44.235604 +0530 IST    deployed        application-1-0.1.0       1.16.0     

deploy new chart

➜  application-1 git:(main) ✗ helm install chart-2 . -f new-values.yaml 
W0325 04:31:02.212820    7835 warnings.go:70] unknown field "spec.ports[0].nodeport"
NAME: chart-2
LAST DEPLOYED: Mon Mar 25 04:31:02 2024
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE: None

creating template file and access through it

create helper template file

create file with name _my-template.tpl

{{- define "labels" }}
app: ngnix
version: "1.0"
team: myteam
{{- end }}
(base) ➜  application-1 git:(main) ✗ helm template .
---
# Source: application-1/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-service
  labels:
    app: ngnix
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 80
      nodeport: 32036
      protocol: TCP
      name: http
  selector:
    app: ngnix
---
# Source: application-1/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployememt
  labels:
    
    app: ngnix
    version: "1.0"
    team: myteam    
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: "ngnix:latest"
(base) ➜  application-1 git:(main) ✗ 

"Advance Temaplate with if statement"

update your deployment file

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Values.deployment.name }}
  labels: {{- include "labels" . | nindent 4 }}    
spec:
  replicas: {{ .Values.deployment.replicaCount }}
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: "{{ .Values.deployment.image.app }}:{{ .Values.deployment.image.version }}"
          ports:
          -  name: http
             containerPort: 80
             protocol: TCP
        {{- if eq .Values.container1.enabled true }}   
        {{- include "container1" . | nindent 8 }}
        {{- end }}

create new template file

{{- define "container1" }}
- name: new-container
  image: "{{ .Values.deployment.image.app }}:{{ .Values.deployment.image.version }}"
  ports:
    - name: http
      containerPort: 80
      protocol: TCP
{{- end }}

update value file

# Default values for application-1.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
deployment:
  replicaCount: 1
  name: my-deployememt
  image:
    app: ngnix 
    version: latest

service:
  name: my-service
  type: NodePort
  port: 80
  targetPort: 80
  nodePort: 32036
  selector:
    app: ngnix   

container1:
   enabled: true    

validate template

(base) ➜  application-1 git:(main) ✗ helm template .
---
# Source: application-1/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-service
  labels:
    app: ngnix
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 80
      nodeport: 32036
      protocol: TCP
      name: http
  selector:
    app: ngnix
---
# Source: application-1/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployememt
  labels:
    
    app: ngnix
    version: "1.0"
    team: myteam    
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: "ngnix:latest"
          ports:
          -  name: http
             containerPort: 80
             protocol: TCP
        
        - name: new-container
          image: "ngnix:latest"
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
(base) ?➜  application-1 git:(main) ?✗ 

else and else if statement

update your templ

{{- define "container1" }}
- name: new-container
  image: "{{ .Values.deployment.image.app }}:{{ .Values.deployment.image.version }}"
  ports:
    - name: http
      containerPort: 80
      protocol: TCP
{{- end }}

{{- define "container2" }}
- name: new-container2
  image: "{{ .Values.deployment.image.app }}:{{ .Values.deployment.image.version }}"
  ports:
    - name: http
      containerPort: 80
      protocol: TCP
{{- end }}

make your container value as false

# Default values for application-1.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
deployment:
  replicaCount: 1
  name: my-deployememt
  image:
    app: ngnix 
    version: latest

service:
  name: my-service
  type: NodePort
  port: 80
  targetPort: 80
  nodePort: 32036
  selector:
    app: ngnix   

container1:
   enabled: false   

update your deployment file with else statement

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ .Values.deployment.name }}
  labels: {{- include "labels" . | nindent 4 }}    
spec:
  replicas: {{ .Values.deployment.replicaCount }}
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: "{{ .Values.deployment.image.app }}:{{ .Values.deployment.image.version }}"
          ports:
          -  name: http
             containerPort: 80
             protocol: TCP
        {{- if eq .Values.container1.enabled true }}   
        {{- include "container1" . | nindent 8 }}
        {{- else }}
        {{- include "container2" . | nindent 8 }}
        {{- end }}

check menfest file

(base) ➜  application-1 git:(main) ✗ helm template .
---
# Source: application-1/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-service
  labels:
    app: ngnix
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 80
      nodeport: 32036
      protocol: TCP
      name: http
  selector:
    app: ngnix
---
# Source: application-1/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployememt
  labels:
    
    app: ngnix
    version: "1.0"
    team: myteam    
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: "ngnix:latest"
          ports:
          -  name: http
             containerPort: 80
             protocol: TCP
        
        - name: new-container2
          image: "ngnix:latest"
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
(base) ➜  application-1 git:(main) ✗ 

50 Helm Template Cheatsheets

Basic Template Functions:

  1. Access a Value from values.yaml:

    replicas: {{ .Values.replicaCount }}
    
  2. Access Release Information:

    releaseName: {{ .Release.Name }}
    releaseNamespace: {{ .Release.Namespace }}
    
  3. Access Chart Information:

    chartName: {{ .Chart.Name }}
    chartVersion: {{ .Chart.Version }}
    
  4. Port Configuration:

    containerPort: {{ .Values.containerPort }}
    

Conditional Blocks:

  1. Conditional Rendering:

    {{- if .Values.enableFeature }}
    featureEnabled: true
    {{- end }}
    
  2. Conditional Rendering with Else Block:

    {{- if .Values.enableFeature }}
    featureEnabled: true
    {{- else }}
    featureEnabled: false
    {{- end }}
    

Loops:

  1. Loop Over a List:

    {{- range .Values.ingress.hosts }}
    - host: {{ . }}
    {{- end }}
    
  2. Loop Over a Map:

    {{- range $key, $value := .Values.labels }}
    {{ $key }}: {{ $value }}
    {{- end }}
    

Accessing Values:

  1. Access Nested Values:

    username: {{ .Values.database.credentials.username }}
    
  2. Quoting a Value:

    message: {{ .Values.message | quote }}
    

Including Partial Templates:

  1. Include a Partial Template:
    {{- include "partials.common" . | indent 2 }}
    

Template Functions:

  1. Convert to YAML:

    {{- toYaml .Values.config | nindent 4 }}
    
  2. Convert to JSON:

    jsonData: {{ toJson .Values.data }}
    
  3. Using Sprig Functions:

    password: {{ randAlphaNum 10 | quote }}
    

Helm Hook Templates:

  1. Pre-install Hook:

    {{- if .Values.preInstallJob }}
    # pre-install job definition
    {{- end }}
    
  2. Post-install Hook:

    {{- if .Values.postInstallJob }}
    # post-install job definition
    {{- end }}
    

Advanced Examples:

  1. Creating a Kubernetes Secret:

    apiVersion: v1
    kind: Secret
    metadata:
      name: {{ .Release.Name }}-secret
    type: Opaque
    data:
      password: {{ .Values.secret.password | b64enc }}
    
  2. Creating a Service:

    apiVersion: v1
    kind: Service
    metadata:
      name: {{ include "mychart.fullname" . }}
    
  3. Defining a ConfigMap:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: {{ include "mychart.fullname" . }}
    data:
      config.yaml: |
        {{ .Files.Get "config.yaml" | indent 4 }}
    
  4. Creating an Ingress:

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: {{ include "mychart.fullname" . }}
    spec:
      rules:
        - host: {{ .Values.ingress.host }}
    
  5. Defining a PersistentVolumeClaim:

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: {{ include "mychart.fullname" . }}-data
    
  6. Setting Resource Limits:

    resources:
      limits:
        cpu: {{ .Values.resources.cpu | quote }}
        memory: {{ .Values.resources.memory | quote }}
    
  7. Creating a Job:

    apiVersion: batch/v1
    kind: Job
    metadata:
      name: {{ .Release.Name }}-job
    spec:
      template:
        spec:
          containers:
          - name: {{ .Chart.Name }}-job
            image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
            command: ["{{ .Values.command }}"]
    
  8. Creating a CronJob:

    apiVersion: batch/v1beta1
    kind: CronJob
    metadata:
      name: {{ .Release.Name }}-cronjob
    spec:
      schedule: "*/1 * * * *"
      jobTemplate:
        spec:
          template:
            spec:
              containers:
              - name: {{ .Chart.Name }}-cronjob
                image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
                command: ["{{ .Values.command }}"]
    
  9. Creating a StatefulSet:

    apiVersion: apps/v1
    kind: StatefulSet
    metadata:
      name: {{ .Release.Name }}-statefulset
    
  10. Creating a Deployment with Liveness and Readiness Probes:

    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: {{ .Release.Name }}-deployment
    spec:
      template:
        spec:
          containers:
          - name: {{ .Chart.Name }}-container
            image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
            livenessProbe:
              httpGet:
                path: /healthz
                port: 80
              initialDelaySeconds: 30
            readinessProbe:
              httpGet:
                path: /readyz
                port: 80
              initialDelaySeconds: 5
    
  11. Creating a Horizontal Pod Autoscaler (HPA):

    apiVersion: autoscaling/v2beta2
    kind: HorizontalPodAutoscaler
    metadata:
      name: {{ .Release.Name }}-hpa
    spec:
      scaleTargetRef:
        apiVersion: apps/v1
        kind: Deployment
        name: {{ .Release.Name }}-deployment
      minReplicas: 1
      maxReplicas: 10
      metrics:
      - type: Resource
        resource:
          name: cpu
          targetAverageUtilization: 50
    

Accessing Values:

  1. Accessing Values from Dependencies:

    dependencyValue: {{ .Values.dependencies.subchart.value }}
    
  2. Accessing Values with Default:

    port: {{ .Values.port | default 8080 }}
    

Advanced Conditional Blocks:

  1. Conditional Block with Nested Conditions:

    {{- if and .Values.condition1 .Values.condition2 }}
    # Block content
    {{- end }}
    
  2. Conditional Block with OR Operator:

    {{- if or .Values.condition1 .Values.condition2 }}
    # Block content
    {{- end }}
    

Advanced Loops:

  1. Loop with Index:

    {{- range $index, $element := .Values.list }}
    - index: {{ $index }}, value: {{ $element }}
    {{- end }}
    
  2. Loop with Sorting:

    {{- range sort .Values.list }}
    - value: {{ . }}
    {{- end }}
    

Advanced Template Functions:

  1. Using tpl Function for Advanced Template Rendering:

    renderedTemplate: {{ tpl (.Files.Get "template.yaml") . | indent 4 }}
    
  2. Using include with Dynamic Name:

    {{- include (printf "%s-config" .Values.serviceName) . | indent 2 }}
    

External Template Files:

  1. Including External Template File:
    {{- include "external-template.tpl" . | indent 2 }}
    

Debugging:

  1. Printing Values for Debugging:
    {{- printf "%#v" .Values | nindent 2 }}
    

Naming Conventions:

  1. Using Release Name and Chart Name for Naming Resources:
    metadata:
      name: {{ .Release.Name }}-{{ .Chart.Name }}
    

Comments:

  1. Adding Comments in Templates:
    # This is a comment
    

External Resources:

  1. Mounting External Files as ConfigMaps:
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: my-configmap
    data:
      {{ .Files.Get "config-file.yaml" | indent 2 }}
    

Combining Functions:

  1. Combining Functions for Complex Operations:
    combinedValue: {{ trimPrefix "prefix-" (upper .Values.value) }}
    

Advanced StatefulSet Configuration:

  1. StatefulSet with Persistent Volume Claim:
    volumeClaimTemplates:
      - metadata:
          name: data
        spec:
          accessModes: [ "ReadWriteOnce" ]
          resources:
            requests:
              storage: 1Gi
    

External Secrets:

  1. Referencing External Secrets:
    apiVersion: v1
    kind: Secret
    metadata:
      name: my-secret
      annotations:
        "helm.sh/resource-policy": keep
    type: Opaque
    data:
      password: {{ .Values.externalSecret.password | b64enc }}
    

Helm Release Specifics:

  1. Accessing Release Timestamp:
    releaseDate: {{ .Release.Timestamp }}
    

Debugging with printf:

  1. Debugging with printf:
    {{ printf "%#v" .Values | nindent 2 }}
    

Using quote and unquote Functions:

  1. Quoting and Unquoting Values:
    quotedValue: {{ .Values.someValue | quote }}
    unquotedValue: {{ .Values.quotedValue | unquote }}
    

Advanced Resource Definitions:

  1. Advanced Pod Annotations:
    annotations:
      myAnnotation: {{ .Values.annotations.myAnnotation | quote }}
    

Configurable Labels:

  1. Configurable Labels:
    labels:
      myLabel: {{ .Values.labels.myLabel | quote }}
    

Conditional Pod Disruption Budget:

  1. Conditional Pod Disruption Budget:
    {{- if .Values.enablePodDisruptionBudget }}
    apiVersion: policy/v1beta1
    kind: PodDisruptionBudget
    metadata:
      name: {{ include "mychart.fullname" . }}
    spec:
      # PDB specification
    {{- end }}
    

Helm Template Debugging:

  1. Template Debugging with required Function:
    requiredValue: {{ required "Value is required" .Values.requiredValue }}
    

Multiple pipelines:

  1. Manipulate value with multiple pipelines:
    domain: {{ .Values.domain | lower | trunc 9 | quote}}