Introduction to Kubernetes

Introduction to Kubernetes

Kubernetes, also known as K8s, is an open-source system for automating deployment, scaling, and management of containerized applications. It is also the de-facto standard for orchestrating container deployments.

Kubernetes is like docker-compose for multiple machines.

Problems with manual container orchestration and/or deployment

  • If a container crashes, we manually have to restart it or replace it with a new one if recovery isn’t possible.
  • If there is a usage spike, we have to manually add more containers and configure the load balancer to evenly distribute traffic across the containers.
  • If there is not much usage, we manually have to remove the containers so that our bill is low.

As you can see, there is a lot of manual work in manual container orchestration. Also, we have to monitor the containers throughout the day to know the specific events mentioned above to even begin our manual work.

Other problems:

  • If we use manual docker container orchestration, we will have to stick to the conventions of a specific cloud provider. If we initially setup our docker app using AWS ECS, it will be kind of a challenge to switch from AWS (if we want to) to other Cloud Services Providers. But if we use Kubernetes in AWS, we can use same Kubernetes configuration file in all other Cloud Services providers.

Keeping the above problems in mind, we can use Kubernetes to abstract away this manual work from us.

What Kubernetes is not

  • It is not a cloud service provider. It is just an open-source project which can be used on any Cloud Service Provider.
  • It is not a service provided by Cloud Service Provider. However, Cloud Services Providers might have some services that make working with Kubernetes easier.
  • It is not just a software that we run on some machine. It is also a collection of concepts and tools.
  • It is not an alternative to docker. It works together with Docker to make container management easier.
  • It is not a paid service. It is open-source and is free. However, you will have to pay for resources that you use to run Kubernetes on a Cloud Service Provider.

Concepts and Architecture

  • Pod: Pods hold the actual running App containers and their required resources (like the volumes, IP, run configurations, etc.)
  • Proxy/Config: Is is something that Kubernetes needs to control the network of the containers. Whether the containers should be allowed to listen to external HTTP requests, etc.
  • Worker Node: Worker nodes are the machines / virtual instances that hosts pods, run app containers + resources.
  • Master Node: Master node manages pods across Worker Nodes through something called as Control Plane.
  • Cluster: A set of node machines which are running the Containerized Application (Worker Nodes) or control other nodes (Master Node).
  • Services: A logical set or group of Pods with a unique pod/container independent IP addresses. More on services.

What we need to do

  • Create Cluster and the Node instances (Worker + Master Nodes)
  • Setup API server, kubelet and other Kubernetes services / softwares on the Nodes
  • Create other resources that might be needed (e.g. Load Balancer, Filesystems)

What Kubernetes will do

  • Create your objects (e.g., Pods) and manage them
  • Monitor pods and re-create them, scale Pods, etc.
  • Kubernetes utilizes the provided (cloud) resources to apply your configuration.

More on Worker Nodes

  • Think of a worker node as one computer or a machine or a virtual instance. The Worker node is managed by the Master Node.
  • Worker nodes run one or more pods. Worker nodes are not tied to a single application. Different applications can run inside a single Worker Node.
  • Pods are created and managed by Kubernetes. Each pod can have multiple containers and their resources (volumes, IP, run configurations).
  • Each Worker node should also have the following tools installed:
    • Docker (obviously)
    • kubelet: For communication between Master and Worker nodes.
    • kube-proxy: Manages Node and Pod network communication.

More on Master Nodes

Master node is the node instance that manages the worker nodes. It has the following services installed and configured:

  • API Server: API for the kubelets to communicate
  • Scheduler: Watches for new Pods, selects Worker Nodes to run them on
  • Kube-Controller-Manager: Watches and controls Worker Nodes, correct Number of Pods and more
  • Cloud-Controller-Manager: Like Kube-Controller-Manager but for a specific Cloud Provider, i.e., knows how to interact with Cloud Provider resources

Installation

For local development, we can use minikube

Some helpful commands

  • minikube start
  • minikube status
  • minikube dashboard

Imperative approach of creating deployments

  • Create a deployment
$ kubectl create deployment first-app --image=vighnesh153/kub-first-app
# It will create a deployment, named 'first-app' from the image on dockerhub
# Make sure that your image is pushed to the registry first.
  • To see all running pods
