Containers Dev Ops Kubernetes

Kubernetes: Getting Started

Kubernetes is an open-source platform for managing containerized applications across a cluster of physical or virtual machines. The original inspiration for Kubernetes was Google’s Borg system. Borg is a cluster management system that handles hundreds of thousands of jobs and applications across massive Google data centers. Kubernetes was intended to be a friendlier version of the cluster management system that everyone could use.

The popularity of containers in the software development process is making Kubernetes popular too. In the old software development process, applications were deployed on physical host machines. Developers working on different components of the application needed to maintain a cohesive environment. Operation and IT personnel needed to carefully manage executables, configurations, and libraries. Different components of the application could run into conflict during the integration process. Also, the process was susceptible to human errors and miscommunications.

Virtual machines (VM) helped bring some level of reliability to the process. But it was still hard to manage applications. Also, VMs are expensive to maintain. Containers changed the landscape. With containers, it was possible for developers working on different components of the same software to maintain separate environments. Containers are light-weight, inexpensive and fast. These benefits gave rise to the idea of developing software using microservices where each container serves a specific task for the application.

With the rise of container use, Kubernetes has become an effective tool to schedule and run applications across clusters. As a platform, it can free developers from the burden of dealing with any kind of machines. Instead of designing for host-centric infrastructures with physical or virtual machine considerations, developers can start designing for container-centric infrastructure. Kubernetes provides the necessary layer of abstraction.

Part 1: Concepts

Master Components

Master components are the controlling services for the cluster. These components handle global decisions and events. Any node in the cluster can run them. However, assigning particular nodes to these components is considered good practice.

kube-apiserver

The kube-apiserver serves the Kubernetes API. Kubernetes API implements a RESTful interface. It works as the bridge between various Kubernetes components like pods, services, replication controllers and others. It is responsible for consistency of communication between the etcd store and the deployed containers.

etcd

The etcd is responsible for storing all Kubernetes cluster data. The etcd project was developed by the CoreOS team. It is a lightweight, distributed key-value store that uses HTTP/JSON API. Nodes in the cluster can use configuration data from the etcd to discover services and recover from failed states. Due to the importance of the data, etcd should be backed up properly.

kube-controller-manager

The kube-controller-manager runs various controllers to provide different services. For example, node controllers recover failed nodes and replication controllers maintain the correct number of pods. Each controller runs as a separate thread and depends on the etcd information to perform their tasks.

cloud-controller-manager

The cloud-controller-manager provides cloud-specific controllers. It can be disabled in the kube-controller-manager. The cloud-controller-manager has been separated out from the core to allow the Kubernetes core to evolve independently of cloud provider specific code. In the past, the dependencies were causing problems.

kube-scheduler

The kube-scheduler is responsible for workload distribution. It keeps track of resource requirements and assigns nodes for newly created pods. It also takes care of the quality of service requirements.

addons

Addons are pods and services used to implement cluster features. Users can use the add-on manager to create and maintain addons. Some important and useful addons are DNS, Web UI(Dashboard), Container Resource Monitoring and Cluster-level logging.

Node Components

A worker machine in Kubernetes is called a node. Node components are present in every node and they handle different aspects of the workload.

kubelet

The kubelet service on each node is the primary agent. It keeps track of the pods assigned to its node through apiserver or local configuration file. It communicates with the master components to find out work requests and report the status of its node.

kube-proxy

The kube-proxy is a small proxy service on each node to deal with individual host subnetting. It can perform rudimentary load balancing for TCP and UDP.

docker

Kubernetes primarily depend on docker to run containers. It is able to build applications from docker images.

rkt

Kubernetes also supports rkt containers. The support is currently experimental.

supervisord

The supervisord can be used to monitor and control kubelets and docker containers.

fluentd

The fluentd is a deamon for providing custer-level logging.

Workloads

Kubernetes workloads can be defined as follows:

Pods

A pod is a fundamental unit in the Kubernetes workload. Containers are not individually assigned to hosts. Groups of containers, generally belonging to an application, are represented as a pod and the pod is then deployed to the host as a single unit. Of course, a pod can contain only one container. This is generally more common in Kubernetes. However, containers are grouped together based on resource and application needs. The grouping is intended to optimize resource sharing.

Controllers

Controllers like replica sets, replication controller, deployments, stateful sets, garbage collection and cron jobs help manage Kubernetes workloads. Replication controllers manage the number of pods. It starts and terminates pods to maintain the correct number of pods running. Deployment controller helps change pods and deployment objects to reach the desired deployment state.

Other Important Ideas

Services

