Den Dribbles

Intro To Helm

April 22, 2019

Intro to Helm

Helm is the best way to find, share and use software built for Kubernetes.

  • Package manager for Kubernetes.
  • Helps you manage Kubernetes apps.
  • Maintained by CNCF.

To use, download the Helm client.

To run, use helm init.

  • This will installer Tiller
  • If you have RBAC installed (recent clusters have it enabled by default), you’ll also need to add a ServiceAccount and RBAC rules.

Helm uses a packaging format call charts.

  • A chart is a collection of files that describe a set of Kubernetes resources.
  • A single chart can deploy an app, a piece of software or a database.
  • It can have depencies ie Wordpress chart requires mysql chart.
  • You can also write your own chart.

Helm commands

CommandDescription
helm initInstall tiller on the cluser
helm resetRemove tiller
helm install <CHART>Install chart
helm search <CHART>Searches for chart
helm search redisLooks for Redis chart
helm install —name myredis stable/redisInstalls Redis chart found under myredis
helm delete myredisDelete Redis install named myredis
helm create <CHART_NAME>Create your own chart
helm update <OPTIONS> <CHART> path/to/chartUpdate the chart
helm history <CHART_NAME>See upgrade history of chart
helm rollback <CHART_NAME> <REVISION>Rollback to version
helm listList running charts
helm list —allList all charts that have ran
helm delete <CHART_NAME> —purgeRelease deleted chart

Installing Helm

curl https://raw.githubusercontent.com/helm/helm/master/scripts/get > get_helm.sh
chmod 700 get_helm.sh
./get_helm.sh

Alternatively:

curl https://raw.githubusercontent.com/helm/helm/master/scripts/get | bash

Linux Distro Install

wget https://kubernetes-helm.storage.googleapis.com/helm-v2.11.0-linux-amd64.tar.gz
tar -xzvf helm-v2.11.0-linux-amd64.tar.gz
sudo mv linux-amd64/helm /usr/local/bin/helm

Adding to cluster

# helm-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: tiller
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: tiller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: tiller
    namespace: kube-system
kubectl apply -f helm-rbac.yaml
helm init --service-account tiller

Creating your own helm charts

This is the recommended way to deploy applications.

  • Packaging the app allows you to deploy the app in 1 command.
  • Helm allows for upgrades and rollbacks.
  • Helm chart is also version controlled.
# creates director mychart/
helm create mychart
ls mychart
# Displays Chart.yaml  charts  templates  values.yaml

values.yaml will control things such as replicas, image etc.

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

replicaCount: 1

image:
  repository: nginx
  tag: stable
  pullPolicy: IfNotPresent

nameOverride: ""
fullnameOverride: ""

service:
  type: ClusterIP
  port: 80

ingress:
  enabled: false
  annotations:
    {}
    # kubernetes.io/ingress.class: nginx
    # kubernetes.io/tls-acme: "true"
  paths: []
  hosts:
    - chart-example.local
  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

nodeSelector: {}

tolerations: []

affinity: {}

Inside the mychart/templates folder we have…

ls mychart/templates
# shows NOTES.txt  _helpers.tpl  deployment.yaml  ingress.yaml  service.yaml  tests

Looking at the deployment.yaml we see the following:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: {{ include "test.fullname" . }}
  labels:
    app.kubernetes.io/name: {{ include "test.name" . }}
    helm.sh/chart: {{ include "test.chart" . }}
    app.kubernetes.io/instance: {{ .Release.Name }}
    app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
  replicas: {{ .Values.replicaCount }}
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ include "test.name" . }}
      app.kubernetes.io/instance: {{ .Release.Name }}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: {{ include "test.name" . }}
        app.kubernetes.io/instance: {{ .Release.Name }}
    spec:
      containers:
        - name: {{ .Chart.Name }}
          image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
          imagePullPolicy: {{ .Values.image.pullPolicy }}
          ports:
            - name: http
              containerPort: 80
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /
              port: http
          readinessProbe:
            httpGet:
              path: /
              port: http
          resources:
            {{- toYaml .Values.resources | nindent 12 }}
      {{- with .Values.nodeSelector }}
      nodeSelector:
        {{- toYaml . | nindent 8 }}
      {{- end }}
    {{- with .Values.affinity }}
      affinity:
        {{- toYaml . | nindent 8 }}
    {{- end }}
    {{- with .Values.tolerations }}
      tolerations:
        {{- toYaml . | nindent 8 }}
    {{- end }}

These values will be filled out when deployed.

The spec values are generally defined by the earlier values.yaml.

The mychart/service.yaml also templates how the service file will be created:

apiVersion: v1
kind: Service
metadata:
  name: { { include "test.fullname" . } }
  labels:
    app.kubernetes.io/name: { { include "test.name" . } }
    helm.sh/chart: { { include "test.chart" . } }
    app.kubernetes.io/instance: { { .Release.Name } }
    app.kubernetes.io/managed-by: { { .Release.Service } }
spec:
  type: { { .Values.service.type } }
  ports:
    - port: { { .Values.service.port } }
      targetPort: http
      protocol: TCP
      name: http
  selector:
    app.kubernetes.io/name: { { include "test.name" . } }
    app.kubernetes.io/instance: { { .Release.Name } }

From here, you can directly install the helm chart using helm install mychart/.

Using the default chart, there is a nginx configuration you then port forward and curl.

kubectl port-forward 80:8080
# Press ^z here
bg # set to background
curl localhost:8080
# result should be default nginx html
fg # bring port-forward back to foreground

Demo with a Nodejs app

Create a chart and update the required value for your image etc.

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

replicaCount: 1

image:
  repository: okeeffed/repo
  tag: latest
  pullPolicy: IfNotPresent

# Could also be LoadBalancer
service:
  type: ClusterIP
  port: 80

ingress:
  enabled: false
  annotations:
    {}
    # kubernetes.io/ingress.class: nginx
    # kubernetes.io/tls-acme: "true"
  paths: []
  hosts:
    - chart-example.local
    # this could also be whatever.domain.com
  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

nodeSelector: {}

tolerations: []

affinity: {}
# Here you can add dependencies

If your helm has depencies, these can be defined in a requirements.yaml file. Example:

dependencies:
  - name: mariadb
    version: 4.x.x
    repository: https://kubernetes-charts.storage.googleapis.com/
    condition: mariadb.enabled
    tags:
      - node-app-database

Ensure you update the chart if you need to change the containerPort or env variables etc.

Once the chart is up and running, you can update charts which will update the orchestration. Use helm update <OPTIONS> <CHART> path/to/chart

Rollbacks can easily be done as well.

Use helm history <CHART> to get a history of deployments. Say we want to rollback to revision one, we can then just run helm rollback <CHART> 1.

Setting up Helm Repo with S3

If you have charts stored on S3:

# Install plugin
helm plugin install https://github.com/hypnoglow/helm-s3.git

# Initialise s3 bucket
helm s3 init s3://helm-bucket/charts

# Add report to helm
helm repo add my-charts s3://helm-bucket/charts

A personal blog on all things of interest. Written by Dennis O'Keeffe, Follow me on Twitter