Introduction
I found this hashnode article to be a great introduction to docker. It shows us how we can dockerize our app and run it as a container. I thought I'll put up a follow-up blog post which will explain how to deploy and manage these containerized apps. Enter kubernetes!
What is kubernetes?
Let's look at the current scenario, we have an app which is dockerized and ready to be deployed and Let's say we have some servers at our disposal. Kubernetes is a software which can be installed on these servers, which then allows us to deploy containers(our apps) on them. Kubernetes allows us to treat this group of servers as one entity and interact with it. Our group of servers will be called a cluster. We can interact with the cluster using the API it provides.
For the rest of the blog post, I'll try demystifying kubernetes part by part. For now, Let it be a black box. This black box has an API which allows us to interact with it. Let me introduce one utility - kubectl
. It is a CLI which allows us to interact with the cluster. Please find the instructions to install it here.
Setup
Let's try to set up a kubernetes cluster for us to play with. All of the cloud providers now provide a managed kubernetes service and most of them provide free credits to get started. Getting a cluster up and running in these cloud environments is well documented and pretty easy. The following are some links which can guide you to get one up and running.
- https://cloud.google.com/kubernetes-engine/docs/quickstart
- https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough
- https://docs.aws.amazon.com/eks/latest/userguide/getting-started.html
- https://www.digitalocean.com/docs/kubernetes/quickstart/
If you want to set up a local cluster you can go with
I'll use a digitalocean cluster for this tutorial. I created one by following the documentation. The next step is to configure kubectl
to talk with our cluster. For this, I've to download the config file for our cluster and configure kubectl
to use this config file.
Now I can set an environment variable KUBECONFIG
to the absolute path of the downloaded file and then, kubectl
will be configured to use the downloaded config file and can connect with our cluster.
/Users/aravindkp/Downloads ✘-1
15:05:32 ▶ export KUBECONFIG="$(pwd)/test-cluster-blog-post-kubeconfig.yaml"
We can confirm that the setup was successful by issuing the following command. kubectl get nodes
to list the nodes in our cluster.
/Users/aravindkp/Downloads ✔
15:05:51 ▶ kubectl get nodes
NAME STATUS ROLES AGE VERSION
test-cluster-blog-post-1-7p0g Ready <none> 3m59s v1.13.5
I created a single node cluster for this blog post. In a production environment, it is recommended to create more than 3 nodes for High Availability.
Deployment
Once you have kubectl configured to interact with your cluster you can start communicating with the cluster and start deploying your containers.
Managing kubernetes can be done declaratively or imperatively, to learn more about the differences between them, refer here. We'll use the declarative model here. In this model, we declare how the system should be and kubernetes will take the necessary steps to achieve that state of the system.
Now let's deploy an App, we'll use the https://httpbin.org/
as an example here.
The first kubernetes object that we are going to create is called Deployment. Kubernetes uses yaml
files to specify objects. We'll create a deployment.yaml
file and fill in the following details.
apiVersion: apps/v1
kind: Deployment # Specify the type of object to create
metadata:
name: httpbin # Name for object
labels:
app: httpbin
spec:
replicas: 3 # Run 3 replicas of this Pod
selector:
matchLabels:
app: httpbin
template:
metadata:
labels:
app: httpbin
spec:
containers:
- name: httpbin # Name of the container to run
image: kennethreitz/httpbin # Container image
ports:
- containerPort: 80 # Expose port 80 of the container
We can create the above object in our cluster using by issuing the following command in kubectl
.
blogpost master L …1 ✔
15:36:04 ▶ kubectl apply -f deployment.yaml
deployment.apps/httpbin created
We can see that the deployment was successfully created. We can confirm that by doing,
blogpost master L …1 ✔
15:48:26 ▶ kubectl get deployments
NAME READY UP-TO-DATE AVAILABLE AGE
httpbin 3/3 3 3 12m
The smallest schedulable object in kubernetes is not a container but something called a Pod. For simplicity let's assume it is synonymous to a container.
Now we have a deployment up and running. It has 3 replicas(pods) running. If we want to inspect the three individual pods,
blogpost master L …1 ✔
15:48:32 ▶ kubectl get pods
NAME READY STATUS RESTARTS AGE
httpbin-549db4d877-b5q6b 1/1 Running 0 13m
httpbin-549db4d877-ljmp5 1/1 Running 0 13m
httpbin-549db4d877-pvh9c 1/1 Running 0 13m
To make sure our containers are working properly we can use kubectl
port forward to pipe the traffic from our local port to these containers.
16:00:50 ▶ kubectl port-forward deployments/httpbin 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
Now if you visit the localhost:8080
, you will be greeted with the https://httpbin.org/
homepage.
Now let us see the magic kubernetes does for us. I'm going to delete one of these pods by issuing the following command.
blogpost master L …1 ✔
15:49:46 ▶ kubectl delete pod httpbin-549db4d877-b5q6b
pod "httpbin-549db4d877-b5q6b" deleted
Now we should see only two pods running right? Let's confirm.
15:51:16 ▶ kubectl get pod
NAME READY STATUS RESTARTS AGE
httpbin-549db4d877-ljmp5 1/1 Running 0 15m
httpbin-549db4d877-pvh9c 1/1 Running 0 15m
httpbin-549db4d877-sdmz5 1/1 Running 0 33s
What? we still have 3 pods running. How did this happen?
Remember writing the deployment.yaml
file? We specified that we need 3 replicas of this pod right, so kubernetes will take the necessary steps to make sure this condition is satisfied. So when we deleted one pod, kubernetes kicked in and created a new pod to satisfy the required state. If we look at the AGE
of the third container, it was created 33s
ago and others 15m
ago which clearly explains this.
Now let's try editing our deployment.yaml
the file itself, we'll change the replicas count to 6
and then issue the same command we used earlier.
blogpost master L …1 ✔
16:09:31 ▶ kubectl apply -f deployment.yaml
deployment.apps/httpbin configured
Now we can see that we have 6 replicas as we confirm with,
blogpost master L …1 ✔
16:10:08 ▶ kubectl get pods
NAME READY STATUS RESTARTS AGE
httpbin-549db4d877-5z44t 1/1 Running 0 22s
httpbin-549db4d877-ljmp5 1/1 Running 0 34m
httpbin-549db4d877-nd7lk 1/1 Running 0 22s
httpbin-549db4d877-p7shj 1/1 Running 0 22s
httpbin-549db4d877-pvh9c 1/1 Running 0 34m
httpbin-549db4d877-sdmz5 1/1 Running 0 19m
Service
Now we want to showcase awesome app to the world, right?
For this, we have to make it on the internet. For that, we'll create a kubernetes object called Service. Create a file called service.yaml
and fill it in with the following contents.
kind: Service
apiVersion: v1
metadata:
name: httpbin
spec:
selector:
app: httpbin # select all pods with this label
ports:
- protocol: TCP
port: 80 # listen on port 80
targetPort: 80 # forward traffic to port 80 of containers
type: LoadBalancer
The service resource will listen on port 80
and load balance requests across the different replicas of our app.
Create the service by issuing the following command
blogpost master L …2 ✔
16:15:46 ▶ kubectl apply -f service.yaml
service/httpbin created
If you look at the service we can see that something called EXTERNAL-IP
is showing a status of pending.
blogpost master L …2 ✔
16:15:51 ▶ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpbin LoadBalancer 10.245.207.44 <pending> 80:31723/TCP 7s
It is because when we create service
with type LoadBalancer
the cloud provider will create a load balancer for us. Wait for some time and the LoadBalancer will be up. You can check the progress using the same command above.
After it's issued it'll look something like this,
blogpost master L …2 ✔
16:16:04 ▶ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpbin LoadBalancer 10.245.207.44 139.59.52.13 80:31723/TCP 10m
Now if we go and visit the external IP, we should see our app running :smile:
Using a service of type LoadBalancer
is not recommended in production. We will use another kubernetes object called Ingress to specify rules for traffic coming in to the cluster.
Conclusion
We have just touched the tip of an iceberg with this blog post.This was a very basic introduction to kubernetes. If you found it interesting and would like to see more follow up blog posts about the architecture, tools and the ecosystem, please leave a comment below.