= Deploying applications using Kubernetes Helm charts
:toc:
:icons:
:linkcss:
:imagesdir: ../../resources/images

https://github.com/kubernetes/helm[Helm] is a tool for managing https://github.com/kubernetes/charts[Kubernetes charts]. A chart is a collection of files that describe a related set of Kubernetes resources. Read more details in https://github.com/kubernetes/helm/blob/master/docs/charts.md[Charts introduction].

== Prerequisites

In order to perform exercises in this chapter, you’ll need to deploy configurations to a Kubernetes cluster. To create an EKS-based Kubernetes cluster, use the link:../../01-path-basics/102-your-first-cluster#create-a-kubernetes-cluster-with-eks[AWS CLI] (recommended). If you wish to create a Kubernetes cluster without EKS, you can instead use link:../../01-path-basics/102-your-first-cluster#alternative-create-a-kubernetes-cluster-with-kops[kops].

All configuration files for this chapter are in the `helm` directory. Make sure you change to that directory before giving any commands in this chapter.

== Install Helm

There are two parts to Helm: The Helm client (`helm`) and the Helm server (`tiller`).

Tiller runs inside of your Kubernetes cluster, and manages releases (installations) of your charts. Helm runs on your laptop, CI/CD, or wherever you want it to run.

This section shows how to install both the client and the server.

=== Install Helm client

Install on Mac OSX:

  brew install kubernetes-helm

https://docs.helm.sh/using_helm/#installing-helm[Installing Helm] provides complete set of options to install the client.

=== Install Helm server

Helm server is also known as `tiller`. By default, tiller is installed in the current `kubectl` context. Check the current Kubernetes context:

  $ kubectl config current-context
  cluster.kubernetes-aws.io

Install `tiller`:

```
$ helm init
Creating /Users/argu/.helm
Creating /Users/argu/.helm/repository
Creating /Users/argu/.helm/repository/cache
Creating /Users/argu/.helm/repository/local
Creating /Users/argu/.helm/plugins
Creating /Users/argu/.helm/starters
Creating /Users/argu/.helm/cache/archive
Creating /Users/argu/.helm/repository/repositories.yaml
$HELM_HOME has been configured at /Users/argu/.helm.

Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.
Happy Helming!
```

This will install `tiller` in the `kube-system` namespace. It can be installed into a specific cluster by using `--kube-context` option. It can be installed into an alternative namespace by using `--tiller-namespace` option.

https://docs.helm.sh/using_helm/#installing-tiller[Installing Tiller] provides complete set of options to install the server.

== Install Helm chart

A Helm chart can be installed using the `helm install` command.

Before installing a chart, Helm allows you to find issues with your chart's formatting or templates using the `lint` command. Let's run `helm lint` on our sample application in the helm folder:

```
$ helm lint sample
==> Linting sample
[INFO] Chart.yaml: icon is recommended

1 chart(s) linted, no failures
```

It's recommended to take a look at the generated manifests of a chart before installing it. This can be done using the `--debug` and `--dry-run` options.

  helm install --dry-run --debug sample

It shows the output as:

```
[debug] Created tunnel using local port: '50827'

[debug] SERVER: "localhost:50827"

[debug] Original chart version: ""
[debug] CHART PATH: /Users/argu/workspaces/kubernetes-aws-workshop/helm/sample

NAME:   eponymous-badger
REVISION: 1
RELEASED: Tue Oct 17 03:06:36 2017
CHART: sample-1.0.0
USER-SUPPLIED VALUES:
{}

COMPUTED VALUES:
db:
  database: employees
  image: mysql:8
  password: mysql
  port: 3306

. . .

    spec:
      containers:
      - name: webapp
        image: arungupta/docker-javaee:dockerconeu17
        ports:
        - containerPort: 8080
```

Finally, install the chart:

  helm install --name sample sample

This shows output:

```
NAME:   sample
LAST DEPLOYED: Tue Oct 17 03:45:36 2017
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/Service
NAME    CLUSTER-IP      EXTERNAL-IP  PORT(S)   AGE
db      100.68.180.123  <none>       3306/TCP  1s
webapp  100.70.164.191  <none>       8080/TCP  1s

==> v1beta1/Deployment
NAME               DESIRED  CURRENT  UP-TO-DATE  AVAILABLE  AGE
mysql-deployment   1        1        1           0          1s
webapp-deployment  1        1        1           0          1s
```

== Verify application

Verify the deployment using `kubectl`:

```
$ kubectl get deployments
NAME                DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
mysql-deployment    1         1         1            1           1m
webapp-deployment   1         1         1            1           1m
$ kubectl get svc
NAME         TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
db           ClusterIP   100.65.195.189   <none>        3306/TCP   1m
kubernetes   ClusterIP   100.64.0.1       <none>        443/TCP    1h
webapp       ClusterIP   100.71.21.2      <none>        8080/TCP   1m
$ kubectl get pods
NAME                                READY     STATUS    RESTARTS   AGE
mysql-deployment-1668503186-9h7lz   1/1       Running   0          1m
webapp-deployment-372583675-hlcbg   1/1       Running   0          1m
```

Start a proxy. Since the webapp service does not expose a public endpoint, proxy will allow you to access your service endpoint via the Kubernetes API:

  kubectl proxy --address 0.0.0.0 --accept-hosts '.*' --port 8080

Access the application using:

  curl -k https://ENVIRONMENT_ID.vfs.cloud9.REGION_ID.amazonaws.com/api/v1/proxy/namespaces/default/services/webapp/resources/employees

This shows the output:

```
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><collection><employee><id>1</id><name>Penny</name></employee><employee><id>2</id><name>Sheldon</name></employee><employee><id>3</id><name>Amy</name></employee><employee><id>4</id><name>Leonard</name></employee><employee><id>5</id><name>Bernadette</name></employee><employee><id>6</id><name>Raj</name></employee><employee><id>7</id><name>Howard</name></employee><employee><id>8</id><name>Priya</name></employee></collection>
```

== Share Helm chart

A chart needs to be packaged before it can be shared with others.

It can be packaged using `helm package` command. Package the chart as:

  helm package sample

This creates `sample-1.0.0.tgz` in your current directory.

This chart can now be shared with others using a chart repository server. The `helm serve` command can be used to start a test chart repository server on your local machine that serves charts from a local directory.

For production, it's recommended to setup a https://github.com/arun-gupta/kubernetes-aws-workshop/issues/70[chart repository on AWS cloud].

== Delete Helm chart

List the deployed charts

    $ helm list

```
NAME    REVISION  UPDATED                   STATUS    CHART         NAMESPACE
sample  1         Tue Oct 17 03:45:36 2017  DEPLOYED  sample-1.0.0  default
```

Delete the deployed chart

    $ helm delete sample


You are now ready to continue on with the workshop!

:frame: none
:grid: none
:valign: top

[align="center", cols="1", grid="none", frame="none"]
|=====
|image:button-continue-developer.png[link=../../03-path-application-development/307-statefulsets-and-pvs]
|link:../../developer-path.adoc[Go to Developer Index]
|=====
