Written by Deepak Vohra
Kubernetes is a cluster manager for Linux containers, not just Docker containers but Rocket containers also, and support for still other types shall be added. Docker containers are the most commonly used containers. Docker containers introduced a new level of modularity and fluidity for applications with the provision to package applications including dependencies, and transfer and run the applications across different environments. But with the use of Docker containers in production practical problems became apparent such as which container to run on which node (scheduling), how to increase/decrease the number of running containers for an application (scaling), how to communicate within containers. Kubernetes was designed to overcome all these and other practical issues of container cluster management.
In this tutorial we shall discuss deploying a Hello World application in a Docker container cluster and managing the cluster with Kubernetes.
Kubernetes artifacts include Pod, Node, Cluser, Service, and Replication controller.
A pod is a collection of Docker containers collocated, forming the atomic unit of deployment. The containers within a Pod could be based on the same Docker image or could be for different containers that have dependency on each other. A pod is an abstraction for a group of containers and being in the same Pod the containers share volumes and network. If all the Docker containers in a Pod are accessible from a bash shell as would be if the Dockerfiles for all the Docker images are based on a Linux Docker image such as “ubuntu” or “debian”, the containers share the filesystem and IP address with the port on which each container is exposed being different. Applications within a pod may access each other at “localhost”. The Pod is the basic unit of management with the scheduling and replication being performed at the Pod level rather than at individual container level. For example if a Pod consists of containers based on two Docker images and the replication level is set at 1, a single Pod replica consists of two containers, one for each type of Docker image.
A node is a machine (physical or virtual) on which Kubernetes pods may be run. The node could be the master node or one of the worker nodes.
A cluster is a collection of nodes, one of which is the Master node and the others if any are the worker nodes. A highly available cluster consists of multiple master nodes.
A replication controller manages the replication level of pod replicas. A replication controller ensures that the configured number of pod replicas are running at any given time. If a replica fails, the replication controller starts a new replica. The replication controller is also used for scaling the replication level. If a cluster is scaled up to have more Pod replicas, the replication controller increases the number of pods within a cluster.
A service is the external client interface for pod/s providing endpoint/s (IPAddress:Port) at which the application/s running in the Pod/s may be invoked. A service has a single IP address but provides zero or more endpoints depending on the Pods represented by the service. Pods have labels and services have selectors to select the pods. An external client does not access the application/s running in a Pod directly but does so via a service. An external client only needs to know the service endpoint at which a particular application is exposed. A service routes requests for an application in a round-robin manner to one of the pods selected using selectors. Thus, a service is a high level abstraction for application/s. A service also supports load balancing.
A label is a key-value pair used to identify a resource such as a pod, service or replication controller; most commonly a pod. A service selector uses labels to select the pods it manages. For example, if a pod is labelled "run=hello-world" and a service "selector" is set as "run=hello-world" the pod is selected by the service.
A selector is a key-value expression to identify resources by matching labels on the resources. A selector is typically used in a replication controller to select the Pod/s it manages and also used in a service to select the Pod/s it manages. As discussed in the preceding sub-section a service selector expression “run=hello-world” would select all pods with the label “run=hello-world”.
A name is used to identify a resource. A name is used in addition to a label. For selecting resources a label is used and not a name. The name is optional in some artifacts.
We have used an Amazon EC2 Linux instance created from AMI Ubuntu Server 14.04 LTS (HVM), SSD Volume Type - ami-d05e75b8. The following software is required for this tutorial and installation of each has been discussed in an earlier tutorial.
We have used an Amazon EC2 Linux instance created from AMI Ubuntu Server 14.04 LTS (HVM), SSD Volume Type - ami-d05e75b8.
SSH Login to the Master Node. Output the Kubernetes cluster information from the Master node using the following command.
kubectl get nodes
The two nodes in the cluster get listed.
In the following sections we shall run a hello-world application with the tutum/hello-world Docker image on the Kubernetes cluster manager. An application may be run on the command line imperatively using the kubectl tool or declaratively using a definition file each for a Pod, replication controller and service. We shall discuss each of these methods.
Start the Kubernetes master and worker node as discussed in an earlier tutorial. Run the kubectl run command using the Docker image tutum/hello-world to run a hello-world application. The –s command parameter specifies the Kubernetes API server host:port. The –image command parameter specifies the Docker image to run as tutum/hello-world. The –replicas parameter sets the number of replicas to create as 1. A replication controller is created even if the –replicas parameter is not specified and default number of replicas is set to 1. The –port parameter specifies the container port the application is hosted at as 80, which is also the default.
kubectl -s http://localhost:8080 run hello-world --image=tutum/hello-world --replicas=1 --port=80
A new Kubernetes Pod with name prefixed with hello-world consisting of a Docker container called hello-world gets created and a replication controller called “hello-world” also gets created. The pod is created implicitly and label “run=hello-world” is added to the pod. The number of Pod replicas is 1.
List the replication controller created.
kubectl get rc
The hello-world replication controller gets listed.
List the pods.
kubectl get pods
The single pod created gets listed. A pod name is assigned automatically and is prefixed with replication controller name. A Pod STATUS “Running” is listed. The Pod is ready as indicated by 1/1 in the READY column. A value of 1/1 in the READY column indicates that 1 of 1 containers in the Pod are ready. The nReady/nTotal syntax for the READY column implies that nReady of the total nTotal containers in the Pod are ready.
In the next sub-section we shall create a service for the hello-world application.
Create a Kubernetes service using the kubectl expose command from the replication controller hello-world. The port to expose the service is set to 8080 and the service type is LoadBalancer.
kubectl expose rc hello-world --port=8080 --type=LoadBalancer
A Kubernetes service called hello-world gets created.
The different types of services are ClusterIp (uses a cluster-internal IP only), NodePort (in addition to a cluster-internal IP exposes the service on each node of the cluster) and LoadBalancer (in addition to the NodePort features requests the cloud provider to provide a load balancer for the service). The default is ClusterIP.
List all the Kubernetes services.
kubectl get services
A “hello-world” service gets created.
With the kubectl describe pod command to list detailed information about the pod hello-world-5z3jf.
kubectl describe pod hello-world-5z3jf
Detailed information about the pod gets listed.
Describe the service hello-world.
kubectl describe pod hello-world
Service description includes the labels, slector, type,IP Address, Port, and endpoints.
Next, we shall invoke the application using the IP Address 184.108.40.206 listed in the IP field.
The hello-world application may be invoked using the IP 10.1.17.2 for the application as listed previously with following curl command.
The HTML markup output for the application gets listed.
Next we shall display the HTML output in a browser. we need to invoke the application from a browser using URL 10.1.17.2:80. As a browser is not available on the Amazon EC2 Ubuntu instance by default set up a SSH tunnel to the IP Address of the application using local port forwarding. Obtain the Public DNS for the Amazon EC2 instance (ec2-54-172-248-196.compute-1.amazonaws.com) from the Amazon EC2 Console and run the following command to set up a SSH tunnel to the 10.1.17.2:80 host:port from a local machine. The –L sets local port forwarding to remote port 10.1.17.2:80.
ssh -i “docker.pem” -f -nNT -L 80:10.1.17.2:80 email@example.com
Local IP address localhost:80 gets forwarded to 10.1.17.2:80.
Invoke the URL http://localhost in a browser on the local machine. The HTML output from the hello-world application gets displayed. The hostname is the same as the Pod name.
A replication controller called hello-world was created by default when we created the hello-world application with replicas set as 1. Next, we shall scale up the number of Pods to 2 using the kubectl scale command. Run the following command to scale up the replication controller hello-world to 2.
kubectl scale rc hello-world --replicas=2
An output of “scaled” implies that the replication controller has been scaled.
Subsequently, list the pods.
The Pods are listed with STATUS->Running and READY state 1/1. Scaling to 2 replicas does not create 2 new Pods, but the total number of Pods is scaled to 2.
Describe the hello-world service using the following command.
kubectl describe svc hello-world
The service name, label/s, selector,type, IP, and Endpoints get listed. Two endpoints are listed, one each for the two Pods.
Invoke the service using one of the two endpoints with curl command.
The HTML markup output gets displayed.
As discussed previously the HTML output may be displayed in a browser by setting up SSH tunneling with port forwarding for the newly added endpoints.
To delete the replication controller hello-world run the following command.
kubectl delete rc hello-world
The replication controller gets deleted. Subsequently list the replication controllers.
The hello-world replication controller does not get listed.
Deleting a replication controller deletes the replication controller and the Pods managed by the replication controller. List the Pods.
The hello-world Pod does not get listed.
Deleting a replication controller does not delete the service managing the replication controller. The kubectl get services command still lists the service.
Next, we shall create the same hello-world application declaratively using a definition file each for a Pod, Service and Replication Controller. The definition files may be configured in YAML or JSON. We have used YAML format. Create the files hello-rc.yaml, hello-world-service.yaml, and hello-world.yaml.
Create a hello-world.yaml file and copy the following listing to the file. The apiVersion mapping is for the API schema version (v1), kind is the resource and must be set to Pod. The metadata mapping specifies the Pod’s metadata and sets the name to hello-world. The spec mapping specifies the Pod behavior with the spec->containers mapping for the containers specification. The hello-world.yaml listed specifies a single container for Docker image tutum/hello-world. Container name is set to hello-world and container ports mapping is for a list of ports in which a single containerPort is set to 8080.
A YAML lint validator (http://www.yamllint.com/) could be used to validate the YAML syntax in the hello-world.yaml. The YAML lint validator does not validate if the definition file conforms to the Pod schema.
For the Pod schema refer http://kubernetes.io/v1.1/docs/api-reference/v1/definitions.html#_v1_pod.
The preceding configuration is equivalent to the following imperative command.
kubectl run hello-world --image=tutum/hello-world --port=8080
Next, create the hello-world application from the hello-world.yaml definition file with the following kubectl create command. The –validate option validates the Pod definition file.
kubectl create -f hello-world.yaml --validate
A Pod called hello-world gets created.
List the Pods.
The hello-world Pod gets listed with STATUS as “Running” and READY state as “1/1”, which implies that 1 of 1 containers in the pod are ready.
Describe the hello-world Pod.
Pod description includes name, Docker image/s, labels if any, status, IP, and replicaiton controllers.
Invoke the hello-world Pod application using the IP 10.1.42.2.
The HTML markup output from the hello-world application gets displayed.
The Pod created is not being managed by any replication controller or service. The hello-world service created imperatively does not list an endpoint for the Pod.
To access the hello-world application running in the standalone Pod set up port forwarding from a local machine to the IP address of the hello-world Pod and subsequently invoke the local url in a browser on a local machine.
Delete the hello-world service as we shall be creating a service hello-world declaratively in the next section.
kubectl delete svc hello-world
Create a service definition file hello-world-service.yaml. The main mappings in the service definition file are kind, metadata and spec. The kind must be set to Service. Two labels app and name are also included. The spec mapping is for the service specification and specifies ports mapping for port 80 with name http. Optionally a targetPort may be set, which defaults to the same value as port. The selector is the main mapping in the spec and is used for selecting the Pods to expose via the service. The app:hello-world selector implies that all Pods with label “app=hello-world” are selected; the app:hello-world setting translates to app=hello-world.
The service schema is available at http://kubernetes.io/v1.1/docs/api-reference/v1/definitions.html#_v1_service.
Create a service from the definition file hello-world-service.yaml with the kubectl create command.
kubectl create -f hello-world-service.yaml
The hello-world service gets created.
List the services.
The hello-world service gets listed.
Describe the hello-world service.
The service name,namespace,labels,selector,type,Ip get listed. As the hello-world service is not managing any Pods no endpoint gets listed.
Next, create a replication controller definition file hello-rc.yaml. Configure a replication controller and label the replication controller to match the selector of the service created previously. The kind mapping of a replication controller must be ReplicationController. The replicas is set to 2 to create two Pod replicas. At least one of the labels in the template->metadata-> labels must match the service selector expression in the service definition file for the Pod to be managed by the service. Add the app:hello-world label to the replication controller template. The template may define one or more containers. Add container definition for only one container for image tutum/hello-world. The hello-rc.yaml listed:
The schema for the replication controller is available at http://kubernetes.io/v1.1/docs/api-reference/v1/definitions.html#_v1_replicationcontroller.
Create the replication controller using the definition file hello-rc.yaml with the kubectl create command.
kubectl create -f hello-rc.yaml
Subsequently list the replication controllers.
A hello-world replication controller gets created.
List the replication controllers.
The hello-rc replication controller gets listed.
List the Pods created with the replication controller.
The two Pods created from the definition file get listed. The Pod created with the Pod definition file also gets listed but is not associated with the replication controller.
kubectl describe service hello-world
The service detail including the Endpoints gets listed. Two service endpoints are listed because two Pods are managed by the service.
The Service endpoints may invoked using curl on the command line or in a browser after setting port forwarding.
To scale the hello-world replication controller use the kubectl scale command. As an example scale to 3 replicas.
kubectl scale rc hello-world --replicas=3
An output of “scaled” indicates the replication controller has been scaled.
The number of Pods for the hello-world replication controller increases to 3. List the Pods.
Three pods get listed in addition to the hello-world Pod created initially using a Pod definition file. The Pods managed by the replication controller have name with format hello-world-<variable>.
The kubectl scale command may also be used to scale down the replication controller. As an example scale down to 1 replicas.
kubectl scale rc hello-world --replicas=1
Subsequently list the Pods.
The number of replicas managed by the hello-world rc gets listed as 1.
To find which Pod is running on which of the nodes in the cluster run the following command.
kubectl get pods –o wide
One of the two Pods is listed as running on the master node and the other on the worker node.
In this tutorial we introduced the Kubernetes concepts including Node, Pod, Service, Replication Controller, Labels and Selector. We developed a hello-world based on the tutum/hello-world Docker image application both imperatively on the command line, and declaratively using definition files.