1.3.1 Docker, Kubernetes and Helm

This chapter explains the tools behind microservice architectures. It requires reading the microservices chapter beforehand.

Docker

Docker is a program that allows users to package software code into microservices, or “containers.” These containers are similar to virtual machines, but rather than simulating hardware and installing an operating system (OS) and dependencies, Docker containers only virtualize the OS.

Here is a video that explains the basics of Docker, including Dockerfiles, images, and containers:

From this video you should learn what docker is, what the dockerfile is, what the image is and what a container is.

Kubernetes

Kubernetes is an open-source tool used to manage and scale large numbers of microservices. It is often referred to as the “operating system of the cloud,” and requires a basic understanding of Docker.

Here is a video that provides an overview of Kubernetes and its role in managing container infrastructure:

Kubernetes is highly complex, from this video all you need to take away as information is that kubernetes manages the container infrastructure and can replace, reboot, and scale the amount of containers of a docker architecture. You should also know pods as the smallest implementable running units on kubernetes and nodes as the machines you run pods on.

Helm

Helm is a tool used to automate the deployment and management of Kubernetes applications. It allows users to define their desired state (e.g. “I want to have one application based on this Docker image with these environment variables…") and automatically creates the corresponding Kubernetes object descriptions to achieve that state. This can be thought of as similar to a docker-compose.yaml file.

To use Helm, users must first import a Helm chart, which is a Kubernetes object description with variables. Helm uses a values.yaml file to populate these variables and generate the object descriptions.

Here is an example values.yaml file for Helm:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  selector:
    matchLabels:
      app: nginx
  replicas: 2 # tells deployment to run 2 pods matching the template
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.14.2
        ports:
        - containerPort: 80

You could now create and maintain all of them manually, which is what some companies do.

To do that automatically, you can use Helm.

Helm will take a values.yaml and will automatically create the corresponding Kubernetes object descriptions.

Example for a Helm template values:

### mqttbridge ###

mqttbridge:
  enabled: true
  image: unitedmanufacturinghub/mqtt-bridge
  storageRequest: 1Gi

### barcodereader ###

barcodereader:
  enabled: true
  image: unitedmanufacturinghub/barcodereader
  customUSBName: "Datalogic ADC, Inc. Handheld Barcode Scanner"
  brokerURL: "factorycube-edge-emqxedge-headless"  # do not change, points to emqxedge i
  brokerPort: 1883  # do not change
  customerID: "raw"
  location: "barcodereader"
  machineID: "barcodereader"

There is nothing comparable to Helm in the Docker world.

For this to work, one needs to import a so-called Helm chart first. This is nothing but a Kubernetes object description with some variables.

Example for a Kubernetes object description template (for Helm):

{{- if .Values.mqttbridge.enabled -}}
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {{ include "factorycube-edge.fullname" . }}-mqttbridge
  labels:
    {{- include "factorycube-edge.labels.mqttbridge" . | nindent 4 }}
spec:
  serviceName: {{ include "factorycube-edge.fullname" . }}-mqttbridge
  replicas: 1
  selector:
    matchLabels:
      {{- include "factorycube-edge.labels.mqttbridge" . | nindent 6 }}
  template:
    metadata:
      labels:
        {{- include "factorycube-edge.labels.mqttbridge" . | nindent 8 }}
    spec:
      containers:
      - name: {{ include "factorycube-edge.fullname" . }}-mqttbridge
        {{- if .Values.mqttbridge.tag }}
        image: {{ .Values.mqttbridge.image }}:{{ .Values.mqttbridge.tag }}
        {{- else }}
        image: {{ .Values.mqttbridge.image }}:{{ .Chart.AppVersion }}
        {{- end }}

A Helm chart can either be stored in a folder (e.g., when you clone the United Manufacturing Hub repository) or in a Helm repository (which we use in our default installation script).

You might be tempted to just clone the repository and change stuff in the Kubernetes object description template (in the sub-folder templates). We consider this a bad idea as these changes are now hard to track and to replicate somewhere else. Furthermore, when updating the Helm chart to a newer version of the United Manufacturing Hub, these changes will be lost and overwritten.

In UMHLens, you can now change the underlying Kubernetes object descriptions by e.g., clicking on a Deployment and then selecting edit. However, these changes will be reverted once you apply the Helm chart again.

Therefore, we recommend in production setups to only adjust the values.yaml in the Helm chart.