All Things Helm 3.0

What is Helm?

Helm is a package manager for Kubernetes.

A package manager generally aims to provide a single command to install some software. Installing software likely has dependencies – a package manager should be able to resolve those dependencies. A package manager is supposed to abstract some complexities of installing software and making it easier to update, upgrade and remove the software.

What can Helm do for us?

  1. Single command installation – helm install
  2. Ability to roll back – helm rollback
  3. Get state information – helm status
  4. Simplified upgrades- helm upgrade
  5. Single command uninstall – helm uninstall

Want to install helm? Grab the installation script from the official guide, and run it.

curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3
chmod 700 get_helm.sh
./get_helm.sh

#Confirm that the installation was successful

helm version
version.BuildInfo{Version:"v3.5.0", GitCommit:"32c22239423b3b4ba6706d450bd044baffdcf9e6", GitTreeState:"clean", GoVersion:"go1.15.6"}

Helm Charts

Charts is the packaging format for Helm. A chart is nothing but a collection of files with a specific file structure that represents resources within Kubernetes. The name of the folder is the name of the chart. A chart contains all the files for a Kubernetes deployment.

Chart Repositories

A chart repository is an HTTP server that serves the packaged charts. A packaged chart is a Helm chart that is processed into an archive (tar) by using the following command and a name.

helm package chartname