$ kubectl get pods
  • To see all deployments
$ kubectl get deployments
  • To expose a port from inside the pod
$ kubectl expose deployment first-app -
-type=LoadBalancer --port=8080
# My application is configured to run on port 8080
  • To see all the services
$ kubectl get services
# As we are using `minikube`, the `EXTERNAL-IP` column will always be in the 
# pending state. If we were using a cloud provider, it would have the IP provided by
# the cloud provider.
  • Minikube provides us a way to interact with the service. Running the following command will bind the application to one of the ports on our machine.
$ minikube service first-app
  • Auto-restarts: If for some reason, our app running in the container crashes, K8s will automatically restart it. To simulate crash, we can have a route /crash with process.exit(1) inside the handler. Although, each subsequent restart will take more time than the previous restart, for each pod. Just like long-polling. This is to avoid restart-loops.
  • Manual scaling
$ kubectl scale deployment/first-app --replicas=3
# The load balancer will now evenly distribute the requests across the replicas.
  • Updating the deployment
$ kubectl set image deployment/first-app kub-first-app=vighnesh153/kub-first-app:2
  • Undo the latest deployment
$ kubectl rollout undo deployment/first-app
  • View the revision history of a deployment
$ kubectl rollout history deployment/first-app
  • Delete service
$ kubectl delete service first-app
  • Delete deployment
$ kubectl delete deployment first-app

Declarative Approach

Let us first create a deployment object.

  • Create a yaml file named anything. I am using the name deployment.yaml.
apiVersion: apps/v1

# Template of the deployment
kind: Deployment
metadata:
  name: second-app-deployment
spec:
  replicas: 1
  selector:
	matchLabels:
	  my-app: second-app
  template:
    # Template of the pod
	metadata:
	  labels:
		my-app: second-app
    spec:
	  containers:
	    - name: second-node
	      image: vighnesh153/kub-first-app:2
	      
	      # We can have our custom health-check 
	      # config like the following. Not requires as
	      # K8s has its default one, but if our liveness
	      # path is different and/or we want to modify
	      # the delay and the interval time, we do 
	      # the following
	      livenessProbe:
		    httpGet:
		      path: /status
		      port: 8080
		    periodSeconds: 10
		    initialDelaySeconds: 5
  • To apply the yaml file
$ kubectl apply -f deployment.yaml
# This will create the deployment for us

Now, let’s create a service object.

  • Create a yaml file, with any name. In my case, service.yaml.
apiVersion: v1
kind: Service
metadata:
  name: my-backend
spec:
  selector:
	my-app: second-app
  ports:
	- protocol: 'TCP'
	  port: 80
	  targetPort: 8080

  # LoadBalancer for making it available to outside world
  # ClusterIp for making it available only inside the cluster
  type:  LoadBalancer
  • To apply the service
$ kubectl apply -f service.yaml

Now, we expose the service using Minikube

$ minikube service my-backend

To update something, for example use more replicas, we make changes to the yaml file and then re-apply it.
To delete the deployment/service resources:

$ kubectl delete -f=deployment.yaml
$ kubectl delete -f=deployment.yaml,service.yaml
$ kubectl delete -f=deployment.yaml -f=service.yaml

Instead of using multiple files, we can even use just a single file.

apiVersion: v1
kind: Service
metadata:
  name: my-backend
spec:
  selector:
	my-app: second-app
  ports:
	- protocol: 'TCP'
	  port: 80
	  targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: second-app-deployment
spec:
  replicas: 1
  selector:
	matchLabels:
	  my-app: second-app
  template:
    # Template of the pod
	metadata:
	  labels:
		my-app: second-app
    spec:
	  containers:
	    - name: second-node
	      image: vighnesh153/kub-first-app:2

It is a good practice to have service section above the deployment section.


Different types of selectors
selector:
  matchLabels:
    run: myapp
  matchExpressions:
    - {key: my-app, operator: In, values: [second-app]}

More on matchExpressions


This was the basics of K8s, and I hope this was helpful. Drop a comment below to share your thoughts and have a Good Day!

Comments

  1. Amazingly helpful which you have shared here. I am impressed by the details and also it is a significant article for us. Continue imparting this sort of info, Thank you.Kubernetes Solutions Provider

    ReplyDelete

Post a Comment