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
withprocess.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]}
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!
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