Hello World example for Kubernetes and Helm
- Kubernetes: https://kubernetes.io/docs/home/
- Helm: https://helm.sh/
In order to run this example in a local Kubernetes cluster on your machine, you need to have Docker, Kubernetes, and Helm (version 3 or greater) installed:
- Install Docker Desktop from https://www.docker.com/products/docker-desktop.
- Enable Kubernetes in Docker Desktop preferences
- Install Helm: https://helm.sh/docs/intro/install/
- Verify that Helm installed successfully by running
helm version
First ensure that the cluster you want to deploy to is set as your current context for the kubectl
command. You can check the current context by running:
kubectl config current-context
To change the context, use the use-context
command, e.g.:
kubectl config use-context docker-desktop
(You can also view or change the current context from the Docker desktop menu - click the Docker icon and then select "Kubernetes" from the menu.)
Before you can install a helm chart, you first need to build any Docker images it uses (unless you're pointing it to an existing Docker image already on the internet), and the Kubernetes cluster needs to have access to these Docker images. If you are running this example locally, you only need to build one image and then you should be able to install the helm chart.
Here is how you can build the image and tag it with both the latest
tag and a 1.0.0
tag:
docker build -t helm-hello-world:latest -t helm-hello-world:1.0.0 .
Note that this chart uses appVersion
in Chart.yaml
to indicate the version of the Docker image. The idea is that each time a new version of the app is released, there should be a new new Docker image with an updated version number, and appVersion
should be updated to match it.
Create your first release:
helm install --debug my-first-release charts/hello-world
You should now be able to access the hello world app in your browser!
Take a look at the files in charts/hello-world
. Observe how many of the settings are being populated with values from the values.yaml
file. There are also some references to template partials in templates/_helpers.tpl
.
This chart was originally created by the helm create
command and greatly simplified, since the default boilerplate would be overkill for such a simple example. For example, the way the metadata
and selector
are set up in deployment.yaml
and service.yaml
is unchanged from the original version generated by helm create
. It would be possible to simplify this further. For example, the helm boilerplate sets the name of each resource as follows:
name: {{ include "hello-world.fullname" . }}
A simpler way to set the name could be to just use the same name as the chart:
name: {{ Chart.Name }}
But using a template partial to get the name is the better way to do it, because if you look at how the example is working, it's appending the name of the current helm release and also truncates the name if it would be too long and cause deployment issues. (The example uses the hello-world.fullname
template partial, which is defined in _helpers.tpl
.) Including the release name makes it easier to identify which version was deployed when looking in the Kubernetes dashboard. It also ensures that resources are created cleanly in each new release, instead of trying to merge the configuration with an existing resource from a prior release.
In summary, charts can be as simple as directly using values from the values.yaml
file (as where {{ .Values.service.internalPort }}
is used) or even hard-coding values in the resource files themselves (e.g. deployment.yaml
and service.yaml
), if they're values that don't need to ever change. But it can still be useful to see all the values in one place, so the helm convention is to put most of the configuration in values.yaml
. The default helpers generated by the helm create
command are good examples of how to enhance your helm charts to make them more robust, provide fallbacks for optional configuration values, etc.
Suppose you want to run the app on a different port number. The Kubernetes Service
in this example helm chart has 3 port numbers:
port
: The port number that this service should listen on inside the cluster (for a chart with multiple services, other services would be able to communicate with it via this port)targetPort
: The port number that the Docker container itself is listening on. It should match the port number specified byEXPOSE
in the Dockerfile, and also the port number of the server running inside the container (in this example anhttpd
daemon).nodePort
: This is only needed for Services of typeNodePort
. NodePorts are the most direct way to make a service inside a Kubernetes cluster accessible from the outside. Other ways to do this are to add aLoadBalancer
service or to use Ingress. For more details on these various options, see https://medium.com/google-cloud/kubernetes-nodeport-vs-loadbalancer-vs-ingress-when-should-i-use-what-922f010849e0.
The service.yaml
file in the helm chart populates each of these values from variables in the values.yaml
file, as can be seen when looking at service.yaml
:
- port: {{ .Values.service.externalPort }}
targetPort: {{ .Values.service.internalPort }}
nodePort: {{ .Values.service.nodePort }}
(Using the names internalPort
and externalPort
is a common convention in helm, presumably because they're a bit more intuitive than the names port
and targetPort
actually used by Kubernetes.)
If all you want to do is change the port number used to access the service in your browser, then in this example you only need to change the nodePort
in values.yaml
.
You can now publish a new version of the chart:
helm install my-second-release charts/hello-world
Alternatively, you could update your existing helm release instead of creating a new one:
helm upgrade my-first-release charts/hello-world
NOTE:
helm install
andhelm upgrade
will tell you if there are any syntax errors, but if you want to check for syntax errors without installing the chart, you can runhelm lint
. See also "Previewing the Kubernetes configuration" below.
You can also uninstall releases with helm uninstall
.
For more information on helm commands, see https://helm.sh/docs/intro/using_helm/
You can optionally check to see the raw Kubernetes configuration that will be deployed, prior to actually installing or upgrading a helm chart, by using the --dry-run
flag, e.g.:
helm install my-second-release charts/hello-world --dry-run