Tutorial: Using Helm Hooks in Your Codefresh Pipeline

Tags: devops, helm, kubernetes, cicd
Published: 2020-10-30 13:06:06

When getting started with Kubernetes and Helm, the process across the release life cycle can feel like a black-box; having to follow debugging processes to understand what is going on behind the scenes. Helm hooks can help with that.

This post provides an overview of:
<ul>
 	<li>Helm hooks, why and how they are used;</li>
 	<li>An example project that you can follow along with;
and</li>
 	<li>How you can use Helm hooks in your Codefresh pipeline.</li>
</ul>
If you are new to Helm, we suggest to check-out our <a href="https://codefresh.io/helm-tutorial/getting-started-with-helm-3/">previous tutorial</a> first and then come back to learn more about Helm hooks.
<h3><b>Overview: What are Helm Hooks?</b></h3>
Hooks perform a single action at a specified point during the release life cycle. At each stage, hooks can be used to intervene in the release for upgrades, downgrades, and deletion.

For example, Helm hooks help you to manage dependencies. Those could exist outside of the Kubernetes cluster or an external dependency. Hooks allow you to determine when and whether a service, installation, or upgrade is finished before starting a new one. For example, if you want to port user information into your database, you can ensure that new data has successfully been transferred before executing queries.
<h3><b>Hook Annotation Values</b></h3>
Hooks are not directly applied to the Kubernetes environment during standard processing. Instead, Hooks run in a separate pod inside of your Kubernetes cluster. The value specified in the helm.sh/hook annotation determines when the hook should be rendered. This makes it possible to perform operations at specific points during the release life cycle.

Helm hooks have several annotation values that are used to specify when a hook should be executed. One annotation may be used at multiple points during the release. Overall, there are nine places where a hook could be called; an overview is provided in the following table, taken from the official Helm documentation.
<table>
<tbody>
<tr>
<td><b>Annotation Value</b></td>
<td><b>Description</b></td>
</tr>
<tr>
<td>pre-install</td>
<td>Executes after templates are rendered, but before any resources are created in Kubernetes</td>
</tr>
<tr>
<td>post-install</td>
<td>Executes after all resources are loaded into Kubernetes</td>
</tr>
<tr>
<td>pre-delete</td>
<td>Executes on a deletion request before any resources are deleted from Kubernetes</td>
</tr>
<tr>
<td>post-delete</td>
<td>Executes on a deletion request after all of the release's resources have been deleted</td>
</tr>
<tr>
<td>pre-upgrade</td>
<td>Executes on an upgrade request after templates are rendered, but before any resources are updated</td>
</tr>
<tr>
<td>post-upgrade</td>
<td>Executes on an upgrade after all resources have been upgraded</td>
</tr>
<tr>
<td>pre-rollback</td>
<td>Executes on a rollback request after templates are rendered, but before any resources are rolled back</td>
</tr>
<tr>
<td>post-rollback</td>
<td>Executes on a rollback request after all resources have been modified</td>
</tr>
<tr>
<td>test</td>
<td>Executes when the Helm test subcommand is invoked (<a href="https://helm.sh/docs/chart_tests/"> view test docs</a>)</td>
</tr>
</tbody>
</table>
The original table can be found in the official <a href="https://helm.sh/docs/topics/charts_hooks/#the-available-hooks">Helm documentation</a>.
<h3><b>Example using Helm Hooks</b></h3>
This tutorial will focus on the install life cycle.

Helm provides two hooks for the install life cycle, “pre-install” and “post-install”.
<ul>
 	<li>“Pre-install” is used after templates are rendered and before resources are created in Kubernetes;</li>
 	<li>“Post-install” is used after all resources are loaded in Kubernetes. Thus, it could be used to invoke a series of checks.</li>
</ul>
Let’s get started working with Helm hooks. For the following example, we will use <a href="https://github.com/anais-codefresh/react-article-display/tree/helm-3-tutorial">this GitHub repository</a>, which is a simple React project to query articles from Hacker News. Please clone the repository to your GitHub account. Alternatively, you can follow with your own project or start a new React application with ‘<a href="https://github.com/anais-codefresh/react-article-display/tree/helm-3-tutorial">create-react-app</a>’. The decision is yours.

Here is what we are going to do:
<ul>
 	<li>Cover Prerequisites</li>
 	<li>Set-up codefresh.yml file</li>
 	<li>Add pre-install and post-install hook</li>
 	<li>Setting up your Codefresh pipeline</li>
