Kubernetes - manage applications with Helm¶
What is Helm ?¶
Helm is for Kubernetes what apt is for Linux.
This is a package manager which allows to easily manage applications deployment in a repeatable manner.
Helm benefits¶
- Share deployment manifest
- Version deployment manifest
- Split configuration from the deployment code
- Repeatable / predictable deployment
- Compose Helm package named Chart to create an application deployment
Syntax¶
The Helm engine is based on go template, so that, the syntax is composed of Kubernetes yaml manifests and go templates in addition to some Helm functions.
Managing multiple environments only with Kubernetes manifests implies to either:
- Create one manifest file per environment
- Introduce some placeholder and create scripts to replace it from configuration files
Helm uses the Go template engine to separate the deployment configuration from the deployment logic, thus it becomes easy to apply one configuration per environment.
apiVersion: v1
kind: Service
metadata:
name: hello-kubernetes
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 8080
selector:
app: hello-kubernetes
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-kubernetes
spec:
replicas: 2
selector:
matchLabels:
app: hello-kubernetes
template:
metadata:
labels:
app: hello-kubernetes
spec:
containers:
- name: hello-kubernetes
image: paulbouwer/hello-kubernetes:1.8
ports:
- containerPort: 8080
env:
- name: MESSAGE
value: Hello World
apiVersion: v1
kind: Service
metadata:
name: {{ .Values.app }}
spec:
type: ClusterIP
ports:
- port: 80
targetPort: {{ .Values.port }}
selector:
app: {{ .Values.app }}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Values.app }}
spec:
replicas: "{{ .Values.replicas }}"
selector:
matchLabels:
app: {{ .Values.app }}
template:
metadata:
labels:
app: {{ .Values.app }}
spec:
containers:
- name: hello-kubernetes
image: "{{ .Values.image }}:{{ .Values.tag }}"
ports:
- containerPort: {{ .Values.port }}
env:
- name: MESSAGE
value: {{ .Values.message}}
app: hello-kubernetes
port: 8080
image: paulbouwer/hello-kubernetes
tag: 1.8
replicas: 2
message: My message coming from the config file
Helm versions¶
They are two production versions of Helm, the version 2 based on a client server architecture and the version 3 which replaces the server side with a Helm library.
Helm 2
Client :
- Local chart development
- Managing repositories
- Managing releases
- Interacting with the Tiller server :
- Sending charts to be installed
- Asking for information about releases
- Requesting upgrading or uninstalling of existing releases
Server :
- Listening for incoming requests from the Helm client
- Combining a chart and configuration to build a release
- Installing charts and then tracking the subsequent release
- Upgrading and uninstalling charts
Helm 3
Client :
- Local chart development
- Managing repositories
- Managing releases
- Interfacing with the Helm library :
- Sending charts to be installed
- Requesting upgrading or uninstalling of existing releases
Helm library :
- Combining a chat and configuration to build a release
- Installing charts to Kubernetes and proving the subsequent release object
- Upgrading and uninstalling charts by interacting with Kubernetes
Hands-on¶
Deploy from your own chart¶
In this use case we will create a simple hello world web site and deploy it with a Helm chart.
```shell
helm create website
```
Folder structure¶
- charts folder: Used to contain chart dependencies / subcharts
- template folder: Contains the template files which are the Kubernetes parametrized manifest
- values.yaml: Used to configure the chart
- Chart.yaml: Used to describe the chart
Read the official documentation Templates folder
Helm creates a package structure allowing us to deploy an application. We can see a serviceaccount.yaml file used to grant your application with permissions on the Kubernetes stack, the ingress.yaml and service.yaml files are used to access the application from outside the stack. Finally the deployment.yaml is used to deploy the application.
By default Helm creates a deployment object which is convenient for most of the use cases, however if you want to use a Kubernetes statefulset you will have to create the associated manifest file into the templates folder.
Configure the deployment¶
All the deployment parameters are gathered into the values.yaml file, by default Helm configures a Nginx stack deployment. We will change the configuration to deploy the httpd container. The deployment customization are in the values-apache.yaml file.
The default configuration exposes the port 80, to use another port you have to edit the deployment.yml file (copy the file to the Helm chart folder).
Install / upgrade¶
The command below performs an upgrade or update depending of if the application was already deployed or not.
```shell
helm upgrade --create-namespace --install --namespace helm-demo -f website/values.yaml -f website/values-apache.yaml website ./website
```
Note
The values contained in the website/values.yaml are overwritten by the ones on the website/values-apache.yaml
We can customize the message in using a lifecycle hook in the deployment object.
```yaml
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello world $(hostname -f) > /usr/local/apache2/htdocs/index.html"]
```
Delete the release¶
The command below is used to delete a Helm release
```shell
helm uninstall website -n helm-demo
helm list --all -n helm-demo
```
Info
We can uninstall a release in keeping the history with the --keep-history options. It allows to be able to rollback to a previous version, even if this version as uninstalled.
Deploy from an existing Chart¶
Helm uses multiple way to configure the chart to be deployed, you can use multiple values file in addition to command line interface (cli) parameters.
Install¶
```shell
kubectl create namespace helm-demo2
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install --namespace helm-demo2 website2 -f values-bitnami.yaml --set cloneHtdocsFromGit.repository="https://lgil3:$GITHUB_PAT@github.dxc.com/Platform-DXC/devcloud-docs.git" bitnami/apache --version 7.3.16
```
The above command will read the configuration from the values.yaml file and overwrite the parameter cloneHtdocsFromGit.repository with the cli value. This precedence mechanism is useful to pass secrets to the chart from the execution context.
Verify¶
Verify pods are up and ready
```shell
kubectl get pods -n helm-demo2
```
List the installed Helm releases
```shell
helm list -n helm-demo2
```
Navigate¶
Open the http://localhost
url to read the DevCloud web site.
Learnings
- Helm can deploy packages from Helm repositories.
- A Helm chart can be configured from a configuration file or from the CLI
- There is a configuration order of precedence between Helm configuration files and CLI
Upgrade¶
```shell
helm upgrade --create-namespace --namespace helm-demo2 -f values-bitnami.yaml --set cloneHtdocsFromGit.repository="https://lgil3:$GITHUB_PAT@github.dxc.com/Platform-DXC/devcloud-docs.git" website2 bitnami/apache --version 7.3.17
```
List history version¶
```shell
helm history website2 -n helm-demo2
```
Rollback¶
```shell
helm rollback -n helm-demo2 website2 1
```
Advanced usage¶
Helm chart rendering¶
```shell
helm template -f ./website/values.yaml -f ./website/values-apache.yaml ./website
```
Inject files in template¶
-
Create a configuration file
echo '#Configuration file' > config echo 'image: {{ .Values.image.repository }}' >> config echo 'tag: {{ .Values.image.tag }}' >> config
-
Create a configmap file
apiVersion: v1 kind: ConfigMap metadata: creationTimestamp: 2016-02-18T18:52:05Z name: config data: config: |- {{ .Files.Get "config" | indent 4 }}
-
Render the chart
helm template -f values.yaml -f values-apache.yaml ./
Templating¶
-
Replace the content of the configmap with
apiVersion: v1 kind: ConfigMap metadata: name: config data: config: |- {{ .Files.Get "config" | indent 4 }} config2: |- {{ tpl (.Files.Get "config") . | indent 4 }}
Loop¶
-
Replace the content of the configmap with
apiVersion: v1 kind: ConfigMap metadata: name: config data: config: |- {{ .Files.Get "config" | indent 4 }} config2: |- {{ tpl (.Files.Get "config") . | indent 4 }} {{- $files := .Files }} {{- range tuple "values.yaml" "values-apache.yaml"}} {{ . }}: |- {{ $files.Get . | indent 4 }} {{- end }}
Flow Control¶
-
Replace the content of the configmap with
apiVersion: v1 kind: ConfigMap metadata: name: config data: {{ if and $.Values.replicaCount (gt $.Values.replicaCount 1.0) }} config: |- {{ .Files.Get "config" | indent 4 }} {{ else }} config2: |- {{ tpl (.Files.Get "config") . | indent 4 }} {{- $files := .Files }} {{- range tuple "values.yaml" "values-apache.yaml"}} {{ . }}: |- {{ $files.Get . | indent 4 }} {{- end }} {{end}}
tips and tricks
Here is the link to the Helm web site tips and tricks.