Kubernetes pods are created and destroyed regularly. So it’s difficult to keep track of them through IP addresses. The dynamic nature of the pods makes it difficult for them to communicate with each other. A service works as an abstraction. It provides the policy to reach a logical set of pods. In Kubernetes, a service is a REST object. Services simplify the container design.

Labels

Labels are a powerful way to keep track and manage groups of working components. Labels are key-value pairs that work as arbitrary tags to help gain finer control over different functions of the system.

Part 2: Hands-on Project

Running a Minikube Project

Minikube is a binary that sets up a single Kubernetes cluster on a local machine. In this project, a Node.js application will be turned into a docker container image and the image will be run on Minikube.

Installing Minikube, kubectl, Hypervisor, NodeJS and Docker

You can install Minikube and Kubernetes command line tool kubectl on Mac OS X, Linux and Windows with various hypervisors. The instructions for different operating systems are available here. Also, you will need NodeJS installed on your machine to run the example HelloWorld application. You can install docker here.

Starting a Cluster

Use the following command to start a cluster:

$ minikube start

Starting local Kubernetes v1.7.5 cluster...
Starting VM...
Downloading Minikube ISO
106.36 MB / 106.36 MB [============================================] 100.00% 0s
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.

Use the command below to see if the cluster is running properly:

$ kubectl cluster-info

Kubernetes master is running at https://192.168.99.100:8443

Create Application Image

Let’s create a server.js file with the following content:

var http = require('http');

var handleRequest = function(request, response) {
  console.log('Received request for URL: ' + request.url);
  response.writeHead(200);
  response.end('Hello World!');
};
var www = http.createServer(handleRequest);
www.listen(8080);

You can run the following command:

$ node server.js

And check if the server is running on http://localhost:8080. You should see “Hello World!” text on the web page.

Convert to Docker Container

In the same directory as server.js create a file Dockerfile with following text:

FROM node:6.9.2
EXPOSE 8080
COPY server.js .
CMD node server.js

The Dockerfile will create an image that will start from the node:6.9.2 image on the Docker Hub.
We want to run the docker images locally. So the following command will tell docker to use Minikube deamon to for docker image storage:

$ eval $(minikube docker-env)

You can use eval $(minikube docker-env -u) to change it back to the default.
Now let’s build the docker image:

$ docker build -t my-node:v1 .

Sending build context to Docker daemon  3.072kB
Step 1 : FROM node:6.9.2
6.9.2: Pulling from library/node
75a822cd7888: Pull complete 
57de64c72267: Pull complete 
4306be1e8943: Pull complete 
871436ab7225: Pull complete 
0110c26a367a: Pull complete 
1f04fe713f1b: Pull complete 
ac7c0b5fb553: Pull complete 
Digest: sha256:2e95be60faf429d6c97d928c762cb36f1940f4456ce4bd33fbdc34de94a5e043
Status: Downloaded newer image for node:6.9.2
 ---> faaadb4aaf9b
Step 2 : EXPOSE 8080
 ---> Running in da7d251b3fd5
 ---> 881f9fb69b2c
Removing intermediate container da7d251b3fd5
Step 3 : COPY server.js .
 ---> 0acf61d9e75e
Removing intermediate container 3a4025539cf6
Step 4 : CMD node server.js
 ---> Running in 8aa9a4cbd723
 ---> 41445e5c48fe
Removing intermediate container 8aa9a4cbd723
Successfully built 41445e5c48fe

Deploy to the Cluster
To deploy my-node:v1, run the following command:

$ kubectl run my-node --image=my-node:v1 --port=8080

deployment "my-node" created

It will create a pod on the cluster. We can check the pod statuses with the following commands:

$ kubectl get deployments

NAME      DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
my-node   1         1         1            1           34s
$ kubectl get pods

NAME                      READY     STATUS    RESTARTS   AGE
my-node-276881918-qth5s   1/1       Running   0          1m
$ kubectl get events

