In the space of a few years, container platforms like Docker have become mainstream tools for deploying applications and microservice architectures. They offer gains in speed, efficiency, and security. They also fit well with another rising star, DevOps. But container platforms typically do not offer tools for managing containers at scale. Manual management processes may work for a few containers and the apps or microservices they contain, but they rapidly become unworkable as the number of containers rises.
Spotting the problem, or indeed the opportunity to improve matters, Google created Kubernetes to automate container management. Kubernetes, Greek for “pilot (of a ship)”, deploys, scales, and manages “boatloads” of containers for you. The building blocks for the Kubernetes technology are reasonably straightforward, at least for initial working configurations.
In this article, we go through the main steps of getting your first Kubernetes management cluster up and running. We use the KISS (Keep It Simple, Stupid!) approach to focus on the key points. More advanced aspects are left as subjects for other posts. We also assume you have a basic understanding of containers, images, and container platforms like Docker or Rocket.
Kubernetes Concepts 101
A common understanding of terms is always a good idea. Here’s a mini-glossary for Kubernetes.
- Master. The server or machine running Kubernetes and directing the container management activities on other servers.
- Nodes. The other servers, also known as slaves or minions, running Kubernetes components like agents and proxies, as well as pods (see below) that hold the containers. Nodes take their orders from, and report back to the master.
- Pod. The smallest manageable unit for Kubernetes. A pod may contain one container, several containers, a complete app or part of an app. In other words, a pod is also flexible.
- Service. An interface (endpoint) for access to one or more pods on a node. Acts as a proxy and does load balancing across a group of replicated pods. Pods may come and go, but a service is designed to stay put.
- Replication Controller. Management functionality for ensuring deployment of the required number of pods. Will automatically create or eliminate pods, as needed to maintain the required state. Newer functionality (Kubernetes “deployment”) now offers an advanced alternative to replication controllers, but for the sake of simplicity, we still discuss them here.
- Kubectl. A command line interface for you to tell Kubernetes what to do.
Kubernetes terminology extends further, but this is enough for us to get started.
Getting and Installing Kubernetes
Google made Kubernetes freely available and free to use. You can:
- Download binaries for installation in a Linux or similar environment (Linux running in Windows, etc.)
- Download a version called Minikube to automatically install a master and a node on the same machine (possibilities include Linux, Mac OS X and Windows).
A Minikube installation can greatly simplify things. Initial installation is often much easier. Master-node communication is done within the same (virtual) machine, so network configuration is not a factor. Minikube also conveniently includes container runtime functionality (the Docker engine). Later, you may well want the master on one machine and nodes on others. To start with, however, the Minikube installation for Mac OS X as an example can be as simple as running the following two commands:
brew cask install minikube
brew install kubectl
You can also try out this Kubernetes online server that lets you launch Kubernetes and try out its commands, even before you proceed to an installation of your own.
After installation, starting Minikube is simple too:
minikube start
Kubectl and apiserver
When Kubernetes is installed (via Minikube or another way), it makes an API available through which you can issue different Kubernetes commands. The component for this is called apiserver and it is part of the master. Kubectl, the CLI, communicates with apiserver. Kubectl can communicate locally, as in Minikube, or remotely, for example when the Kubernetes master is running on another machine or in the cloud. So, when you’re ready, you can simply point kubectl to a remote installation from the same machine on which you started with Minikube. Of course, by that stage you may be accessing apiserver programmatically anyway, rather than via the CLI.
Starting a Kubernetes Pod
A pod holds one or more containers. Pods are the ultimate management goal of Kubernetes, so let’s make a pod and start managing it. A simple way to do this is to make a YAML file with the basic pod configuration details inside. After, we’ll use kubectl to make a pod, simply giving it the file name to point it to the configuration of the pod to be made. The configuration file (“pod1.yml
” for instance) will have content like this:
apiVersion: v1
kind: Pod
metadata:
name: my_pod
labels:
app: my_app
spec:
containers:
name: my_app
image: my_app
ports:
containerPort: 80
The kubectl command to make the pod looks like this:
kubectl create -f pod1.yml
We can check that the pod now exists by entering:
kubectl get pods
To find out more about the range of kubectl commands available, simply enter: kubectl
Creating a Kubernetes Service
Next, we’ll make a Kubernetes service. The service will let us address a group of replicated pods as one entity. It will also do load balancing across the group. We can use the same approach as for making a pod, i.e. make another YAML file (“service1.yml
”), this time with the service configuration details. The contents of the file will look something like this:
apiVersion: v1
kind: Service
metadata:
name: my_service
spec:
selector:
app: my_app
version: v1
ports:
protocol: TCP
port: 4000
The kubectl command to make the service looks like this:
kubectl create -f service1.yml
We can check that the service now exists by entering:
kubectl get svc
Making a Replication Controller
We’re now ready for some Kubernetes automation, albeit on a local basis. The replication controller for a group of replicated pods makes sure that the number of pods you specify is also the number of pods running at any given time. Once again, we can create another YAML file (“rc1.yml
”) along the lines of the following:
apiVersion: v1
kind: ReplicationController
metadata:
name: my_rc
labels:
app: my_app
version: v1
spec:
replicas: 8
selector:
app: my_app
version: v1
template:
metadata:
labels:
app: my_app
version: v1
spec:
containers:
name: my_app
image: (path)/my_app:1.0.0
ports:
containerPort: 4000
The kubectl command to make the replication controller looks like this:
kubectl create -f rc1.yml
When you now use the command:
kubectl get pods
you will see eight pods running, because of the “replicas: 8
” instruction in the “rc1
” YAML file. Kubernetes also uses information in the YAML files we have shown here to associate service1
and rc1
, so that somebody addressing service1
will now be routed by service1
to one of the eight pods created by rc1
.
The replication controller keeps track of each pod via a label that Kubernetes gives the pod, in the form of a key/value pair. The Kubernetes master keeps all such labels in an etcd key value store. After you have started the replication controller, you can try deleting (kubectl command “delete
”) one of the replicated pods to see how the replication controller automatically detects the deletion because a known label has disappeared, and makes a new replicated pod to replace the deleted one.
Setting Up Separate Kubernetes Nodes
So far, we’ve done everything on the same local machine. This is good for seeing how to start using Kubernetes. It is also a useful environment for development, so the local one-master-one-node cluster that we have set up already brings benefit.
The next step is to distribute Kubernetes management of containers over multiple nodes that are also remote from the master. This allows you to make use of additional Kubernetes functionality, like its ability to decide which servers to use for which containers, making efficient use of server resources as it goes. The Kubernetes components in the master are the apiserver, the etcd key value store, a scheduler, and a controller-manager. For each node, the components are an agent (kubelet) for communicating with the master, a container runtime component (like Docker), and a proxy (a Kubernetes load-balancing service).
The main steps to split out the master and the nodes are:
- Make sure the system with the master and the node systems can resolve each other’s address (for example, by adding
/etc/hosts
entries for Linux systems) - Configure the
apiserver
andetcd
components to listen on the network connecting the master and the nodes - Install the kubernetes-node package on each node
- Install and configure tunneling (such as flannel) for inter-node communication.
More Advanced Steps
Further possibilities with Kubernetes include automated rollover and rollback for new container images, the use of a graphical dashboard instead of a command line interface, and the addition of monitoring tools. Kubernetes also continues to be actively supported and developed, so expect new functionality and possibilities to arrive at regular intervals to supplement what we have discussed here. Sooner or later, our KISS approach will have to be modified too. Simplicity can only take you so far, but at least far enough to already get the benefit of a local Kubernetes management cluster, as we have described in this article.