Note: A chart repository serves an index.yaml file. This file is the source of truth of packaged charts and where they are. (Example: https://charts.helm.sh/stable/index.yaml)

The following section contains some commonly used commands.

Add a repository:

helm repo add stable https://charts.helm.sh/stable
"stable" has been added to your repositories

# Note: "stable" after the add argument is the name of the repository which can be changed. 

List the added repositories if the repositories are already configured:

helm reop list
NAME    URL
stable  https://charts.helm.sh/stable

Search and Download (or fetch) a chart:

# search a chart
helm search repo apache

# download a chart
helm fetch stable/spark

ls
spark-1.0.5.tgz

Create a repository index from packaged charts:

# We have a number of packaged helm charts in a directory
ls sample
kafka-manager-2.3.5.tgz  spark-1.0.5.tgz

# create an index and give the directory as the argument
helm repo index ./sample/

# Notice that now we have an index file in the sample repository

cat sample/index.yaml

apiVersion: v1
entries:
  kafka-manager:
  - apiVersion: v1
    appVersion: 1.3.3.22
    created: "2021-05-23T17:36:13.257252559Z"
    dependencies:
    - condition: zookeeper.enabled
      name: zookeeper
      repository: https://charts.helm.sh/incubator
      version: 2.1.4
    deprecated: true
    description: DEPRECATED - A tool for managing Apache Kafka.
    digest: 2570c27581a7b51e50e5857836aae0c1c86293cd68e36836cd7d91006520b84d
    home: https://github.com/yahoo/kafka-manager
    icon: https://kafka.apache.org/images/logo.png
    keywords:
    - kafka
    - zookeeper
    - kafka-manager
    kubeVersion: ^1.8.0-0
    name: kafka-manager
    sources:
    - https://github.com/yahoo/kafka-manager
    urls:
    - kafka-manager-2.3.5.tgz
    version: 2.3.5
  spark:
  - apiVersion: v1
    appVersion: 1.5.1
    created: "2021-05-23T17:36:13.258001094Z"
    deprecated: true
    description: DEPRECATED - Fast and general-purpose cluster computing system.
    digest: e0b4862812f85dcf7b92d71ed90e9f894f1aef35bb76f384fe322ba736cd10fc
    home: http://spark.apache.org
    icon: http://spark.apache.org/images/spark-logo-trademark.png
    name: spark
    sources:
    - https://github.com/kubernetes/kubernetes/tree/master/examples/spark
    - https://github.com/apache/spark
    urls:
    - spark-1.0.5.tgz
    version: 1.0.5

Update or remove repositories:

helm repo update . 

helm repo remove name

Install, get status or remove a chart:

#search for an example chart, wordpress in our case. 
helm search repo wordpress
NAME                    CHART VERSION   APP VERSION     DESCRIPTION
stable/wordpress        9.0.3           5.3.2           DEPRECATED Web publishing platform for building...

#install
helm install wordpress stable/wordpress

#You'll see the pods appear in your Kubernetes cluster
kubectl get pods
NAME                         READY   STATUS    RESTARTS   AGE
wordpress-6d8b97544f-jt7pc   0/1     Pending   0          60s
wordpress-mariadb-0          0/1     Pending   0          59s

#See the status of helm chart in helm

helm ls
NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
wordpress       default         1               2021-05-23 18:07:33.476648857 +0000 UTC deployed        wordpress-9.0.3 5.3.2

#Delete the installation
helm delete wordpress
release "wordpress" uninstalled

Releases in Helm

While a chart contains the structure of objects that you’ll need for a Kubernetes deployment, it will require values and other information for deployment. When we install a chart, the structure will be combined with Values to create objects in a Kubernetes cluster. This combination of chart and values is called a release.

Each Chart has a version number and a REVISION number. We saw the following output in the wordpress installation after we installed the wordpress chart. Note the REVISION number.

NAME: wordpress
LAST DEPLOYED: Sun May 23 18:15:24 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
This Helm chart is deprecated

If you look at the Chart.yaml file in the wordpress chart, you’ll notice that the chart version number is 9.0.3.

cat Chart.yaml
apiVersion: v1
appVersion: 5.3.2
deprecated: true
description: DEPRECATED Web publishing platform for building blogs and websites.
engine: gotpl
home: http://www.wordpress.com/
icon: https://bitnami.com/assets/stacks/wordpress/img/wordpress-stack-220x234.png
keywords:
- wordpress
- cms
- blog
- http
- web
- application
- php
name: wordpress
sources:
- https://github.com/bitnami/bitnami-docker-wordpress
version: 9.0.3

# This was the version that was deployed (You might have to install the wordpress chart again if you're following) 
helm ls
NAME            NAMESPACE       REVISION        UPDATED                                 STATUS          CHART           APP VERSION
wordpress       default         1               2021-05-23 18:15:24.991379171 +0000 UTC deployed        wordpress-9.0.3 5.3.2

Let’s change the above installation. We can do that by using helm upgrade command.

# Let's say in the example, we want to change the mariadb version. 
helm upgrade wordpress stable/wordpress --set image.tag='docker.io/bitnami/mariadb:10.3.21-debian-10-r27'

# check the status of wordpress installation
helm status wordpress
NAME: wordpress
LAST DEPLOYED: Sun May 23 18:27:00 2021
NAMESPACE: default
STATUS: deployed
REVISION: 2
NOTES:
This Helm chart is deprecated

#Note that the REVISION is changed to 2. 

Note that the Chart.yaml file which is fetched locally remains unchanged by an upgrade command. If you want to change the chart permanently, you need to change the value inside the chart file.

Chart Structure

The following folder structure shows a structure of a chart and how files are laid out.

wordpress/
  Chart.yaml          # A YAML file containing information about the chart
  LICENSE             # OPTIONAL: A plain text file containing the license for the chart
  README.md           # OPTIONAL: A human-readable README file
  values.yaml         # The default configuration values for this chart
  values.schema.json  # OPTIONAL: A JSON Schema for imposing a structure on the values.yaml file
  charts/             # A directory containing any charts upon which this chart depends.
  crds/               # Custom Resource Definitions
  templates/          # A directory of templates that, when combined with values,
                      # will generate valid Kubernetes manifest files.
  templates/NOTES.txt # OPTIONAL: A plain text file containing short usage notes

If you want to create a demo chart, you can do that with a helm create command. Also, if you do a dry run on the newly created helm chart, helm will output the yaml file

# Create a demo chart
helm create demo

# You can do a dry run to check how helm converts the chart to a Kubernetes manifest file

helm install demo ./demo --dry-run

NAME: demo
LAST DEPLOYED: Sun May 23 20:45:34 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
HOOKS:
---
# Source: demo/templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
  name: "demo-test-connection"
  labels:
    helm.sh/chart: demo-0.1.0
    app.kubernetes.io/name: demo
    app.kubernetes.io/instance: demo
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
  annotations:
    "helm.sh/hook": test
spec:
  containers:
    - name: wget
      image: busybox
      command: ['wget']
      args: ['demo:80']
  restartPolicy: Never
MANIFEST:
---
# Source: demo/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: demo
  labels:
    helm.sh/chart: demo-0.1.0
    app.kubernetes.io/name: demo
    app.kubernetes.io/instance: demo
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
---
# Source: demo/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: demo
  labels:
    helm.sh/chart: demo-0.1.0
    app.kubernetes.io/name: demo
    app.kubernetes.io/instance: demo
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
spec:
  type: ClusterIP
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app.kubernetes.io/name: demo
    app.kubernetes.io/instance: demo
---
# Source: demo/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: demo
  labels:
    helm.sh/chart: demo-0.1.0
    app.kubernetes.io/name: demo
    app.kubernetes.io/instance: demo
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: demo
      app.kubernetes.io/instance: demo
  template:
    metadata:
      labels:
        app.kubernetes.io/name: demo
        app.kubernetes.io/instance: demo
    spec:
      serviceAccountName: demo
      securityContext:
        {}
      containers:
        - name: demo
          securityContext:
            {}
          image: "nginx:1.16.0"
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          resources:
            {}

NOTES:
1. Get the application URL by running these commands:
  export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=demo,app.kubernetes.io/instance=demo" -o jsonpath="{.items[0].metadata.name}")
  export CONTAINER_PORT=$(kubectl get pod --namespace default $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
  echo "Visit http://127.0.0.1:8080 to use your application"
  kubectl --namespace default port-forward $POD_NAME 8080:$CONTAINER_PORT

Read Values from an Existing Chart

If you wanted to read just values from an existing chart, you can also use helm show values command. It will show values and strip out other information from a chart which makes it (a little bit) easier to read the values.

helm show values demo

# Default values for demo.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

replicaCount: 1

image:
  repository: nginx
  pullPolicy: IfNotPresent
  # Overrides the image tag whose default is the chart appVersion.
  tag: ""

imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""

serviceAccount:
  # Specifies whether a service account should be created
  create: true
  # Annotations to add to the service account
  annotations: {}
  # The name of the service account to use.
  # If not set and create is true, a name is generated using the fullname template
  name: ""

podAnnotations: {}

podSecurityContext: {}
  # fsGroup: 2000

securityContext: {}
  # capabilities:
  #   drop:
  #   - ALL
  # readOnlyRootFilesystem: true
  # runAsNonRoot: true
  # runAsUser: 1000

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: false
  className: ""
  annotations: {}
    # kubernetes.io/ingress.class: nginx
    # kubernetes.io/tls-acme: "true"
  hosts:
    - host: chart-example.local
      paths:
        - path: /
          pathType: ImplementationSpecific
  tls: []
  #  - secretName: chart-example-tls
  #    hosts:
  #      - chart-example.local

resources: {}
  # We usually recommend not to specify default resources and to leave this as a conscious
  # choice for the user. This also increases chances charts run on environments with little
  # resources, such as Minikube. If you do want to specify resources, uncomment the following
  # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
  # limits:
  #   cpu: 100m
  #   memory: 128Mi
  # requests:
  #   cpu: 100m
  #   memory: 128Mi

autoscaling:
  enabled: false
  minReplicas: 1
  maxReplicas: 100
  targetCPUUtilizationPercentage: 80
  # targetMemoryUtilizationPercentage: 80

nodeSelector: {}

tolerations: []

affinity: {}

Chart Modifications

There are three main ways to modify a helm charts.

Inline modification using set

If you want to just test a few values, you can use –set option with the install command. This will override the values from values.yaml file. This method is usually used in a proof of concept type environment.

If you dry run the demo chart that we created earlier (helm install demo demo –dry-run), by default it uses nginx:1.16.0 image.

Now if you want to change this image, you can do that by –set option.

helm install demo demo --set image.tag=latest --dry-run
# Side note: the first "demo" argument is the name of the deployment and the second "demo" argument is the name of our chart folder. 
# you can do multiple sets together

Passing a file

You can also pass a file that contains the values that you want to override from the values.yaml.

In the same example that we used above, we can create a yaml file with the image tag that we want to override.

image:
	tag: latest
# install the demo chart with input of the above yaml file to override values

helm install demo demo -f override_values.yaml

Change values.yaml

Last but not least, you can modify the values.yaml instead of overriding values via passing a file or setting values inline. This effectively creates a new chart.

Subcharts

A parent chart can have a subchart located in charts directory in the main chart folder. Each chart has its own values file. The parent chart can override the value of a subchart by defining the value in its own (parent’s) values.yaml file.

Continuing our earlier example of wordpress chart, you can see that wordpress chart has a subchart of mariadb.

├── charts
│   └── mariadb
│       ├── Chart.yaml
│       ├── files
│       │   └── docker-entrypoint-initdb.d
│       │       └── README.md
│       ├── OWNERS
│       ├── README.md
│       ├── templates
│       │   ├── _helpers.tpl
│       │   ├── initialization-configmap.yaml
│       │   ├── master-configmap.yaml
│       │   ├── master-pdb.yaml
│       │   ├── master-statefulset.yaml
│       │   ├── master-svc.yaml
│       │   ├── NOTES.txt
│       │   ├── rolebinding.yaml
│       │   ├── role.yaml
│       │   ├── secrets.yaml
│       │   ├── serviceaccount.yaml
│       │   ├── servicemonitor.yaml
│       │   ├── slave-configmap.yaml
│       │   ├── slave-pdb.yaml
│       │   ├── slave-statefulset.yaml
│       │   ├── slave-svc.yaml
│       │   ├── test-runner.yaml
│       │   └── tests.yaml
│       ├── values-production.yaml
│       ├── values.schema.json
│       └── values.yaml
├── Chart.yaml
├── README.md
├── requirements.lock
├── requirements.yaml
├── templates
│   ├── deployment.yaml
│   ├── externaldb-secrets.yaml
│   ├── _helpers.tpl
│   ├── ingress.yaml
│   ├── NOTES.txt
│   ├── pvc.yaml
│   ├── secrets.yaml
│   ├── servicemonitor.yaml
│   ├── svc.yaml
│   ├── tests
│   │   └── test-mariadb-connection.yaml
│   └── tls-secrets.yaml
├── values.schema.json
└── values.yaml

A child chart cannot access values in the parent folders. If you want a child chart to access value from a parent chart, you need to create a global value. Global values can be accessed by both the parent all subcharts. Global values are defined using the global keyword. In our example, here are some global values in the main values.yaml file. Although commented out, but shows an example.

##
# global:
#   imageRegistry: myRegistryName
#   imagePullSecrets:
#     - myRegistryKeySecretName
#   storageClass: myStorageClass

Chart Hooks

Chart hooks provide a way to allow chart developers to have control at certain points during a chart’s lifecycle. Hooks inject a job at certain points in chart lifecycles.

For example, after we complete a release, we need to load some data in that release. We can use post install hook to run a pod that loads data.

These are some of the hook types which are available at the time of the writing.

Hook TypeDescription
Pre-InstallExecutes after templates are rendered but before resource creation in k8s.
Post-InstallAfter all resources are loaded in k8s.
Pre-DeleteBefore a resource is deleted.
Post-DeleteAfter a resource is deleted.
Pre-UpgradeAfter templates are rendered but before resource updates in k8s.
Post-UpgradeAfter all resources are updated.
Pre-RollbackAfter templates are rendered but before resource roll backs.
Post-RollbackAfter all resources are rolled back.
TestExecutes when helm test is invoked.

Some pointers on hooks

  • A hook is defined in its annotation. It is a template that has some special annotations to convert it into a hook.
  • Hooks are part of a chart. A parent chart cannot override subchart’s hooks.
  • Hooks have weights. If there are multiple hooks, you can provide it a priority by assigning weights to hooks. The hook with the lowest weight executes first.
  • If hooks fail, the release will fail.
  • There’s no limit on number of hooks.
  • We make to make sure that hook jobs deletes or cleans itself because hook objects stand alone. When a release is deleted, hook resources can persist.

Hook example

Let’s create a demo chart for hooks. We’ll create a file named hook.yaml in templates directory. This example is of a post-install example which means that this pod will run after our release is complete.

helm create demo-hook
nano demo-hook/templates/hook.yaml

#contents of hook.yaml
apiVersion: v1
kind: Pod
metadata:
  name: posthook
  annotations:
    "helm.sh/hook": "post-install"
    "helm.sh/hook-weight": "0"
    #"helm.sh/hook-delete-policy": hook-succeeded
spec:
  containers:
  - name: democontainer
    image: busybox
    imagePullPolicy: IfNotPresent
    command: ['sh', '-c', 'echo post-install hook Pod is running && sleep 20']
  restartPolicy: Never
  terminationGracePeriodSeconds: 0

helm install demo-hook ./demo-hook/
NAME: demo-hook
LAST DEPLOYED: Sat Jun 19 12:39:35 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
NOTES:
1. Get the application URL by running these commands:
  export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=demo-hook,app.kubernetes.io/instance=demo-hook" -o jsonpath="{.items[0].metadata.name}")
  export CONTAINER_PORT=$(kubectl get pod --namespace default $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
  echo "Visit http://127.0.0.1:8080 to use your application"
  kubectl --namespace default port-forward $POD_NAME 8080:$CONTAINER_PORT

kubectl get pods
NAME                         READY   STATUS      RESTARTS   AGE
demo-hook-795cc96467-xdrwf   1/1     Running     0          30s
posthook                     0/1     Completed   0          30s

Note the output of the last command where we can see the posthook pod as a complete pod. This is because hook-delete-policy line is commented out in the YAML file. If we uncomment that line, the posthook pod in the last command will not be part of the output.

Test Hooks

A test is a type of hook with a job definition that specifies a container with a command to run. If the command succeeds, then the container should exist with a success code.

Helm will create an example test by default in In demo-hook/templates/tests/test-connection.yaml as part of chart creation process. Here are the contents of that test-connection.yaml file. You’ll see in annotations that this is a hook of type test.

cat demo-hook/templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
  name: "{{ include "demo-hook.fullname" . }}-test-connection"
  labels:
    {{- include "demo-hook.labels" . | nindent 4 }}
  annotations:
    "helm.sh/hook": test
spec:
  containers:
    - name: wget
      image: busybox
      command: ['wget']
      args: ['{{ include "demo-hook.fullname" . }}:{{ .Values.service.port }}']
  restartPolicy: Never

Now if you do run helm test with the deployment name, it will create a container that runs that test command for us.

#run the test suite in the demo-hook release
helm test demo-hook
NAME: demo-hook
LAST DEPLOYED: Sat Jun 19 18:10:58 2021
NAMESPACE: default
STATUS: deployed
REVISION: 1
TEST SUITE:     demo-hook-test-connection
Last Started:   Sat Jun 19 18:11:55 2021
Last Completed: Sat Jun 19 18:13:56 2021
Phase:          Succeeded

Library Charts

A library chart is a boilerplate helm chart that defines chart primitives and definitions for sharing templates with the goal of reducing repetition. It is important to note that in the templates directory, any file starting with an underscore (_) does not output to a manifest file. By convention, helper templates are placed in files with a naming pattern of _*.yaml or _*.tpl.

Here’s an example:

# Create a new chart 
helm create libdemo

# remove all templates and the value file

rm -rf libdemo/templates/*
rm -f libdemo/values.yaml 

# You'll have two directories and one Chart.yaml file
tree libdemo/
libdemo/
├── charts
├── Chart.yaml
└── templates

2 directories, 1 file

We’ll create a common ConfigMap which creates a data resource with a defaultvalue config. This means that any chart that inherits this configmap will inherit this default value.

nano libdemo/templates/_configmap.yaml

{{- define "libdemo.configmap.tpl" -}}
apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name | printf "%s-%s" .Chart.Name }}
data:
 defaultvalue: defaultvalue
{{- end -}}
{{- define "libdemo.configmap" -}}
{{- include "libdemo.util.merge" (append . "libdemo.configmap.tpl") -}}
{{- end -}}

# Note that the above file includes another named template (libdemo.configmap). 

Next, we’ll change the chart type to library in Chart.yaml.

cat libdemo/Chart.yaml
apiVersion: v2
name: libdemo
description: A Helm chart for Kubernetes
type: library
version: 0.1.0
appVersion: "1.16.0"

# We need to ensure that we add the utility function that we're using to merge two YAML templates. 
nano libdemo/templates/_util.yaml
{{- /*
libdemo.util.merge will merge two YAML templates and output the result.
This takes an array of three values:
- the top context
- the template name of the overrides (destination)
- the template name of the base (source)
*/}}
{{- define "libdemo.util.merge" -}}
{{- $top := first . -}}
{{- $overrides := fromYaml (include (index . 1) $top) | default (dict ) -}}
{{- $tpl := fromYaml (include (index . 2) $top) | default (dict ) -}}
{{- toYaml (merge $overrides $tpl) -}}
{{- end -}}

# Now if you try to install this chart, you'll get an error confirming that library charts are not installable

helm install libdemo libdemo/
Error: library charts are not installable

Now if you want to use the above library chart, let’s create another chart, and include our common configmap in the new chart. This configmap will get all standard properties defined in the common configmap and just add myvalue in addition to that.

helm create usinglibdemo

#add a config map that will inherit configmap definition that we created earlier. 

nano usinglibdemo/templates/configmap.yaml

{{- include "libdemo.configmap" (list . "mychart.configmap") -}}
{{- define "mychart.configmap" -}}
data:
  myvalue: "Hello World"
{{- end -}}

Before we try generating the above configmap, we will add the earlier libdemo chart as a dependency in usinglibdemo chart.

nano usinglibdemo/Chart.yaml

apiVersion: v2
name: usinglibdemo
description: A Helm chart for Kubernetes
dependencies:
- name: libdemo
  version: 0.1.0
  repository: file://../libdemo

type: application

version: 0.1.0

appVersion: "1.16.0"

# update dependencies in usinglibdemo
helm dependency update usinglibdemo
Saving 1 charts
Deleting outdated charts

Now if you do a dry run, you’ll see your configmap rendered as part of the manifest and it includes the default value we defined in our libraryl.

helm install usinglibdemo usinglibdemo/ --debug --dry-run
install.go:173: [debug] Original chart version: ""
install.go:190: [debug] CHART PATH: /home/user/usinglibdemo

NAME: usinglibdemo
LAST DEPLOYED: Sun Jun 20 14:51:02 2021
NAMESPACE: default
STATUS: pending-install
REVISION: 1
USER-SUPPLIED VALUES:
{}

COMPUTED VALUES:
affinity: {}
autoscaling:
  enabled: false
  maxReplicas: 100
  minReplicas: 1
  targetCPUUtilizationPercentage: 80
fullnameOverride: ""
image:
  pullPolicy: IfNotPresent
  repository: nginx
  tag: ""
imagePullSecrets: []
ingress:
  annotations: {}
  enabled: false
  hosts:
  - host: chart-example.local
    paths: []
  tls: []
libdemo:
  global: {}
nameOverride: ""
nodeSelector: {}
podAnnotations: {}
podSecurityContext: {}
replicaCount: 1
resources: {}
securityContext: {}
service:
  port: 80
  type: ClusterIP
serviceAccount:
  annotations: {}
  create: true
  name: ""
tolerations: []

HOOKS:
---
# Source: usinglibdemo/templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
  name: "usinglibdemo-test-connection"
  labels:
    helm.sh/chart: usinglibdemo-0.1.0
    app.kubernetes.io/name: usinglibdemo
    app.kubernetes.io/instance: usinglibdemo
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
  annotations:
    "helm.sh/hook": test
spec:
  containers:
    - name: wget
      image: busybox
      command: ['wget']
      args: ['usinglibdemo:80']
  restartPolicy: Never
MANIFEST:
---
# Source: usinglibdemo/templates/serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: usinglibdemo
  labels:
    helm.sh/chart: usinglibdemo-0.1.0
    app.kubernetes.io/name: usinglibdemo
    app.kubernetes.io/instance: usinglibdemo
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
---
# Source: usinglibdemo/templates/configmap.yaml
apiVersion: v1
data:
  defaultvalue: defaultvalue
  myvalue: Hello World
kind: ConfigMap
metadata:
  name: usinglibdemo-usinglibdemo
---
# Source: usinglibdemo/templates/service.yaml
apiVersion: v1
kind: Service
metadata:
  name: usinglibdemo
  labels:
    helm.sh/chart: usinglibdemo-0.1.0
    app.kubernetes.io/name: usinglibdemo
    app.kubernetes.io/instance: usinglibdemo
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
spec:
  type: ClusterIP
  ports:
    - port: 80
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app.kubernetes.io/name: usinglibdemo
    app.kubernetes.io/instance: usinglibdemo
---
# Source: usinglibdemo/templates/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: usinglibdemo
  labels:
    helm.sh/chart: usinglibdemo-0.1.0
    app.kubernetes.io/name: usinglibdemo
    app.kubernetes.io/instance: usinglibdemo
    app.kubernetes.io/version: "1.16.0"
    app.kubernetes.io/managed-by: Helm
spec:
  replicas: 1
  selector:
    matchLabels:
      app.kubernetes.io/name: usinglibdemo
      app.kubernetes.io/instance: usinglibdemo
  template:
    metadata:
      labels:
        app.kubernetes.io/name: usinglibdemo
        app.kubernetes.io/instance: usinglibdemo
    spec:
      serviceAccountName: usinglibdemo
      securityContext:
        {}
      containers:
        - name: usinglibdemo
          securityContext:
            {}
          image: "nginx:1.16.0"
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          resources:
            {}

NOTES:
1. Get the application URL by running these commands:
  export POD_NAME=$(kubectl get pods --namespace default -l "app.kubernetes.io/name=usinglibdemo,app.kubernetes.io/instance=usinglibdemo" -o jsonpath="{.items[0].metadata.name}")
  export CONTAINER_PORT=$(kubectl get pod --namespace default $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
  echo "Visit http://127.0.0.1:8080 to use your application"
  kubectl --namespace default port-forward $POD_NAME 8080:$CONTAINER_PORT

Packaging and Validating Charts

When we package a chart, we can sign it using a key by which helm will generate a signature of the chart – this will produce a chart in .tgz format. It also generates a provenance file which can be used to confirm that the chart has not been altered after it was signed. Here’s an example of how we can create a gpg key and sign a package.

# Create a gpg key 
gpg --full-generate-key

# Follow the prompts in the commandline. I've named the key as testkey
gpg --list-keys
/home/user/.gnupg/pubring.kbx
----------------------------------------------
pub   rsa3072 2021-06-20 [SC]
      9DC3BC5B27D3BC09DE6DE58474C435882DDA8D6F
uid           [ultimate] testkey (nocomments) <testkey@email.email>
sub   rsa3072 2021-06-20 [E]

# Helm doesn't work with the latest .kbx file from gpg. So we need to export the private key in secring.gpg file.
gpg --export-secret-keys >~/.gnupg/secring.gpg

# Now we can use the testkey to sign our chart.
helm package --sign --key testkey --keyring ~/.gnupg/secring.gpg usinglibdemo
Successfully packaged chart and saved it to: /home/user/usinglibdemo-0.1.0.tgz

# Note that this will give us two files. The packaged file usinglibdemo-0.1.0.tgz and a provenance file usinglibdemo-0.1.0.tgz.prov where the signature is stored.

# now you can verify your packaged chart with helm verify usinglibdemo-0.1.0.tgz command

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s