Creating a Helm Chart

You can think of Chart as a package and Helm itself as a package manager. Every Chart describes related Kubernetes resources and has the following structure:

Let’s get started by creating the helm folder in the root directory of the dummy project and describing our package in the Chart.yaml file:

We can use the .helmignore file to inform Helm, that we don’t want to process some specific files:

The Kubernetes resources, which are required to run our project in a cluster, are described in the templates folder. In our case, we only need 3 types of objects:

Deployment describes pods to be created in a cluster. Even though every pod might consist of several containers, more common approach is to have one container per a pod. That’s why, within this tutorial, you can think of a pod as a container.

describes pods to be created in a cluster. Even though every pod might consist of several containers, more common approach is to have one container per a pod. That’s why, within this tutorial, you can think of a pod as a container. Service enables communication between pods.

enables communication between pods. Ingress exposes services to external clients.

Templates

Instead of describing each resource separately (i.e. Nginx deployment, PHP-FPM deployment, etc.), we will create configurable templates for every object type and then apply them to related services: Nginx, PHP-FPM, MySQL.

Deployment Template

Let’s start from the deployment template, as it’s the most vital object for our application. By following the best practices, I’ve created the deployment.tpl file with the following content:

Every template is wrapped in define block:

The actual template starts with an object type and a name:

Note, that we use variables here and there: .service.name, .service.replicas, etc. When you include a template in a YAML file, you can pass a dictionary to the include command. The dot character, that prefixes variable names is the reference to that dictionary.

In the section above, we instruct the cluster to form a pod out of containers, which are labeled with a service name, and define the desired number of replicas.

In the template part we define how to create and label containers. Let’s have a closer look at the container definition:

We provide a name, an image to use and a condition to pull the image from registry for every container. Under the resources section we instruct the cluster to start the container, if the configured resources are available, and to kill the container, if it exceeds the CPU and memory limits. As for the environment variables, we have two possible configuration options: using plain values, using Kubernetes secrets.

As we finished with the template, we can create deployment YAML files for our services:

php-fpm.deployment.yaml:

mysql.deployment.yaml:

nginx.deployment.yaml:

Service Template

Since we created the pods, the next step is to enable communication between them. But before we actually define the services, let’s create a new template in the service.tpl file:

It starts quite similar to what we’ve already seen in the deployment template: a resource type and metadata. Under the spec section we assigned an internal cluster IP address to a pod, which is labeled with the service name, and exposed one of its ports.

Without further ado, let’s define the application services:

php-fpm.service.yaml:

mysql.service.yaml:

nginx.service.yaml:

Ingress Template

As our application has to be accessible from outside, we need to create an Ingress object. Here is the ingress.tpl file content:

Every Ingress rule maps a host to one or more services, depending on a path. In our case we forward all the requests to a single service.

Let’s make the Nginx service available from outside by creating an Ingress resource in the nginx.ingress.yaml file:

Configuration

You might wonder, what are those .Value variables, that we used in YAML files? Well, the dot character is the main Chart dictionary and Values is a configuration, defined in the values.yaml file:

I believe this configuration is self explanatory, but if you are very attentive, you’ve probably noticed, that some variables, that we used in the templates (e.g. nginx.host and imageTag) , are not presented in the values.yaml file. We want some configuration to be dynamic, because it may vary from one environment to another. These dynamic values, can be passed directly to the Helm upgrade command, which we about to use to publish the Chart.