Chapter 1. Introduction to Kubernetes

 

What is Kubernetes?

Kubernetes refers to a portable and open source platform which is used for scaling, managing and automating the deployment of containerized workloads, applications, and services. Its ecosystem has become large and it is rapidly growing day after day. This can be attributed to the widely available Kubernetes support, tools, and services. Kubernetes was developed by Google and it came into existence in 2015 after being announced in June 2014 to people at Dockeron. Kubernetes descended from Borg which was developed by Google as the first unified-container management system. The main idea behind Borg was to provide management of both batch jobs and long-running services.

Kubernetes exhibits many features and it can be thought as a container, micro service or portable cloud platform which provides a container-centric management environment. This helps in orchestrating computing, storage infrastructure and networking on behalf of users’ workloads. This leads to a simplified Platform as a Service (PaaS) which has a flexible infrastructure hence supporting portability across various providers.

Kubernetes as a platform allows streamlining of application-specific workflows hence accelerating developer’s velocity. The ability to support Ad hoc orchestration leads to robust scale automation. Labels provide the capability of allowing users to organize their resources freely. In addition, Kubernetes have annotations. They enable resource decoration and customization with information which facilitates their workloads and also makes management of tools easy. Additionally, Kubernetes has a control panel which is built upon API’shence allowing other systems to be built on top of Kubernetes by users and developers.

Kubernetes eliminates the traditional, all-inclusive Platform as A service (PAAS) which was monolithic hence eliminating the need for orchestration. Kubernetes shifts the operation from hardware level to container level allowing PAAS features such as scaling, deployment, load balancing, monitoring, and logging. This leads to a system which is easy to use and its more resilient, robust, powerful and extensible.

Kubernetes Components

Google Kubernetes Engine is made up of multiple machines which are grouped together to form a cluster. The open source cluster management system by Kubernetes is used to power the GKE clusters. In order to deliver a well-functioning Kubernetes cluster, the following components are very crucial.

  • Master Components
  • Node Components
  • Addons

Master Components

These are the components which provide control of the cluster. They are used in global decision-making about the cluster. These decisions include detecting, scheduling and responding to events initiated by the cluster. Any machine can be used to run master components without facing any challenges. In order to ensure simplicity, there are written scripts which are used to start all master components simultaneously.Below is a brief overview of the master components of a Kubernetes cluster.

API Server

This is the component on the master that exposes the Kubernetes Rest API. It acts as the front-end for the Kubernetes control panel. As a result of its design, it can scale horizontally because of its stateless nature and stores all its data in the etcd cluster.The scalability continues as the number of instances increases. API server provides communication between various components hence maintaining the health of a cluster. It allows one to query, create, update or remove some components within the Kubernetes cluster.

Etcd

Etcd is a consistent, distributed and highly reliable data store. Kubernetes uses etcd to store all cluster data. In a small cluster which is transient, a single instance of etcd can be run on the node with all other components of the master. However, when there are more clusters which are substantial, three or five nodes would be suitable to ensure availability and redundancy. The data stored in etcd is accessed by Kubernetes API by use of simple HTTP or JSON API.

Control Manager

This refers to a collection of the various controller which are rolled up into one binary. Some of these controllers include; pod controller, replication controller, endpoint controller, services controller among others. All these managers are tasked with watching over the state of the cluster through the use of API and they direct as well as guide the cluster to the desired state. This is achieved by scaling the workloads up and down. Additionally, they manage, monitor and discover new nodes as well as updating the service endpoints.

Scheduler

This component is tasked with the role of scheduling pods into nodes. It takes all pods which are unscheduled and places them to the appropriate nodes. This procedure uses a scheduling algorithm during the binding of pods into nodes. This is a complex process which requires consideration of several interacting factors such as:

  • Resource requirements
  • Service requirements
  • Hardware/software policy constraints
  • Affinity and anti-affinity specifications
  • Data locality
  • Deadlines

Node Components

These are components which run on each and every node in order to maintain the running pods as well as the runtime environment of the Kubernetes. Some of these components are as discussed below:

Kubelet

This is the primary node agent. It runs on all nodes of the cluster ensuring that containers are still running in a pod. The main roles of Kubelet are:

  • It keeps a look on the pods that have been assigned to its node
  • Mounts the required volume to the pods
  • Download the pod secrets from the API server
  • Runs the container of a pod via the Docker or Rkt
  • It runs live probes of a container
  • It reports the status of the node and each and every node which might involve creating a ‘mirror pod’ if necessary
  • It reports back the status of a node back to the system

Kube-proxy

It provides an abstraction of the Kubernetes service by ensuring maintenance of the network rules on the host’s side. It also performs connection forwarding.

Container-Runtime

It is the software that has the responsibility for running containers. It provides support for several runtimes. These include Rkt, Docker among others.

  • Docker- It is used to actually run the container
  • Rkt- It serves as an alternative to the Docker
  • Supervisord- It is a lightweight process which oversees the whole system for keeping Docker and Kubelet running.
  • Fluentd- It is a daemon which is responsible for providing cluster-level-logging.

Addons

These are pods and services which are used to implement features of the cluster. Deployment and replication controllers are in charge of managing the pods. Creation and maintenance of the add-ons resources are managed by the Add-ons manager. Below are some of the details on selected addons.

  • DNS

DNS service is a crucial service of the Kubernetes which is scheduled just like a regular pod. Every service is given a DNS name which is very essential for automatic discovery.Cluster DNS is a requirement for all Kubernetes clusters. It acts as a DNS server which serves Kubernetes services with DNS records.

  • The user interface (Web UI/ Dashboard)

This Is a web-based UI which provides an overview of the clusters’ state. HTTP proxy or Kubernetes API provides access to the dashboard which helps users to troubleshoot and manage applications which are running in the cluster.

  • Container resource monitoring

It is used to record metrics on generic-time series about containers. This data is stored in the central database and the container resource monitoring provides a UI for accessing and browsing that data.

  • Cluster-level-logging

This mechanism is responsible for saving container logs into a central database and provide a UI which gives a way of accessing and browsing the data.

The Kubernetes API

The Kubernetes API acts as the system’s foundation which provides a declarative configuration schema. There is a command line tool known as Kubectl which is used to create, get, update or delete API objects. Kubernetes API conventions are aimed at simplifying client development and ensuring implementation of configuration mechanisms that can work consistently across a wide and diverse set of use cases.

Kubernetes API has a RESTful style in nature. Through the standard HTTP verbs such as PUT, POST, GET and DELETE, clients can be able to create, retrieve, delete or update data about an object. The queried data is returned in form of a JSON. Additionally, Kubernetes expose endpoints for which are non-standard and allows alternative content types. All JSON which has been accepted and returned from the server has a schema which is identified by two fields; kind and apiVersion. Below is a brief description of these fields:

  • Kind– This refers to the name of a specific object in a particular schema. The object can have different attributes and properties. For example, a goat and a rabbit would have different properties and attributes. Kinds are categorized into three groups:
  • Objects- This represents an entity which is persistent in the system.
  • Lists- This refers to a collection of resources which are of one or more kinds.
  • Simple- This type of kinds is used on an object with specific action as well as on entities which is non-persistent.
  • apiVersion- It refers to a set of resources which are exposed together as a group along with the version. For example, “work.k8.io/V1”

The resourceis used to depict a representation of an entity of the system which is sent or retrieved via HTTP from the server and presented in a JSON format. Each resource is designed to accept and return data of a single kind at each and every time of operation. Multiple resources which bear a reflection of specific use case can accept or return data of a single kind.

API groups consist of several resources bounded together where each and specific group can have one or more versions. These versions evolve independently and each version in a group can have one or more resources.

API changes

A successful system will always exhibit growth and it is associated with many changes. Therefore, Kubernetes API is expected to grow and continuously experience new changes.  These changes should always ensure compatibility with the current features and create a smooth transition.

