Getting started with Kubernetes

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.

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 …115: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 …115: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 …115: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 …116: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 …216: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 …216: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.

Aravind

Foodie🍗 | Motorhead 🏎️ | GSW 🏀 | Software Engineer @hashnode 🖥️

Write your comment…

"tip of an iceberg " I really liked it!

Reply to this…