LASTSEEN   FIRSTSEEN   COUNT     NAME                      KIND         SUBOBJECT                  TYPE      REASON                    SOURCE                  MESSAGE
32m        32m         1         minikube                  Node                                    Normal    Starting                  kube-proxy, minikube    Starting kube-proxy.
32m        32m         1         minikube                  Node                                    Normal    Starting                  kubelet, minikube       Starting kubelet.
32m        32m         2         minikube                  Node                                    Normal    NodeHasSufficientDisk     kubelet, minikube       Node minikube status is now: NodeHasSufficientDisk
32m        32m         2         minikube                  Node                                    Normal    NodeHasSufficientMemory   kubelet, minikube       Node minikube status is now: NodeHasSufficientMemory
32m        32m         2         minikube                  Node                                    Normal    NodeHasNoDiskPressure     kubelet, minikube       Node minikube status is now: NodeHasNoDiskPressure
32m        32m         1         minikube                  Node                                    Normal    NodeAllocatableEnforced   kubelet, minikube       Updated Node Allocatable limit across pods
32m        32m         1         minikube                  Node                                    Normal    RegisteredNode            controllermanager       Node minikube event: Registered Node minikube in NodeController
32m        32m         1         minikube                  Node                                    Normal    NodeReady                 kubelet, minikube       Node minikube status is now: NodeReady
6m         6m          1         minikube                  Node                                    Normal    RegisteredNode            controllermanager       Node minikube event: Registered Node minikube in NodeController
5m         5m          1         minikube                  Node                                    Normal    Starting                  kubelet, minikube       Starting kubelet.
5m         5m          1         minikube                  Node                                    Normal    NodeAllocatableEnforced   kubelet, minikube       Updated Node Allocatable limit across pods
5m         5m          1         minikube                  Node                                    Normal    NodeHasSufficientDisk     kubelet, minikube       Node minikube status is now: NodeHasSufficientDisk
5m         5m          1         minikube                  Node                                    Normal    NodeHasSufficientMemory   kubelet, minikube       Node minikube status is now: NodeHasSufficientMemory
5m         5m          1         minikube                  Node                                    Normal    NodeHasNoDiskPressure     kubelet, minikube       Node minikube status is now: NodeHasNoDiskPressure
5m         5m          1         minikube                  Node                                    Normal    NodeNotReady              kubelet, minikube       Node minikube status is now: NodeNotReady
5m         5m          1         minikube                  Node                                    Normal    Starting                  kube-proxy, minikube    Starting kube-proxy.
5m         5m          1         minikube                  Node                                    Normal    NodeReady                 kubelet, minikube       Node minikube status is now: NodeReady
2m         2m          1         my-node-276881918-qth5s   Pod                         Normal    Scheduled                 default-scheduler       Successfully assigned my-node-276881918-qth5s to minikube
2m         2m          1         my-node-276881918-qth5s   Pod                          Normal    SuccessfulMountVolume     kubelet, minikube       MountVolume.SetUp succeeded for volume "default-token-r5pl1" 
2m         2m          1         my-node-276881918-qth5s   Pod          spec.containers{my-node}   Normal    Pulled                    kubelet, minikube       Container image "my-node:v1" already present on machine
2m         2m          1         my-node-276881918-qth5s   Pod          spec.containers{my-node}   Normal    Created                   kubelet, minikube       Created container
2m         2m          1         my-node-276881918-qth5s   Pod          spec.containers{my-node}   Normal    Started                   kubelet, minikube       Started container
2m         2m          1         my-node-276881918         ReplicaSet                              Normal    SuccessfulCreate          replicaset-controller   Created pod: my-node-276881918-qth5s
2m         2m          1         my-node                   Deployment                              Normal    ScalingReplicaSet         deployment-controller   Scaled up replica set my-node-276881918

Create a Service
A pod is inaccessible. You have to create a service to make the pod accessible to the world. The following command should create the necessary service:

$ kubectl expose deployment my-node --type=LoadBalancer

service "my-node" exposed

You can check the service status like this:

$ kubectl get services

NAME         CLUSTER-IP   EXTERNAL-IP   PORT(S)          AGE
kubernetes   10.0.0.1     <none>        443/TCP          34m
my-node      10.0.0.213   <pending>     8080:31460/TCP   31s

If you use the following command, it will open up the service on a web browser:

$ minikube service my-node

Opening kubernetes service default/my-node in default browser...

You can check what going in your pod with the “logs” command — kubectl logs [nameOfThePod].

$ kubectl logs my-node-276881918-qth5s

Received request for URL: /
Received request for URL: /favicon.ico

The above logs are showing the requests made to the server.js application running on the cluster.

Cleaning up
You can delete the service and the pod with the following commands:

$ kubectl delete service my-node

service "my-node" deleted

$ kubectl delete deployment my-node[/code]

deployment "my-node" deleted

You can stop the minikube:

$ minikube stop

Stopping local Kubernetes cluster...
Machine stopped.

Conclusion

Kubernetes is a vast system with large-scale capabilities. Kubernetes documentation is the best place to learn about this powerful technology.

Further Study:
Kubernetes Documentation: https://kubernetes.io/docs

About the author

Zak H

Zak H

Zak H. lives in Los Angeles. He enjoys the California sunshine and loves working in emerging technologies and writing about Linux and DevOps topics.