Advantages of Kubernetes

Kubernetes offers a wide variety of benefits to users. Below is a discussion on the major benefits of using Kubernetes:

  • Velocity

This refers to the speed at which your system constantly updates and deploys in order to give new features to the users. Some days back, the addition of a new deployment or carrying out an update required the system to be taken down to facilitate time to perform such tasks. This usually led to downtime which kept the service unavailable to the users. Such tasks were normally performed on a weekend or at midnight. However, carrying out these changes during a downtime did not increase the velocity. The main goal is always to carry out the update while maintaining a 100% uptime to the users. Hence velocity is used to refer to the measure of the number of updates that can be performed per hour while maintaining total uptime throughout the whole process. In order to achieve this, Kubernetes has some core concepts which leads to high velocity. These components are declarative configuration, immutability, and self-healing system as discussed below.

  • Immutability

Kubernetes are built in a design which adheres to the immutable infrastructure. In this kind of infrastructure, an artifact which has already been created remains unchanged despite modifications from the user. Previously, the mutable infrastructure allowed changes of the top existing objects initiated by incremental updates. This kind of infrastructure was associated with a state of an artifact being an accumulation of incremental changes and updates rather than a state of a single artifact. A process for carrying out an update involved logging into a VM and downloading all software binaries of the whole application then kill the server and restart again. If something went wrong at any part of the process, there were no records of the number of updates had been deployed or a show of the exact point of error.

The immutable infrastructure allows carrying of an update by simply building a new container with a tag and deploy it instantly. This process kills the older container and replaces it with the new container. By doing this, there is always an artifact record which can easily show if an error happened during the process. In case of any errors, one can be able to roll back easily to the previous image.

 

  • Declarative configuration

In Kubernetes, the desired state of the system is represented as a declarative configuration of an object. The traditional system involved the use of imperative configuration whereby the system’s state was defined by a series of instructions which were to be executed rather than just giving the desired state of the system. Below is an example of both an imperative and declarative configuration.

A task which involves running three replicas of a piece of work can be expressed in the following ways:

Imperative configuration- “run J, run K, run L”

Declarative configuration- “replicas=3”

Declarative configuration is used in giving the exact state of the system and it is always error-free. This makes rollbacks extremely easy for Kubernetes which is usually impossible when handling imperative configuration.

  • Self –healing systems

As Kubernetes take actions which are aimed at matching the current state with the desired state, they also try to maintain the status of the current state based on the previous state. For example, if the current state has three items and one item is manually destroyed, the Kubernetes will roll back to the previous state and pick the missing item to match the desired state.

 

  • Scaling Services

Every system is associated with growth which requires scaling in order to meet and accommodate the new changes. Kubernetes is able to achieve scalability due to its favoritism towards decoupled architectures.

  • Decoupling

In this kind of architecture, components are separated from each other by service load balancers and defined API’s.  API’s are used to provide a buffer between the consumer and the implementer. On the other hand, load balancers act as a buffer between the instances of each running service. This makes scaling easier because it eliminates the need of doing adjustments or configurations of any layer of your service.

  • Scaling clusters and applications

The immutable and declarative nature of Kubernetes makes scaling fairly easy. The replica number in the declarative config can be changed as the need arises hence making it easy to set auto-scaling. Auto-scaling operates on the assumption of the existence of enough resources. If it happens there are not enough resources, one will be required to carry out the scaling by themselves. Kubernetes make this process easy by allowing the creation of a new machine which is then added to the existing cluster.

 

  • Abstraction of Infrastructure

Kubernetes provide a separation between the developer and the specific machines. Application of cloud architecture enables portability since the developers are able to consume a higher level of API which is implemented in terms that are specific to a certain cloud infrastructure APIs. This makes transferability of work by developer fairly easy. The process basically involves sending of the new declarative configuration to the new cluster. Kubernetes also have several plugins which are used to provide an abstraction on various cloud platforms.

 

  • Efficiency

In Kubernetes, several applications can be collocated on a single machine and run efficiently without interfering with each other. Hence, tasks from various and multiple users can be packed tightly in a few machines. This leads to greater efficiency as well as reducing the cost of machines since fewer machines are needed.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Chapter 2. Kubernetes-Core Concepts and Constructs

 

The Architecture

Kubernetes has an architecture which consists of the master and nodes. In this kind of architecture, the administrative interactions are usually done via the Kubectl script and/ or RESTful service call to the underlying API. The results are normally returned in JSON format.

Master

Master serves as the brain of the whole cluster. The core API is located here and it is responsible for maintaining the RESTful web services which are used to query and define the desired cluster and the workload state.Notably, the control panel makes an access to the master to initiate changes only and cannot access the nodes directly.

The master has a scheduler which is used together with the API server to be able to create schedules for workloads which are in pods form at the actual nodes. These pods are part of the containers which constitute the application stack. By default, the pods are spread by the Kubernetes scheduler across the cluster. This is followed by matching of pod replicas using different nodes.

There is a need to ensure there is always a correct number of pod replicas which are running at any specific time. In order to achieve this, API server works with the replication controller to accomplish this task. Finally, etcd is used as a storage location which stores the Kubernetes state. It allows the values stored there to be watched so that it can always store the updated value. In other words, this can be referred to as the shared memory.

Nodes

Each node consists of a couple of different components. The Kublet is responsible for interacting with the API server in order to carry out an update on the state. In addition, it starts new workloads which have been invoked or initiated by the scheduler. Kube proxy is a component which performs load balancing and channels traffic intended for a specific service to the right pod at the backend. There exist other default pods which are tasked with running various services associated with the node.

The core constructs

This a deeper exploration of the core abstraction which is used by the Kubernetes. This will enable someone to have a better understanding of Kubernetes application.

Pods

Pods allow related containers to be kept close to each other based on their network or hardware infrastructure. This allows data to reside near application hence the processing becomes faster because of the reduced latency. In addition, common data which is shared between a couple of containers can be stored in shared volumes.

Labels

These are key or value pairs which are attached to an object. Such objects include pods, services, and replication controllers. They are used as identifying attributes for such objects. They can be added to an object during creation time or they can be added or even modified at runtime.

Label Selector

These are used to select objects on the basis of their labels. Selectors which are equally-based are used in specifying a key value and a key name. This involves the use of two operators which are ‘’! =” and “=” or “==”. The former is used for inequalitywhile the latter is used for equality based on the value. Below are examples to show this can be used:

Role = web server

In this instance, all objects which match that key label and value will be selected.

Label selectors may have multiple requirements. This can be represented as follows by use of a comma for separation.

Role = webserver, application! = foo                          

Selectors which are set based have extended capabilities which allows selection based on multiple values:

Role in (webserver, backend)

Annotation

They allow an association between Kubernetes objects and arbitrary metadata. Kubernetes provides storage of the annotation and avails their metadata for easy access. Annotations are quite different from labels since they don’t have strict restrictions on the size and limit on a numberof characters. Such kind of metadata comes handy when dealing with complicated systems. In such a situation, Kubernetes makes it fairly easy by eliminating the need of having an individual to create their own metadata store or mapping of objects to their metadata.

Any system is bound to fail at some point during operation. This can be brought by several factors which include container and pods crashing or getting corrupted. Other factors could be human-initiatedefforts out of malice or ignorance. In order to handle such events in the right way, Kubernetes has service and replication controller constructs which help in containing such incidences. These constructs help applications to run with little or no interruptions. When an interruption occurs, the application is able to recover gracefully. Below are further details on these two constructs.

Services

Services are used to provide an abstraction between consumers and the applications. Access of pods running on a cluster is made easy by creating a reliable endpoint which can be used by other programs and users. In Kubernetes, this is made possible by the existence of a proxy which is known as Kube-proxy. Its main task is allowing communication between service endpoint and the pod where the actual application is running. Any request that is received by the service is channeled to the right and appropriate node. Below is an example showing how to create a service using an API request and passing some information:

Kind: Service

apiVersion: v1

metadata:

name: my-task

spec:

app: MyAppOne

ports:

-protocol: TCP

Port: 80

TargetPort: 9378

 

In this example, the new service is called “my-task” and has its target on TCP port 9378 on any pod which has a metadata label “app-MyAppOne”.

The service’s label selector is constantly evaluated by Kubernetes in order to establish the pods which are included in the service. Hence a new service can include pods which are already in existence provided the label selector matches.

Kubernetes provides support for strings “targetPorts” which facilitate the change of ports in the pods or applications. This allows each pod to have the capability of exposing a different pod provided there is a mapping to the commonly named pod. Hence this allows changing of port numbers without breaking the clients.

Using Services for External Workloads

A service can be used for external workload hence allowing for abstraction when accessing a database or backend that is running outside the Kubernetes. In order to this, the service needs to be defined without having a label selector. After the creation of the service, there needs to be a specification of the endpoints which belong to the external workload. This is well depicted in the example shown below:

Kind: Endpoints

apiVersion: V1

metadata:

name: my-App

subsets:

 address:

IP: 62 .84. 24. 195

ports:

-port:9376

All the traffic coming to “my-App” will be routed straight to the endpoint denoted by “62 .84. 24. 195: 9376

Service Types

There are three types of services as discussed below:

  • ClusterIP- It is the simplest service type which exposes a service’s ClusterIP address to the Kubernetes Cluster internally.
  • NodePort- It is responsible for exposing a service on a specific node to all other nodes in the Kubernetes cluster.
  • Loadbalancer- It is exposed the same as NodePort however it creates a load balancer in the cloud, a place where the Kubernetes is running. It is responsible for receiving external requests to a specific service.
  • ExternalName- It returns an alias to a component which resides outside the Kubernetes cluster. Any request which comes to the service is routed to the specified domain by the Kubernetes. Here is an example which is used to redirect traffic sent to “my-App” to “www.example.com”

Kind: service

apiVersion: v1

metadata:

name: my-App

namespace: default

spec:

type: ExternalName

ExternalName: www.example.com

 

Service Discovery

Environmental variables which are located on the nodes and DNS are used for service discovery in Kubernetes. The Kubernetes API is tasked with watching on the DNS server for new services. In addition, it is required to create DNS records for all services.Standard DNS name resolutions make it easy for pods to access services. If the cluster is using namespaces, then pods are required to qualify the namespace of the service. For e.g., “my-service” will be mentioned as “my-service.my-namespace”

Environmental variables are usually unreliable since a pod might fail to access a service that was created afterward. Kubernetes is responsible for exporting environment variables for each and every active service in Kubernetes cluster during the pod’s time of creation. These variables are taken to the nodes where the pods got created making them visible at their respective pods.

Replication Controllers

Their main role is to manage the number of nodes that a specific pod or included container runs on. They ensure that a specific number of copies is used when running an instance of an image. During operation of pods and containers, several needs arise. These include carrying out of updates, upward and downward scaling of the number of nodes that a pods or container’s image runs on. Replication controllers always ensure things are running correctly across the cluster and application. In other words, they are tasked with ensuring that your application is running with the desired scale. In addition, you can use the replication controller to launch more instances of your applications.

Kubernetes Concepts

In order to make good use of Kubernetes, there is always the need to have a deeper understanding of the different abstractions which are used to represent the state of the system. We have already looked at the core constructs of Kubernetes and below is an overview of key concepts which are used by Kubernetes.

  • Volume- This can be compared to a Dock’s container volume. In Kubernetes it refers to the whole pod which is mounted on all containers in a given pod. Kubernetes ensures the preservation of data across the container and the volume can only be removed when the pod has been destroyed. A pod has the capability of having multiple volumes.
  • Namespace- A virtual cluster involves a single physical cluster which is used to run other multiple clusters. It is normally intended for the environment which have more many users who are spread across multiple projects or teams. The main goal of having a virtual cluster is to provide isolation. A namespace can also be allocated a resource quota in avoidance of excess consumption shared resources belonging to the overall physical cluster.
  • Deployment- This refers to a yaml file which is used to describe the desired state or a replica set or a pod. The deployment controller is tasked with ensuring continuous creation and updating of replicas in pursuit of matching the current with the desired state. For instance, if a yaml file defines 3 replicas for a pod but the current state shows only 2 replicas, an extra one will be created in order to match the desired state. Replicas which use deployment for its management can only be manipulated by creating a new deployment but no via direct manipulation.

Kubernetes Design Principles

The main idea behind the design of Kubernetes was to support features which are in high demand by distributed systems. Such features include security, portability, auto-scaling and high availability. Below aremore details on these design principles.

  • Scalability

Based on the CPU utilization, Kubernetes have the capability for providing horizontal scaling of pods. CPU has a threshold which is configurable and if it is reached during operation, the Kubernetes will start new pods automatically. For instance, if the CPU threshold is 80% but the application grows to 200%, then Kubernetes will create three pods which after deployment will pull down the CPU threshold back to 80%. When there are multiple pods for a given application, Kubernetes performs load balancing across all of them. Horizontal scaling of stateful pods is also supported by Kubernetes. A stateful set is tasked with ensuring persistence and stability of storage even when the pod is destroyed.

  • High availability

Kubernetes ensures there is high availability at both infrastructure and application level. Replica sets always ensure the minimum number of replicas belonging to a stateless pod of a given application are running. Kubernetes offers support of various storage backend at the infrastructure level. Some of these back ends include Azure Disk, AWS EBS, Google Persistent Disk, NFS and many more. Kubernetes have an added layer which is available and reliable hence offering high availability of the stateful workloads. Higher availability can be achieved by creating a configuration of a master node to exhibit multi-node configuration.

  • Security

Kubernetes ensures enforcement of security measures at all multiple levels. These levels include application, cluster, and network. Transport Layer Security (TLS)is used to ensure API endpoints are secured. Cluster operations are limited to authenticated users only. At the application level, there exist Kubernetes secrets which are used to store information considered to be sensitive. Such information includes passwords and tokens. Secrets are available for access by any pod provided they all belong to the same cluster. During deployment, there is a need to have a network policy which is used to specify communication between pods and the endpoints.

  • Portability

This design principle is exhibited vividly by Kubernetes in terms of the choice of operating system, processor architecture, cloud providers and new container runtimes. Any mainstream of Linux distribution can be used to run a cluster. The processor architecture can be either bare metal or virtual machine. Different cloud service providers can be used by Kubernetes without having any challenges. These kinds of cloud providers include Azure, AWS or Google Cloud. Additionally, by using the concept of federation, Kubernetes support workloads which can be distributed across hybrid or multi-cloud environment. The cloud environment can either be private or public. This also supports fault tolerance and creates an availability zone within a single cloud provider.

 

A sample installation and setup of a Kubernetes Application

In this example, it assumed that all components are installed inside a single Docker container which acts as both the master and work node. This example is aimed at providing guidance on how to get started with Kubernetes:

Installing Kubernetes

  1. Set the K8S_VERSION env variable to the newest stable Kubernetes unharnesses, for later retrieval:

Export K8S_VERSION=$(curl -sS https://storage.googleapis.com/kubernetes-release/release/stable.txt)

  1. assumption of the host’s design is amd64, set the ARCH env variable:

export ARCH=amd64

  1. Run the hypercube longshoreman instrumentation, that itself takes care of putting in all the Kubernetes elements.

It requires special privileges, which are explained below.

Docker run -d –volume=/:/rootfs:ro \

–volume=/sys:/sys:rw –volume=/var/lib/Docker/:/var/lib/docker:rw \

–volume=/var/lib/kubelet/:/var/lib/kubelet:rw –volume=/var/run:/var/run:rw \

–net=host –pid=host –name=hyperkube-installer \

–privileged gcr.io/google_containers/hyperkube-$: $\

/hyperkube kubelet –containerized \

–hostname-override=127.0.0.1 –api-servers=http://localhost:8080 \

–config=/etc/kubernetes/manifests –allow-privileged –v=2

  1. Run the command Dockerps to see all the running containers started by hypercube, for example a container created with the command “/hyperkube apiserver”.The volume parameters are required to mount and give access to the host’s /root,/sys,/var/run and /var/lib/Dockerfilesystems inside the container instance.

Theprivileged possibility grants access to all or any devices of the host, particularly to begin new containers. Parameters –net=host and –pid=host enable access to the network and namespace of the host.

hypercube’s Docker image is available from Google’s Container Registry (GCR), we use ARCH and K8S_VERSION env variables to construct the full

path to the image that fits our environment.

gcr.io/google_containers/hyperkube-$: $

Deploying Pods

  1. begin a bash shell within the hypercube container:

Docker exec -it hyperkube-installer /bin/bash

  1. Export the Kubernetes version and processor design within the container:

exportK8S_VERSION=$(curl-sShttps://storage.googleapis.com/kubernetes-release/release/stable.txt)

export ARCH=amd64

  1. transfer the kubectl program line tool into /usr/bin/kubectl and create it executable:

curl-SSL”HTTP://storage.googleapis.com/Kubernetes-release/release/$K8S_VERSION/bin/linux/$ARCH/kubectl” > /usr/bin/kubectl

chmod +x /usr/bin/kubectl

  1. currently you’ll run kubectl commands to retrieve data on Kubernetes state:

kubectl get pods

kubectl get namespaces

  1. begin readying of a sample nginx pod and exit the container:

kubectl run nginx –image=nginx –port=80 ; exit6. Run the command Dockerps to see the new nginx containers running on the host.

  1. Declare the nginx pod readying as a service and map port eighty of the nginx service to port 8080 on the host:

Docker exec -it hyperkube-installer /bin/bash

kubectl expose deployment nginx –port=8080 –target-port=80

  1. ensure the nginx service is prepared and assigned a scientific discipline, and store it in a very variable:

kubectl get service nginx

ip=$(kubectl get svc nginx –template=}

  1. Check the nginx welcome page is there via a browser or downloading it with curl:

curl HTTP://$ip:8080

Health Checks

Kubernetes have two layers which perform health checking. The first one involves the use of HTTP or TCP checks whereby K8s tries to establish a connection to a specific endpoint and it returns the health status when the connection is successful. The second one involves the use of command line scripts to perform the health checks.

 

 

 

 

 

 

Chapter 3. KubernetesServices, Load Balancing, and Networking

 

Kubernetes Networking

A Kubernetes cluster is made up of various pods and nodes. There is a need to understand how communication takes place in a cluster. This leads to study of a Kubernetes networking model which its capability offers support to open source implementations of different types. Each pod is provided with an IP address by the Kubernetes. This eliminates the need for mapping the host ports to container ports. This was a requirement in the Docker networking model. In the Kubernetes networking model, pods are treated more like VMs or like a physical host based on the mode of naming, load balancing, port allocation, and application configuration. This kind of networking aims at addressing the following challenges:

  • Container-to-container communications which are highly coupled.
  • Pod-to-pod communications
  • Pod-to-service communications
  • External-to-service communications

The following fundamental requirements are imposed by Kubernetes during a network implementation.

  • Communication between all containers can take place without NAT
  • Node-to- container communications can take place without NAT
  • The IP that a container sees it haves is the same as the one that all the others see

 

In a nutshell, this means that in order to implement a Kubernetes networking model, there is the need to ensure that all requirements have been stipulated above have been met.

Kubernetes Vs Docker Networking Model

The Docker networking model relies on a virtual network known as Docker0. Every host has a private network whereby containers are attached to each other and given a private IP address. This means that containers which are running on different machines are unable to communicate with each other. Cross communication among various nodes in the Docker model requires mapping of host ports to container ports and channeling of the traffic. At this instance, the Docker is tasked with avoiding port clashes between containers.

The Kubernetes model provides native support for multi-host networking which allows communication between pods regardless of where they reside. Kubernetes does not provide an implementation of this model but it relies on third-party tools.

Kubernetes Networking Model Implementations

As noted earlier, Kubernetes does not provide an implementation of this kind of a networking model but it relies on third-party tools. Below is a discussion on the various implementation options which are used nowadays:

  • Flannel– This depicts a simple overlay network which meets all the Kubernetes requirements. This is achieved by running allocation of a subnet lease on each host. The subnet lease is chosen from a wide space containing preconfigured addresses. The flat network created by flannel runs above the host network.
  • Project Calico- It is responsible for the provision of a network which is highly scalable as well as a network policy which offers a solution for connecting pods. This type of connection is based on IP networking principles which are similar to those of the internet. Deployment of calico does not require overlays or encapsulation. This results in a data center which possesses high performance and has high data scalability.
  • Weave Net- This refers to the creation of a highly resilient and simple network by use of a cloud networking toolkit. This kind of a network does not require any configuration. Additionally, it provides functionalities such as service discovery, scaling, security networking and performance which is complexity free.

There are other unpopular options such as Cilium, Cisco ACI, Kube-router, Romana, Nuage, Contrail, Contiv, VMWare NSX-T among others. Some tools even provide support of multiple implementations. Such tools include Multus and Huawei CNI-Genie.

How Pods Communicate with Each Other?

Each pod has a unique IP address which is chosen from the flat address space within the Kubernetes cluster. As a result of this, there exist pod-to-pod direct communications which are supported without the need of using a proxy or carrying out address translation. This also supports the use of standard ports for most applications since the need to route traffic is eliminated. One challenge which can rise up is port conflicts among containers. This can be caused by the fact all containers belonging to a single pod share the same IP address. This eliminates the possibility of container-private ports. However, pods are designed to run as a single service similar to a VM design in which the occurrence of such conflicts are minimal and rare.

How Pods Communicate with Services?

Kubernetes services provide the capability of grouping pods which share a common access policy. The service is allocated a virtual IP address which is used to facilitate communication with pods which reside outside the Kubernetes Cluster. Requests which are made by the outside pods are proxied to the pods inside the service by use of a Kube-proxy. There are several modes of proxy which are discussed below:

  • Iptables:

Installation of tables by Kube-proxy allows access to service IP addresses as well as redirecting them to the right pods.

  • Userspace: This mode involves opening of a port at the local node whereby its requests get proxied to another service’s pods.
  • IPVs- This involves the creation of IPV rules which are regularly synchronized with endpoints of the API.

Incoming Traffic from the Outside World

By default, there exists a firewall which resides between the internet and the nodes located in Kubernetes cluster. Hence the service IP address is only reachable and targetable within a cluster network. There is a need to map a service IP to the external IP in order to allow the flow of incoming traffic from the outside of a cluster. Any requests which arrive at the external IP address gets routed to a node residing within the cluster. This is followed by forwarding of the request to the appropriate node by checking on the service which is mapped to the external IP and eventually knowing which pods belong to that service in particular.

In more complex policies on incoming traffic, Kubernetes provide an Ingress API which offers reachability of external URLs. Additionally, it provides traffic load balancing, name-based virtual hosting as well as SSL termination to services. An ingress depicts a collection of rules which allow inbound traffic to reach the cluster service. In order to use ingress, an ingress controller must be configured and deployed for the cluster. This can be done automatically or manually depending onthe cloud provider you are using for the Kubernetes.

A simple ingress specification is as shown below:

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

  name: my-ingress

spec:

  backend:

serviceName: my-App

servicePort: 60

When this specification is being processed, the ingress controller allocates an external IP which satisfies “my-ingress” rules. All requests which arrive at this IP are forwarded to the “my-App:60”.

Below is an example of a slightly more complex example which uses a simple load balancing.

apiVersion: extensions/v1beta1

kind: Ingress

metadata:

  name: my-ingress

  annotations:

    ingress.kubernetes.io/rewrite-target: /

spec:

  rules:

  – host: foo.bar.uk

    http:

      paths:

      – path: /foo

        backend:

serviceName: my-App-1

servicePort: 60

      – path: /bar

        backend:

serviceName: my-App-2

servicePort: 60

All requests which are sent to “foo.bar.uk/foo” are routed to “my-App1:60”. On the other hand, all requests sent to “foo.bar.uk/bar” get routed to “my-App-2:60“.This routing is facilitated by the use of a load balancing strategy.

DNS for Services and Pods

Kubernetes has its own internal DNS which is used for domain name resolution within the cluster in order to allow communication between pods. DNS implementation by Kubernetes requires the use of a regular service which is responsible for performing the name resolution. It also does the configuration on individual containers enabling them to make contact to the DNS regularly in order to carry out domain names resolution. Notably, the internal DNS is compatible with the cloud provider’s DNS Service.

Every service is assigned a DNS name that resolves the IP Cluster of the service. The convention used during the naming process must include the namespace and the service name. This is as shown below:

my-service.my-namespace.svc. cluster. local

A pod which resides in the same namespace as the service would do not really need to have the name. In the example shown above, a pod in the same namespace as the noted service can perform a DNS query simply by querying for “my-service”. A pod outside the cluster may have to make a query as follows:

my-service.my-namespace

Network Policies

By default, pods are bound to accept traffic from any pod which resides in the same cluster. A network policy is used to provide restrictions on how communication takes place between a group of pods and other endpoints of the network. Labels are used by a network policy to carry out a selection of pods which define rules governing the flow of traffic in and out of those pods. Below is an example to show how this happens:

apiVersion: networking.k8s.io/v1

kind: network policy

metadata:

  name: my-network-policy

  namespace: default

spec:

  podSelector:

    matchLabels:

      role: ab

  policyTypes:

  – Ingress

  – Egress

  ingress:

  – from:

    – ipBlock:

        cidr: 172.17.10.0/16

        except:

        – 172.17.11.0/24

    – namespaceSelector:

        matchLabels:

          project: my-project

    – podSelector:

        matchLabels:

          role: frontend

    ports:

    – protocol: TCP

      port: 8080

  egress:

  – to:

    – ipBlock:

        cidr: 10.10.0.0/24

    ports:

    – protocol: TCP

      port: 5968

podSelector- This is used to specify the group of pods where the network policy should be applied. If it was empty, all pods in the namespace could have been selected. In this particular example, the pods which were selected include only those which were labeled “role: ab”.

The ingress rules in this example provide specifications that the selected pods can only receive TCP traffic on port “8080” in case the origin is from any of these sources:

  • IP addresses in CIDR 172.17.10.0/16 but not in CIDR 172.17.11.0/24
  • any pod in the namespace my-project
  • any pod in the namespace default with label role: frontend

The Egress rules during this example specify that affected pods will solely send protocol traffic to port “5968” of information science addresses in “CIDR ten.10.0.0/24”

Network Extensions

Network extensions refer to the ways of enhancing a network through the introduction of additional functionalities such as network policies and cross-node networking. There are two types of network plugins or extensions:

  • CNI plugin– This plugin is designed for interoperability. It plays a huge role in the implementation of Container Network Interface.
  • Kubernetes plugin– This plugin is used for setting up communication rules between various nodes. This is achieved with the help of a cloud provider. It works only in Linux operating system.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Chapter 4. Kubernetes and Container Operations

 

Kubernetes is regarded as a platform used for the creation, deployment, and management of distributed applications. These applications exist in many different sizes and shapes which consist of one or more applications which run on individual machines. These applications are tasked with accepting input, manipulating data and returning the generated results. In order to understand how a distributed system is built, there is a need to understand the building of a container image. A collection of containers leads to the creation of a distributed system. Hence this chapter aims at providing more details about containers and applicable applications.

Containers

Containers refer to methods of virtualization which packages codes, dependencies and configurations of an application into building blocks aiming at achieving version control, efficiency, consistency, and productivity. The operating system installed on the server is shared by all containers. They all run as resource-isolated processes in order to allow consistent, reliable and quick deployments irrespective of the environment. This allows software to run correctly even if it is moved from one environment to another.

Container image

This refers to a piece of software which is self-contained having its own code, resources, and tools needed to run. Using Dockerfiles, it is very easy to create and modify container images. There are two ways of obtaining a container image which includes the creation of the file from the local file system or downloading a pre-existing file from a container registry. After obtaining the container image, one can be able to run it and produce an application which is running inside the Operating System of the container.

Docker Image Format

This is the most popular container image format which was developed by the Docker open source project. Its main idea is to package, distribute and run containers by use of a Docker command. This is the widely used format in container operations. Below is a look at the whole process of creating a container image.

Building Application Images with Docker

Creation of a Docker container image is automated by use of a Dockerfile. The following is an example describing the process of building a kuard. A kuard is a term used to refer a Kubernetes which is up and running.

FROM alpine

MAINTAINER Kelsey Hightower <kelsey.hightower@kuar.io>

COPY bin/kuard /kuard

ENTRYPOINT [“/kuard”]

This text is then stored in a text file named Dockerfile which is later used to create a Docker image. In order to achieve this, one is supposed to run the command illustrated below:

$ docker build -t kuard-amd64: 1.

This results in a Docker image which is approximately 6 MB and resides within the local Docker registry. The image is only accessible to a single machine. However, Docker allows sharing of images across multiple machines which broadens the Docker community.

Image Security

There is a need to follow all right practices when building container images which will run in a Kubernetes cluster. One of these practices includes avoidance of password inclusion at any layer during the building process. One of the dangers associated with container layers is that deletion of a file on one layer does not remove it from preceding layers. This means that the file can still be accessed by attackers using some specials tools.

Optimizing image sizes

As people continue to interact with container images, there are some operations which might lead to overly large images. For instance, when a file is removed from subsequent layers it is still present in the images. They only become inaccessible.

Storing Images in a Remote Registry

Kubernetes relies on the capability of having images available across all machines in a given cluster. This process involves the use of a container image registry service. This is a service which enables storage of container images and is hosted either as a public or private registry or by a third party. One of the processes used to achieve a distribution of these image files includes exportation of the kuard image then import it to each and every machine within the cluster. This tends to be a tedious process.

Docker community has its standard which requires Docker images to be stored in a remote registry. Docker registries come with a ton of options which one can choose from depending on various needs and requirements. These might include consideration of security and future collaboration features.

One of the choices includes deciding on whether the registry will be private or public. A public registry allows downloads from anyone while a private registry requires authentication before downloading any image. Public registries are useful when one wants to share images with the whole world. One is able to distribute software and be assured that it has reached many users and they feel the exact experience. On the other hand, the private registry is useful when storing applications which are private and do not require to be used by other people across the world.

Regardless of the option, you are using, one is required to authenticate to the registry when pushing an image. This can be done by generally using the Docker login command. However, this may vary depending on the registries. Once the image has been pushed, it becomes available on a remote registry and ready for deployment when using Docker.

The Docker Container Runtime

Although Kubernetes have an API which is used to describe an application deployment, it relies on a container runtime to enable them set up an application container. This process involves the use of native API’s which are container-specific in order to meet the requirements of the target OS. Kubernetes use Docker’s default runtime which provides an API which is responsible for container applications on both Windows and Linux systems.

Running Containers with Docker

Deployment of containers is made easy by use of a Docker CLI command. At first, this command initiates the kuard database and maps ports 8080 between your local machine and the container. This is necessary in order to allow access to the local machine.

Exploring the kuard Application

When a kuard is executed, a simple web interface is exposed. This can be accessed by pointing to the browser at this address:

http://localhost:8080

Limiting Resource Usage

This is made possible by use of Docker which provides exposure of the underlying c technology in the Linux kernel in order to limit the amount of resource used by applications.

Limiting memory resources

Among the major benefits associated with running containerized applications is the ability to provide restriction of resource utilization. This allows the existence of multiple applications to run on similar hardware with fair usage of resources.

Limiting CPU resources

This is a critical resource on a computer whereby its utilization can be used restricted using Docker run command with the CPU shares flag.

Clean up

Once an image has been built, deletion can be done using the Docker rml command. This can be done either via their tag name or via their image ID. Notably, unless an explicit deletion of an image is carried out, it will exist in the system forever. In addition, building a new image with the same ID as an old image does not remove the old image but it continues to exist by only moving the tag to the new image. Using Docker images command one is able to see all images that are in your machine at any particular time. Tags which are no longer in use can be deleted. Another approach which is a bit complex involves the use of cron job which acts as an image garbage collector. For instance, the docker –gc tool is widely used to perform image garbage collection because it can easily run a recurring cron job.

Container Environment Variables

This refers to the resources which are available to containers in the container environment.

Container environment

This kind of environment is responsible for providing several resources which are important to the containers. These resources include:

  • A file system- This consists of a combination of one or more volumes and an image
  • Information describing the container itself
  • Information describing other objects within a cluster

Container information

A container has a hostname which refers to the name of the pod within which the container is running. The hostname can be obtained by using the hostname command or using the gethostname function when using libc.

The name of the Pod and namespace are made available using downward API. Additionally, the container has user-defined environment variables which are derived from the Pod definition. There are the only statically specified variables within the Docker image.

Cluster Information

This depicts all lists of services which were running during the creation of a container. This information is made available to the container as an environment variable.

Runtime Class

This refers to an alpha feature which is used for container runtime configuration selection which will be used to run containers of a pod. This can be set up as discussed below:

  • Runtime Class feature gate has to be enabled- This has to be enabled on both the Kubelets and API servers
  • Installation of Runtime Class CRD- The CRD can be found in the directory of Addons and this command below can be used during installation.

Install the CRD with kubectl apply -f runtimeclass_crd.yaml

  • A configuration of the CRI implementation on the nodes- these configurations are runtime dependent.
  • Creation of the responding Runtime Class resources- Each configuration which has been set up in the previous step should have a RuntimeHandler name which is used for identity. For each RuntimeHandler a corresponding RuntimeClass Object is created.

Usage

After RuntimeClasses have been configured for a given cluster, running them becomes easy. One is only required to specify a RuntimeClassName as shown below:

apiVersion: v1

kind: Pod

metadata:

name: mypod

spec:

runtimeClassName: myclass

The Kubernetes is instructed to use the named RuntimeClass. If the specified RuntimeClass does not exist, or the CRI fails to run the corresponding Handler, the pod will enter the unsuccessful terminal phase and the process will be considered to have failed.

 

Container Lifecycle hooks

This section tends to explain how containers managed by Kubelets can use the Container Lifecycle hook framework to execute code which has been triggered by events in the course of management lifecycle.

As noted in several programming languages such as Angular which have lifecycle hooks, Kubernetes facilitate the provision of containers with lifecycle hooks. One of the major roles of the hooks is to make the containers to be aware of events happening in their management lifecycle. Consequently, this helps in running the code which has been implemented in a handler after the corresponding lifecycle hook was executed.

Container hooks

There are two hooks which are exposed to containers namely:

  • PostStart- After completion of a Container creation process, this hook is executed immediately. During this process, there no parameters which are passed to the handler.
  • PreStop- Before termination of a container, this hook is executed. This hook is blocking hence it is synchronous. Therefore, its execution has to be completed before calling the function responsible for deleting a Container. Additionally, there are no parameters which are passed to the handler.

Hook Handler Implementation

Access to a hook by Container is achieved through the registration and implementation of a handler associated to that hook. Hook handlers exist in two types in which they can be implemented for containers. These are:

  • Exec- It is used for execution of commands such as pre-stop.sh within the namespaces and cgroups of the Container. Any resources which could have been consumed by the command are counted against the Container.
  • HTTP- It is responsible for executing an HTTP request against a specific endpoint within the Container.

Hook Handler Execution

A function call on a Container lifecycle management hook Triggers the Kubernetes management system to execute the handler within the Container that is registered for that specific hook.

Hook delivery Guarantees

Hook delivery is intended to occur at least once. This means that a hook might receive many calls for any given event either PostStart or PreStop. Hence it is the responsibility of the hook to ensure the implementation has been handled correctly.

Debugging Hook handlers

A hook handler does not expose the logs in pod events. If there is a failure in the handler, an event is broadcasted.  For a PostStat, there is FailedPostStartHook event, and or for a PreStop, there is the FailedPreStopHookevent.These events can be accessed by using the following command.

kubectl describe pod <pod_name>

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Chapter 5. Integrating Storage Solutions and Kubernetes

 

Containerized architectures lead to large complexity which is associated with the immutable, decoupled and declarative application development. In addition, complexity comes as a result of data gravity. Most of the containerized applications are usually built through adaptation of existing systems which are then deployed onto VMs. Such systems likely include data which involves importation and migration. Lastly, there has been an evolution towards the cloud computing which directly infers that storage is regarded as an external cloud service. Hence the storage cannot exist within a Kubernetes cluster.

This chapter aims at covering the various approaches which are used for the integration of storage into containerized services in Kubernetes. The initial process will involve understanding how external storage solutions are imported into Kubernetes. This external solution may include cloud services or storages running on VMs. Secondly, this chapter will explore how singletons inside Kubernetes are executed so that they can match the VMs where the storage solutions have been deployed. Lastly, this chapter focuses on the StatefulSets which represent the future in Kubernetes for Stateful workloads.

Importing External Services

In your network, there exists a machine that contains some sort of database running on it. In such a scenario, one may not be necessarily required to move the database into containers and Kubernetes. Such a legacy server has a variety of advantages such as in-built service discovery and naming primitives which are provided by Kubernetes. Most importantly, this allows one to configure all applications which makes it look like the database resides in the local machine. This makes it trivial to carry out a replacement with a database which is a Kubernetes service. For instance, in a production stage, one may rely on the legacy database that is running on a machine but during continuous testing stage, one may deploy a test database as a transient container. In such a case, the test database is can be created and destroyed after each test has been run. This method of representation which has both Kubernetes and databases services enable the maintenance of identical configurations during the production and testing phases. This leads to high fidelity between the two phases which result in a successful deployment in production. In order to achieve this kind of fidelity, all Kubernetes objects are deployed into namespaces. The following object shows how a test service is imported:

kind: Service

metadata:

 name: my database

 # note ‘test’ namespace here   

The production service looks as shown below:

kind: Service

metadata:

 name: my database

 # note ‘prod’ namespace here

 namespace: prod

When you deploy a Pod into the test namespace and it looks up the service named my database, it will receive a pointer to my-database.test.svc.cluster.internal, which in turn points to the test database. In contrast, when a Pod deployed in the prod namespace looks up the same name (my database) it will receive a pointer to my-database.prod.svc.cluster.internal, which is the production database. Thus, the same service name in two different namespaces resolves to two different services. For more details on how this works.

Services without selectors

External services do not require label query. However, they only require a DNS name which is used to point to a specific server that is running the database. For instance, if the name of the server is database.mycompany.com. To carry out importation of this external database into the Kubernetes service requires one to start a service without a Pod selector. This service provides some reference to the DNS name of the database server. This is as shown below:

 kind: Service

apiVersion: v1

metadata:

 name: external-database

spec:

 type: ExternalName

externalName: “database.mycompany.co

Limitation of External Services: Health Checking

One of the major limitation associated with external services in Kubernetes is failing to provide a health checking mechanism. Hence the user is tasked with ensuring that the endpoint or a DNS name that has been supplied to Kubernetes is reliable and necessary for the application.

Running Reliable Singletons

Running solutions which have been stored in the Kubernetes is faced with several challenges such as the expectation of them being identical and replaceable by some Kubernetes primitives. One of the solutions to this problem is by running a single Pod which runs the database or any other storage solution. This prevents replication.

Kubernetes-Native Storage with StatefulSets

At first, when Kubernetes were being developed, there was a need for homogeneity on all replicas of a given replicated set. Additionally, there was no replica which has unique and identity or configuration. The developer was responsible for determining the design which could establish an identity for an application. Despite this approach having many benefits such as isolation and system orchestration, it makes it difficult to develop Stateful applications. As a result of the great input from the community and great deals of experimentation, Stateful applications were born.

Properties of StatefulSets

These refer to a group of Pods which are replicated and are similar to Replica Sets. However, unlike the Replica Sets, StatefulSets have the following characteristics:

  • Each and every replica has a persistent hostname which has a unique index
  • Creation of replicas happens in order from the lowest to the highest. The creation process is blocked until the Pod which is at the previous index is available and healthy.
  • Deletion is executed from the highest index going downward. This also applies to downscaling.

Persistent Volumes and StatefulSets

Persistence storage requires the mounting of a persistent volume into the /data/db directory. This is as shown below:

volumeMounts: – name: database mountPath: /data/db

This approach is similar to the one witnessed with reliable singletons. This is because the StatefulSet replicates more than one pod hence making it difficult to reference a persistent volume claim. In order to solve this, a persistent volume claim template is required. This kind of a template is similar to Pod template but instead of creating pods it is tasked with the creation of volume claims. In order to achieve this, the following code is added at the bottom of a StatefulSets definition:

volumeClaimTemplates:

 – metadata:

 name: database

 annotations:

 volume.alpha.kubernetes.io/storage-class: anything

 spec:

accessModes: [ “ReadWriteOnce” ]

 resources:

 requests:

 storage: 100Gi  

After each successful addition of a volume claim template, a Pod is created by the StatefulSets controller. This Pod becomes part of the StatefulSets which later on creates a persistent volume claim based on that template that is part of that Pod.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Chapter 6. Deploying Real-World Applications

 

The previous chapters have explored deeply about what are Kubernetes and all API objects which are present in Kubernetes clusters and how they can be used to construct reliable distributed systems. This chapter aims at discussing how one can use these objects and create a real-world application. Some of these applications include:

  • Parse which is an open source API server used in mobile phones applications
  • Ghost which is a platform used for blogging and content management
  • Redis which is a performance and lightweight key or value store

The information provided on these real-world applications will equip you with knowledge on how to structure and deploy your own application using Kubernetes.

Parse

Parse server is a cloud-based API which is dedicated to providing mobile application storage solutions which are easy to use. This is achieved by the provision of a wide variety of client libraries which make it easy to integrate with Android, iOS among other mobile platforms. In 2013, Parse was bought by Facebook and later shut down. However, another core server was opened by the core team of Parser and it is available for use. Below is a step-by-step guideline on how to set up Parse in Kubernetes.

Prerequisites

The parser uses a cluster of MongoDB for its storage. This process assumes one has three-replica of Mongo Cluster which is running in the Kubernetes with the names:

mongo-0. mongo, mongo-1. mongo, and mongo-2. Mongo

It is also assumed that one has docker login. Lastly, it is assumed that one has a deployed Kubernetes cluster and the Kubectl tool is properly configured.

Building the parse-server

As an open source, the parse-server comes with a Dockerfile by default in order to make containerization easy. The steps followed when building a parser are as follows:

  • Cloning of the Parse repository

This is achieved by running the following command:

$ git clone https://github.com/ParsePlatform/parse-server

  • Navigating to the directory in order to build the image:

$ cd parse-server

$ docker build -t ${DOCKER_USER}/parse-server

  • Pushing of the image up to the Docker hub
  • $ docker push ${DOCKER_USER}/parse-server

Deploying the Parse server

After the container image is built, deployment of the parse becomes fairly easy and straight forward. Parse looks for the following environmental variables during the configuration.

  • APPLICATION_ID

This the identifier which is responsible for authorizing your application

  • MASTER_KEY

This is the identifier that is tasked with authorizing the master or root user

  • DATABASE_URI

This refers to the URI for the MongoDB cluster

A combination of all these information, a successful Parse can be deployed using the YAML file shown in the example below:

apiVersion: extensions/v1beta1

kind: Deployment

metadata:

 name: parse-server

 namespace: default  spec:

 replicas: 1

 template:

 metadata:

 labels:

 run: parse-server

 spec:

 containers:

 – name: parse-server

 image: ${DOCKER_USER}/parse-server

env:

 – name: DATABASE_URI

 value: “MongoDB://mongo-0.mongo:27017,\

 mongo-1.mongo:27017,mongo-2.mongo\

 :27017/dev?replicaSet=rs0″

 – name: APP_ID

 value: my-app-id

 – name: MASTER_KEY

 value: my-master-key

 

Testing Parse

In order to ensure that the deployed Parse is working well, one needs to expose it as a Kubernetes service. This can be done using the service depicted by the sample code shown below:

apiVersion: v1

kind: Service

metadata:

name: parse-server

namespace: default

spec:

ports:

– port: 1337

protocol: TCP

target port: 1337

selector:

run: parse-server

As per now, the Parse server is well configured and its up and running. It can now be able to receive requests from mobile applications.

Ghost

Ghost is one of the most popular and widely used blogging engines that has a clean interface which is written in JavaScript. It either uses SQLite database which is file-based or MySQL for data storage purposes.

Configuring Ghost

Configuration of Ghost involves use a simple JavaScript file which describes the server. This file is stored as a configuration map. A simple file for developing a configuration for Ghost is as shown below:

var path = require(‘path’),

config;

config = {

 development: {

 url: ‘http://localhost:2368’,

 database: {

 client: ‘sqlite3’,

 connection: {

 filename: path.join(process.env.GHOST_CONTENT,

 ‘/data/ghost-dev.db’)

 },

 debug: false

 },

 server: {

 host: ‘0.0.0.0’,

 port: ‘2368’

 },

 paths: {

contentPath: path.join(process.env.GHOST_CONTENT, ‘/’)

 }

 }

};

module.exports = config;

 

This configuration is then saved to config, js which is then used for creating a Kubernetes ConfigMap object by use of the following command:

$ kubectl apply cm –from-file ghost-config.js ghost-config

This results to a ConfigMap which has ghost-config as its name. As seen in the Parse example, this configuration file will be mounted as a volume inside the container. This is followed by deployment of the Ghost as a Deployment object. This provides a definition of the volume as part of the template of that Pod. This is as shown in the YAML file below:

apiVersion: extensions/v1beta1

kind: Deployment

metadata:

 name: ghost  spec:

 replicas: 1

 selector:

 matchLabels:

 run: ghost

 template:

 metadata:

 labels:

 run: ghost

 spec:

 containers:

 – image: ghost

 name: ghost

 command:

 – sh

 – -c

 – cp /ghost-config/config.js /var/lib/ghost/config.js

&& /entrypoint.sh npm start

volumeMounts:

 – mountPath: /ghost-config

 name: config

 volumes:

 – name: config

configMap:

defaultMode: 420

 name: ghost-config

The above file can be run using the following commands:

$ kubectl apply -f ghost.yaml

After the Pod is up and running, it can be exposed as service by using the following command:

$ kubectl expose deployments ghost –port=2368

The Ghost server can now be accessed by using the following kubectl proxy command:

$ kubectl proxy

Ghost + MySQL

The above example is not reliable or even scalable because the blog contents are stored are only in the local file within the container. In order to achieve scalability, a different approach is used. This approach involves the use of a MySQL database to store the blog’s data. This is achieved by use carrying out modification of the config.js file as shown below:

database: {

 client: ‘mysql’,

 connection: {

host : ‘mysql’,

user : ‘root’,

password : ‘root’,

database : ‘ghost_db’,

charset : ‘utf8’

 }

 },

The next step involves the creation of a ghost-configConfigMap object using the following command:

$ kubectl create configmap ghost-config-mysql –from-file config.js

After this, the ghost Deployment is updated where the name of the  ConfigMap is mounted from config-map to config-map-mysql:

– configMap:

 name: ghost-config-mysql

This is followed by deployment of a MySQL server in the Kubernetes cluster while ensuring the service is named mysql. After this, one is required to create a database in the MySQL database using the following commands:

$ kubectl exec -it mysql– mysql -u root -p

Enter password

Welcome to the MySQL monitor. Commands end with; or \g.

mysql> create database ghost_db;

Finally, the new configuration needs to be configured using the command shown below:

$ kubectl apply -f ghost.yaml

The resulting Ghost server is decoupled from its database and one can be able to scale up while the server continues to share the data across all the available replicas. For instance:

Edit ghost. yaml to set spec.replicas to 4, then run:

$ kubectl apply -f ghost.yaml This results to a host server which is scaled up to four replicas.

Redis

This is a popular in-memory store for keys and values with a variety of additional features. Redis presents a good example of a Kubernetes Pod Abstraction. This is due to the fact that a working Redis application consists of two programs which are working together. The first one includes a Redis-server which is used for the key/value storage implementation. The other program is the Redis-sentinel that is responsible for implementing health checking and failover for a Redis cluster which has been replicated.

Deployment of a Redis in a replicated manner results into a single master server which can be used to perform both read and write functions. In addition, there are replicated servers which are responsible for the duplication of data which is written to the master. This leads to several benefits which include read operations for load balancing.

Configuring Redis

This procedure uses ConfigMaps to carry out a configuration of Redis installation. This kind of installation requires configuration of the slave and master replicas to be different. The configuration of the master can be achieved by the creation of a file named master.conf  which will contain the code sample shown below:

bind 0.0.0.0

port 6379

dir /Redis-data

This gives a direction to perform the binding of all network interfaces on port 6379 and then store its files on this directory (/Redis-data)

The slave configuration file is almost similar but additionally, it contains a single slave of the directive. The initial step will include the creation of the file named slave.conf which contains the following lines of codes:

bind 0.0.0.0

port 6379

dir. slave of Redis-0.redis 6379

The other step involves configuration of the Redis Sentinel which can be done by creating a file named, sentinel.conf with the following contents:

bind 0.0.0.0

port 26379

sentinel monitor redis redis-0.redis 6379 2

sentinel parallel-syncs redis 1

sentinel down-after-milliseconds redis 10000

sentinel failover-timeout redis 20000

After creation of the above configuration files, the other steps involve creating wrapper scripts which will be used during the StatefulSets Deployment. These scripts are as discussed below:

  • The first script is tasked with establishment of whether a Pod is a master or a slave by looking at the hostname. After this, the Redis is able to launch the appropriate configuration. The content of this first script are as shown below:

#! /bin/bash

if [[ $ == ‘redis-0’ ]]; then

redis-server /redis-config/master.conf

else

redis-server /redis-config/slave.conf

  • The other script is used by the Sentinel. It becomes necessary because there is the need for one to wait for the redis-0.redis DNS name to be made available. This is accomplished by creating a script named nel.sh which contains the following contents:

#!/bin/bash

while ! ping -c 1 redis-0.redis; do

echo ‘Waiting for server’

sleep 1

done

redis-sentinel /redis-config/sentinel.conf

After these scripts are written, they are packaged into a ConfigMap object. This can be done by running the subsequent command:

$ kubectl create configmap \

–from-file=slave.conf=./slave.conf \

–from-file=master.conf=./master.conf \

–from-file=sentinel.conf=./sentinel.conf \

–from-file=init.sh=./init.sh \

–from-file=sentinel.sh=./sentinel.sh \

redis-config

 

Creating a Redis Service

In the deployment process of a Redis, the next step involves the creation of a Kubernetes service which will provide discovery and naming for the replicas of the Redis. In order to achieve this, a service is created which does not have a cluster IP address.

This service has two containers present in the Pod. One is responsible for running the init.sh while the other one runs the sentinel script. Notably, there are two volumes which are defined in the Pod. One of these volumes uses the ConfigMapin order to carry out the configuration of the two Redis applications. The other volume is just a simple emptyDir volume that is mapped into the server container where application data is held. This ensures the survival of a container restart.

Playing with the deployed Redis Cluster

The following tests are performed in order to ensure that the creation of the Redis cluster was successful.

  • Firstly, one can try to establish which server is regarded as the master by the Redis Sentinel. This can be achieved by simply using the command below:

$ kubectl exec redis-2 -redis \ — redis-cli -p 26379 sentinel get-master-addr-by-name redis

This prints out the IP address of the redis -0 pod. This can be confirmed by the command below:

kubectl get pods -o wide

  • Confirmation if the replication is working. This is achieved by use of the following command:

$ kubectl EXEC redis-2 -c redis — redis-cli -p 6379 get foo

This command tries to read data the value foo from one of the replicas. The correct response should not be able to show any data.

  • The other method is by trying to write data to a given replica

$ kubectl exec redis-2 -c redis — redis-cli -p 6379 set foo 10

READONLY you cannot write against a scan solely slave. A replica cannot be

written into

it because it is a READONLY file.

After conducting these tests, one can confirm that the cluster was set up correctly and there is data replication between the replicas and the masters.

 

 

References

 

Baier, J. (2017). Getting Started with Kubernetes. Packt Publishing Ltd.

Hightower, K., Burns, B., & Beda, J. (2017). Kubernetes: Up and Running: Dive Into the Future of Infrastructure. ” O’Reilly Media, Inc.”.

Marmol, V., Jnagal, R., &Hockin, T. (2015). Networking in containers and container clusters. Proceedings of netdev 0.1, February.

Kharb, L. (2016). Automated deployment of software containers using dockers. International Journal of Emerging Technologies in Engineering Research (IJETER)4(10), 1-3.

Roles, D. O. How Kubernetes Changes Operations. Operating Systems and Sysadmin, 36.

Toffetti, G., Brunner, S., Blöchlinger, M., Dudouet, F., & Edmonds, A. (2015, April). An architecture for self-managing microservices. In Proceedings of the 1st International Workshop on Automated Incident Management in Cloud (pp. 19-24). ACM.

Bernstein, D. (2014). Containers and cloud: From lxc to docker to kubernetes. IEEE Cloud Computing, (3), 81-84.

Abdelbaky, M., Diaz-Montes, J., Parashar, M., Unuvar, M., &Steinder, M. (2015, December). Docker containers across multiple clouds and data centers. In Utility and Cloud Computing (UCC), 2015 IEEE/ACM 8th International Conference on (pp. 368-371). IEEE.

Kratzke, N. (2014). A lightweight virtualization cluster reference architecture derived from open source paas platforms. Open Journal of Mobile Computing and Cloud Computing1(2), 17-30.

Leave a Reply

ESSAY Instant Price

Get an Instant Price. No Signup Required

Total Price

We respect your privacy and confidentiality!

Contact Us At

Subscribe

Join our mailing list today and benefit from our free ebooks, daily deals, and discount