</ul>
<h4><b>Prerequisites</b></h4>
It is assumed that you already set-up a Kubernetes cluster <a href="https://codefresh.io/docs/docs/integrations/kubernetes/">with Codefresh</a>. This tutorial will not cover the set-up process. You can read more about Kubernetes clusters in Codefresh in the Codefresh documentation on <a href="https://codefresh.io/docs/docs/new-helm/using-helm-in-codefresh-pipeline/">Using Helm in a Codefresh Pipeline</a>.

Additionally, please ensure that you:
<ul>
 	<li>Have <a href="https://helm.sh/">installed Helm</a>.</li>
 	<li>Have a basic Helm Chart setup; to do so you can either <a href="https://codefresh.io/helm-tutorial/getting-started-with-helm-3/">follow this tutorial</a>. Alternatively, the <a href="https://github.com/anais-codefresh/react-article-display/tree/helm-3-tutorial">example repo</a> provided already has a Helm Chart.</li>
 	<li>Can <a href="https://docs.docker.com/get-docker/">access Docker</a> in your terminal and that your project already has a Dockerfile. Build your Docker image and use the same repository in your Helm Chart. By using the example repository, this is already done for you. However, you can also <a href="https://codefresh.io/helm-tutorial/getting-started-with-helm-3/">follow this tutorial</a> to set it up in your project.</li>
</ul>
<h4><b>Set-up codefresh.yml file </b></h4>
The codefresh.yml file is used to build your Codefresh pipeline and allows you to customize the build steps in your pipeline. There are two ways that you could set-up the codefresh.yml file. Namely,
<ul>
 	<li>Create a pipeline file from scratch</li>
 	<li>Set-up a new Codefresh pipeline and modify it according to your needs. This will create a codefresh.yml file in the Codefresh UI automatically. You can then customize the file in the UI.</li>
</ul>
For the purpose of this tutorial, we will follow the first option and define our codefresh.yml file in our project folder. Note that if you are using the example repository, the codefresh.yml file is already set-up. However, if you are using a different React App or/and Docker image, please make sure to modify it like described below.

To set-up the codefresh.yml file please run the following command in your main project folder:
<pre>touch codefresh.yml</pre>
Our <a href="https://github.com/anais-codefresh/react-article-display/blob/master/codefresh.yml">codefresh.yml</a> file will use the <a href="https://codefresh.io/docs/docs/getting-started/create-a-basic-pipeline/">minimum set-up</a> for this project but feel free to <a href="https://codefresh.io/docs/docs/codefresh-yaml/what-is-the-codefresh-yaml/">dive deeper</a> and add <a href="https://codefresh.io/docs/docs/codefresh-yaml/steps/freestyle/">freestyle steps</a> in accordance with your needs.
{% raw %}
<pre>version: "1.0"
 
stages:
 - "clone"
 - "build"
 - "test"
 - "deploy"
 steps:
 clone:
   title: "Cloning repository"
   type: "git-clone"
   repo: "anais-codefresh/react-article-display"
   revision: "${{CF_BRANCH}}"
   git: "github"
   stage: "clone"
 
 build:
   title: "Building Docker image"
   type: "build"
   image_name: "anaisurlichs/react-article-display"
   working_directory: "./react-article-display"
   tag: "${{CF_BRANCH_TAG_NORMALIZED}}"
   dockerfile: "Dockerfile"
   stage: "build"
 
 test:
   title: "Running test"
   type: "freestyle" # Run any command
   image: "ubuntu:latest" # The image in which command will be executed
   working_directory: "./react-article-display" # Running command where code cloned
   commands:
     - "ls"
   stage: "test"
</pre>
{% endraw %}
Please make sure to adapt the following keys to your project:
<pre>image_name: "your Docker image name goes here"
working_directory: "change to your working directory"
</pre>
In the next steps, we will add our Helm hooks to our Helm Chart.
<h4><b>Add pre-install and post-install hook</b></h4>
At this stage, we have completed the minimum set-up to use Docker, a Codefresh pipeline, and Helm charts. We will now add the Helm pre-install hook to our chart based on the <a href="https://helm.sh/docs/topics/charts_hooks/">template</a> provided by the official Helm documentation and make modifications as needed.

Hooks are placed inside the /templates folder of your chart and called with the helm.sh/hook annotation. If you are looking through the existing files, you can see that a hook is already used in the default template in the <a href="https://github.com/anais-codefresh/react-article-display/blob/helm-3-tutorial/charts/example-chart/templates/tests/test-connection.yaml">charts/example-chart/templates/test-connection.yaml</a> file.
<pre>annotations:

"helm.sh/hook": test-success
</pre>
First, create a pre-install-job.yaml file in your templates directory inside the charts folder. Next, add the <a href="https://github.com/anais-codefresh/react-article-display/blob/master/charts/example-chart/templates/pre-install-job.yaml">following template</a>:
{% raw %}
<pre>apiVersion: batch/v1
kind: Job
metadata:
 name: "{{ .Release.Name }}"
 labels:
   app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
   app.kubernetes.io/instance: {{ .Release.Name | quote }}
   app.kubernetes.io/version: {{ .Chart.AppVersion }}
   helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
 annotations:
   # hooks are defined here
   "helm.sh/hook": pre-install
   "helm.sh/hook-weight": "-5"
   "helm.sh/hook-delete-policy": hook-succeeded
spec:
 template:
   metadata:
     name: "{{ .Release.Name }}"
     labels:
       app.kubernetes.io/managed-by: {{ .Release.Service | quote }}
       app.kubernetes.io/instance: {{ .Release.Name | quote }}
       helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
   spec:
     restartPolicy: Never
     containers:
     - name: pre-install-job
       image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
       command: ['sh', '-c', 'echo pre-install Job Pod is Running ; sleep 2']
</pre>
{% endraw %}
This annotation section specifies our hook:
<pre>annotations:
   # hooks are defined here
   "helm.sh/hook": pre-install
   "helm.sh/hook-weight": "-5"
   "helm.sh/hook-delete-policy": hook-succeeded
</pre>
Next, we will do the same for our <a href="https://github.com/anais-codefresh/react-article-display/blob/master/charts/example-chart/templates/post-install-job.yaml">post-install hook</a>. Create the post-install-hook.yaml file in the templates directory. It will look pretty much the same as the pre-install hook. The main difference will be the hook annotation.
<pre class="">annotations:
   # hooks are defined here
   "helm.sh/hook": post-install
   "helm.sh/hook-weight": "3"
   "helm.sh/hook-delete-policy": hook-succeeded</pre>
As you can see there are some differences. First, we reference a different hook, second, we changed the hook-weight from “-5” for the pre-install hook to “3” in the post-install hook. The <a href="https://helm.sh/docs/topics/charts_hooks/">weight of hooks</a> set the execution order of the hooks, which is defined by negative values. Meaning, the lower the number, the higher the weight.

Now it is time to install your chart. Note that normally, you would push the chart to a Helm repository first. <a href="https://codefresh.io/docs/docs/new-helm/using-helm-in-codefresh-pipeline/">Codefresh provides a free Helm repository</a> for every account. However, for this tutorial, we will install the chart directly from the filesystem.

To do so run the following command; if your chart path looks different, make sure to change the command accordingly.
<pre>helm install example-hook ./charts/example-chart</pre>
The output in your console should look something like this*:

<a href="https://codefresh.io/wp-content/uploads/2020/10/helminstall.png"><img class="size-large wp-image-17869" src="https://codefresh.io/wp-content/uploads/2020/10/helminstall-300x52.png" alt="helm install step" width="300" height="52" /></a>

To double-check that your chart is up and running, please use the helm ls command:
<pre>helm ls</pre>
The “STATUS” section will also display keywords if something went wrong during the installation process. As you can see below, we currently have three pods deployed*:

<a href="https://codefresh.io/wp-content/uploads/2020/10/helmls.png"><img class="size-medium wp-image-17870" src="https://codefresh.io/wp-content/uploads/2020/10/helmls-300x16.png" alt="helm ls command" width="300" height="16" /></a>

*Note that we are using the namespace “demo”. Thus, our commands vary slightly.
<h4><b>View Hook Details</b></h4>
The pod of the hook will automatically be deleted once the job is finished. To view the details of the post-install hook, follow these steps:
<ol>
<li>Remove the following line from post-install-job.yaml:
<pre>"helm.sh/hook-delete-policy": hook-succeeded</pre>
</li>
 	<li>Install a new chart:
<pre>helm install second-example-hook ./charts/example-chart</pre>
</li>
 	<li>When you now view the Kubernetes pods, you will see an additional pod:
<pre>kubectl get pods</pre>
</li>
 	<li>View the details of the pod:
<pre>kubectl describe pod</pre>
</li>
</ol>
<a href="https://codefresh.io/wp-content/uploads/2020/10/kubectlccommand.png"><img class="size-medium wp-image-17872" src="https://codefresh.io/wp-content/uploads/2020/10/kubectlccommand-300x150.png" alt="kubectl command" width="300" height="150" /></a>
<h4><b>Access Application</b></h4>
You could now follow the commands in the console output to access your application in the browser. Those are provided by the NOTES.txt file in your templates folder. After running the commands, we will see our application:

