By: Paul Czarkowski (@pczarkowski)
Edited By: Paul Stack (@stack72)
Kubernetes Kubernetes Kubernetes is the new Docker Docker Docker
“Kubernetes is an open-source system for automating deployment, scaling, and management of containerized applications.”
Remember way back in 2015 when all anybody would talk about was Docker even though nobody actually knew what it was or what to do with it? That’s where Kubernetes is right now. Before we get into Helm charts, a quick primer on Kubernetes is a good idea.
Kubernetes provides scheduling and management for your containerized applications as well as the networking and other necessary plumbing and surfaces its resources to the developer in the form of declarative manifests written in YAML or JSON.
A Pod is the smallest deployable unit that can be deployed with Kubernetes. It contains one or more collocated containers that share the same [internal] IP address. Generally a pod is just a single container, but if your application requires a sidecar container to share the same IP or a shared volume then you would declare multiple containers in the same pod.
A Pod is unmanaged and will not be recreated if the process inside the container ends. Kubernetes has a number of resources that build upon a pod to provide different types of lifecycle management such as a Deployment that will ensure the correct number of replicas of your Pod are running.
A Service provides a stable name, IP address, and DNS (if KubeDNS is enabled) across a number of pods and acts as a basic load balancer. This allows pods to easily communicate to each other and can also provide a way for Kubernetes to expose your pod externally.
Helm is a Package Manager for Kubernetes. It doesn’t package the containers (or Pods) directly but instead packages the kubernetes manifests used to build those Pods. It also provides a templating engine that allows you to deploy your application in a number of different scenarios and configurations.
[Helm] Charts are easy to create, version, share, and publish — so start using Helm and stop the copy-and-paste madness. – https://helm.sh/
Let’s Build a Helm Chart!
In order to follow along with this tutorial you will need to install the following:
If you are on a Mac you should be able to use the following to install the necessary bits:
$ brew cask install minikube
$ brew install kubernetes-helm
If you already have a Kubernetes manifest its very easy to turn it into a Helm Chart that you can then iterate over and improve as you need to add more flexibility to it. In fact your first iteration of a Helm chart can be your existing manifests tied together with a simple Chart.yaml
file.
Prepare Environment
Bring up a test Kubernetes environment using Minikube:
$ minikube start
Starting local Kubernetes v1.7.5 cluster...
Starting VM...
Getting VM IP address...
Moving files into cluster...
Setting up certs...
Connecting to cluster...
Setting up kubeconfig...
Starting cluster components...
Kubectl is now configured to use the cluster.
Wait a minute or so and then install Helm’s tiller service to Kubernetes:
$ helm init
$HELM_HOME has been configured at /home/XXXX/.helm.
Tiller (the Helm server-side component) has been installed into your Kubernetes Cluster.
Happy Helming!
If it fails out you may need to wait a few more minutes for minikube to become accessible.
Create a path to work in:
$ mkdir -p ~/development/my-first-helm-chart
$ cd ~/development/my-first-helm-chart
Create Example Kubernetes Manifest.
Writing a Helm Chart is easier when you’re starting with an existing set of Kubernetes manifests. One of the easiest ways to get a basic working manifest is to ask Kubernetes to run something and output the resultant manifest to a file.
Run a basic nginx Deployment and expose it via a NodePort Service:
$ mkdir -p templates
$ kubectl run example --image=nginx:alpine \
-o yaml > templates/deployment.yaml
$ kubectl expose deployment example --port=80 --type=NodePort \
-o yaml > templates/service.yaml
Minikube has some helper functions to let you easily find the URL of your service. run curl
against your service to ensure that its running as expected:
$ minikube service example --url
http://192.168.99.100:30254
$ curl $(minikube service example --url)
...
<title>Welcome to nginx!</title>
...
You’ll see you now have two Kubernetes manifests saved. We can use these to bootstrap our helm charts:
$ tree
└── templates
├── deployment.yaml
└── service.yaml
Explore the deployment.yaml
file in a text editor. Following is an abbreviated version of it with comments to help you understand what some of the sections mean:
# These first two lines appear in every Kubernetes manifest and provide
# a way to declare the type of resource and the version of the API to
# interact with.
apiVersion: apps/v1beta1
kind: Deployment
# under metadata you set the resource's name and can assign labels to it
# these labels can be used to tie resources together. In the service.yaml
# file you'll see it refers back to this `run: example` label.
metadata:
labels:
run: example
name: example
# how many replicas of the declared pod should I run ?
spec:
replicas: 1
selector:
matchLabels:
run: example
# the Pod that the Deployment will manage the lifecycle of.
# You can see once again the use of the label and the containers
# to run as part of the pod.
template:
metadata:
labels:
run: example
spec:
containers:
- image: nginx:alpine
imagePullPolicy: IfNotPresent
name: example
Explore the service.yaml
file in a text editor. Following is an abbreviated version of it:
apiVersion: v1
kind: Service
metadata:
labels:
run: example
name: example
spec:
# The clusterIP is the IP address that other nodes can use to access the pods
# Since we didn't specify and IP Kubernetes picked one for us.
clusterIP: 10.0.0.62
# The Port mappings for the service.
ports:
- nodePort: 32587
port: 80
protocol: TCP
targetPort: 80
# Any pods that have this label will be exposed by this service.
selector:
run: example
# All Kubernetes worker nodes will expose this service to the outside world
# on the port specified above as `nodePort`.
type: NodePort
Delete the resources you just created so that you can move on to creating the Helm Chart:
$ kubectl delete service,deployment example
service "example" deleted
deployment "example" deleted
Create and Deploy a Basic Helm Chart
The minimum set of things needed for a valid helm chart is a set of templates (which we just created) and a Chart.yaml
file which we need to create.
Copy and paste the following into your text editor of choice and save it as Chart.yaml
:
Note: the file should be capitalized as shown above in order for Helm to use it correctly.
apiVersion: v1
description: My First Helm Chart
name: my-first-helm-chart
version: 0.1.0
We now have the the most basic Helm Chart possible:
$ tree
.
├── Chart.yaml
└── templates
├── deployment.yaml
└── service.yaml
Next you should be able to install this helm chart giving it a release name of first
and using the current directory as the source of the Helm Chart:
$ helm install -n example .
NAME: example
LAST DEPLOYED: Wed Nov 22 10:55:11 2017
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1beta1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
example 1 1 1 0 1s
==> v1/Service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
example 10.0.0.62 <nodes> 80:32587/TCP 1s
Just as you did earlier you can use minikube
to get the URL:
$ curl $(minikube service example --url)
...
<title>Welcome to nginx!</title>
Congratulations! You’ve just created and deployed your first Helm chart. However its a little bit basic, the next step is to add some templating to the manifests and update the deployment.
Add variables to your Helm Chart
In order to render templates you need a set of variables. Helm charts can come with a values.yaml
file which declares a set of variables and their default values that can be used in your templates. Create a values.yaml
file that looks like this:
replicaCount: 2
image: "nginx:alpine"
These values can be accessed in the templates using the golang templating
engine. For example the value replicaCount
would be written as {{ .Values.replicaCount }}
.
Helm also provides information about the Chart and Release that can be handy to utilize.
Update your templates/deployment.yaml
to utilize our values:
apiVersion: apps/v1beta1
kind: Deployment
metadata:
labels:
run: "{{ .Release.Name }}"
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
name: "{{ .Release.Name }}"
namespace: default
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
run: "{{ .Release.Name }}"
template:
metadata:
labels:
run: "{{ .Release.Name }}"
spec:
containers:
- image: "{{ .Values.image }}"
name: "{{ .Release.Name }}"
Edit your templates/service.yaml
to look like:
apiVersion: v1
kind: Service
metadata:
name: "{{ .Release.Name }}"
labels:
run: "{{ .Release.Name }}"
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
release: "{{ .Release.Name }}"
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
run: "{{ .Release.Name }}"
type: NodePort
Once your files are written out you should be able to update your deployment:
$ helm upgrade example .
Release "example" has been upgraded. Happy Helming!
LAST DEPLOYED: Wed Nov 22 11:12:25 2017
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/Service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
example 10.0.0.79 <nodes> 80:31664/TCP 14s
==> v1beta1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
example 2 2 2 2 14s
You’ll notice that your Deployment now shows as having two replicas of your pod
demonstrating that the replicas
value provided has been applied:
$ kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
example 2 2 2 2 2m
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
example-5c794cbb55-cvn4k 1/1 Running 0 2m
example-5c794cbb55-dc7gf 1/1 Running 0 2m
$ curl $(minikube service example --url)
...
<title>Welcome to nginx!</title>
You can override values on the command line when you install (or upgrade) a Release of your Helm Chart. Create a new release of your helm chart setting the image to apache instead of nginx:
$ helm install -n apache . --set image=httpd:alpine --set replicaCount=3
NAME: apache
LAST DEPLOYED: Wed Nov 22 11:20:06 2017
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1beta1/Deployment
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
apache 3 3 3 0 0s
==> v1/Service
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
apache 10.0.0.220 <nodes> 80:30841/TCP 0s
Kubernetes will now show two sets of Deployments and Services and their corresponding pods:
$ kubectl get svc,deployment,pod
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
svc/apache NodePort 10.0.0.220 <none> 80:30841/TCP 1m
svc/example NodePort 10.0.0.79 <none> 80:31664/TCP 8m
svc/kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 58m
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
deploy/apache 3 3 3 3 1m
deploy/example 2 2 2 2 8m
NAME READY STATUS RESTARTS AGE
po/apache-5dc6dcd8b5-2xmpn 1/1 Running 0 1m
po/apache-5dc6dcd8b5-4kkt7 1/1 Running 0 1m
po/apache-5dc6dcd8b5-d2pvt 1/1 Running 0 1m
po/example-5c794cbb55-cvn4k 1/1 Running 0 8m
po/example-5c794cbb55-dc7gf 1/1 Running 0 8m
By templating the manifests earlier to use the Helm release name in the labels for the Kubernetes resources the Services for each release will only talk to its corresponding Deployments:
$ curl $(minikube service example --url)
...
<title>Welcome to nginx!</title>
$ curl $(minikube service apache --url)
<html><body><h1>It works!</h1></body></html>
Clean Up
Delete your helm deployments:
$ helm delete example --purge
release "example" deleted
$ helm delete apache --purge
release "apache" deleted
$ minikube delete
Deleting local Kubernetes cluster...
Machine deleted.
Summary
Congratulations you have deployed a Kubernetes cluster on your laptop using minikube and deployed a basic application to Kubernetes by creating a Deployment and a Service. You have also built your very first Helm chart and used the Helm templating engine to deploy different versions of the application.
Helm is a very powerful way to package up your Kubernetes manifests to make them extensible and portable. While it is quite complicated its fairly easy to get started with it and if you’re like me you’ll find yourself replacing the Kubernetes manifests in your code repos with Helm Charts.
There’s a lot more you can do with Helm, we’ve just scratched the surface. Enjoy using and learning more about them!
No comments:
Post a Comment