<a href="https://codefresh.io/wp-content/uploads/2020/10/application-display.png"><img class="size-medium wp-image-17873" src="https://codefresh.io/wp-content/uploads/2020/10/application-display-300x193.png" alt="running application" width="300" height="193" /></a>

In the next section, we will look at adding a deployment step for your Helm chart to your Codefresh Pipeline.
<h3><b>Set-up a Codefresh Pipeline</b></h3>
If you have followed the “<b>Set-up codefresh.yml file step</b>” in the previous section or you have cloned the <a href="https://github.com/anais-codefresh/react-article-display/tree/helm-3-tutorial">example repo</a>, you already have the set-up in your codefresh.yml file to create a basic Codefresh pipeline. In this section, we will add one additional step to install the Helm chart.

Please add the following in your codefresh.yml file to install the Helm chart to your cluster:
<pre> deploy:
   type: "helm"
   working_directory: "./react-article-display"
   arguments:
     action: "install"
     chart_name: "charts/example-chart"
     release_name: "example-chart"
     helm_version: 3.0.2
     kube_context: "anais-cluster@codefresh-sa"
   stage: "deploy"
</pre>
Make sure that your chart_name is pointing to the chart name in your main repository, in our case this is “charts/example-chart”, and that your kube_context states the Kubernetes cluster <a href="https://codefresh.io/docs/docs/deploy-to-kubernetes/add-kubernetes-cluster/">connected to your Codefresh account</a> that you will be using. If you do not have a Kubernetes cluster connected to Codefresh, now is the time to do that.

Next, we will push all of our changes to our GitHub repository. Once this is done, we will set-up our Codefresh pipeline.
<ol>
 	<li>In your Codefresh account, select “New Project” from the top right of your Dashboard in the projects tap:</li>
<a href="https://codefresh.io/wp-content/uploads/2020/10/codefresh-new-project.png"><img class="aligncenter size-large wp-image-17810" src="https://codefresh.io/wp-content/uploads/2020/10/codefresh-new-project-1024x426.png" alt="codefresh-new-project" width="1024" height="426" /></a>
 	<li>Next, follow the instructions to create your project.</li>
 	<li>Once you created your project, you will be redirected to your project section in your Dashboard:</li>
<a href="https://codefresh.io/wp-content/uploads/2020/10/project-dashboard.png"><img class="aligncenter size-large wp-image-17811" src="https://codefresh.io/wp-content/uploads/2020/10/project-dashboard-1024x580.png" alt="project-dashboard" width="1024" height="580" /></a>
 	<li>Go ahead and create a pipeline for your project. Assuming that you are connected with your GitHub account to Codefresh, it will ask you to select the repository that you want to create the pipeline for. Once you have provided the information, you will be redirected to the workflow, which displays the auto-generated codefresh.yml file. In our case, we will use the YAML from our repository instead.</li>
<a href="https://codefresh.io/wp-content/uploads/2020/10/inline-yml.png"><img class="size-full wp-image-17812" src="https://codefresh.io/wp-content/uploads/2020/10/inline-yml.png" alt="inline-yml" width="577" height="408" /></a>
 	<li>Hit run at the bottom of the screen; which will direct you to the Codefresh step. You can follow the processing through the command line. Once done, you will see the output of our NOTES.txt file.</li>

<a href="https://codefresh.io/wp-content/uploads/2020/10/codefresh-pipeline-1.png"><img class="size-medium wp-image-17813" src="https://codefresh.io/wp-content/uploads/2020/10/codefresh-pipeline-1-300x142.png" alt="codefresh-pipeline" width="300" height="142" /></a>

 	<li>Now the Helm chart is deployed to our Kubernetes Cluster using the Codefresh pipeline. To view the Helm Chart, access Helm &gt; Releases within DEVOPS INSIGHTS. You should see something similar to the following. If not, please make sure that you have selected the right Helm version and Kubernetes cluster in the settings.</li>
</ol>
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/w6si60z1x991i5or7yep.png)

<h3>Summary</h3>
In this tutorial, we have looked at Helm hooks, what they are used for, the different types of hook annotations, and finally, set-up an example project to use the pre-install and post-install hook. If you have followed all steps, you have a project up and running in your Codefresh pipeline that uses Helm to manage Kubernetes resources.

Please let us know in the comments whether this tutorial was helpful, you have any questions, suggestions, or useful links for the community to learn more about Helm hooks.

✨New to Codefresh? <a href="https://codefresh.io/codefresh-signup/?utm_source=Blog&amp;utm_medium=Post&amp;utm_campaign=helmhooks">Create Your Free Account today</a>✨
And if you liked this post and want to make sure others see it too, please give it a like 🤩