First steps in Kubernetes. In this post I would like to show you…
By: Shazni Nazeer
Tags: Kubernetes, Docker, Containers

Running a simple container in k8s

Let’s see how to deploy a container into this k8s cluster. In my previous post on docker, I showcased a sample REST API on a docker container. We pushed that to the docker hub as well. Let’s use the image in dockerhub to create a deployment in Kubernetes. Issue the below command.

$ kubectl create deployment flask-rest-api --image=shazni/flask-sample-app

Note you can also use any working image instead of the one that I have used here.

Well, what this command did was, create a new deployment and a pod along with a replicaset. You may see more than one deployment and pod-based on your previous work.

$ kubectl get deployments

NAME READY UP-TO-DATE AVAILABLE AGE

flask-rest-api 1/1 1 1 2m $ kubectl get pods

NAME READY STATUS RESTARTS AGE

flask-rest-api-69c9f844dd-mszmp 1/1 Running 0 2m

Exposing a service

To expose the functionality of the deployment, we need to expose it as a service. There are different types of services such as NodePort and LoadBalancer. Here in this case let’s expose the deployment as a NodePort.

$ kubectl expose deployment flask-rest-api --type=NodePort --port=5000

service/flask-rest-api exposed

I have used port 5000, as my flask rest api is exposed in port 5000. I need to make sure that I expose the application listening port.

We can now see the available services using the below command. ‘kubernetes ‘ is a default service in the cluster.

$ kubectl get svc

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

flask-rest-api NodePort 10.111.160.54 <none> 5000:30363/TCP 4s

kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4d

The cluster IP and port 5000 are internal to the k8s cluster. Also note that we don’t have an EXTERNAL-IP. We can use below port forwarding method to map the locally visible IP/port to cluster IP/port.

$ kubectl port-forward service/flask-rest-api 7000:5000

Forwarding from 127.0.0.1:7000 -> 5000

Forwarding from [::1]:7000 -> 5000

Handling connection for 7000

Handling connection for 7000

Then you should be able to call the API on port 7000 on 127.0.0.1. Let’s test that now.



HTTP/1.0 201 CREATED

Content-Type: application/json

Content-Length: 252

Server: Werkzeug/0.15.4 Python/2.7.12

Date: Fri, 11 Dec 2020 15:16:37 GMT



{

"available_count": 0,

"category": "houshold",

"durability": 5,

"id": 1,

"is_material_scarce": false,

"manufacture_date": "Fri, 11 Dec 2020 15:16:37 -0000",

"name": "Modern Spy Glass",

"uri": "/api/products/1"

} $ curl -iX POST -H "Content-Type: application/json" -d '{"name":"Modern Spy Glass", "durability":5, "category": "houshold"}' http://127.0.0.1:7000/api/products/ HTTP/1.0 201 CREATEDContent-Type: application/jsonContent-Length: 252Server: Werkzeug/0.15.4 Python/2.7.12Date: Fri, 11 Dec 2020 15:16:37 GMT"available_count": 0,"category": "houshold","durability": 5,"id": 1,"is_material_scarce": false,"manufacture_date": "Fri, 11 Dec 2020 15:16:37 -0000","name": "Modern Spy Glass","uri": "/api/products/1"

Then let’s use the GET method /api/products/ to retrieve all products.

$ curl -iX GET http://localhost:7000/api/products/

HTTP/1.0 200 OK

Content-Type: application/json

Content-Length: 296

Server: Werkzeug/0.15.4 Python/2.7.12

Date: Fri, 11 Dec 2020 16:00:00 GMT



[

{

"available_count": 0,

"category": "houshold",

"durability": 5,

"id": 1,

"is_material_scarce": false,

"manufacture_date": "Fri, 11 Dec 2020 15:16:37 -0000",

"name": "Modern Spy Glass",

"uri": "/api/products/1"

}

]

Scaling the deployment

Before trying to scale let’s stop the port-forwarding by hitting Ctr+C. And delete the flask-rest-api service by issuing the below command.

$ kubectl delete svc flask-rest-api

service "flask-rest-api" deleted

Next up I want to create a LoadBalancer type service so that when I have multiple pods running, it can help distribute the traffic. The below command exposes a service as a loadbalancer.

$ kubectl expose deployment flask-rest-api --type=LoadBalancer --port=5000

service/flask-rest-api exposed

Next, let’s issue the below command. It’ll show available ReplicaSets.

$ kubectl get rs

NAME DESIRED CURRENT READY AGE

flask-rest-api-69c9f844dd 1 1 1 23m

Replication set is a concept in k8s to manage stable sets of pods. It’s responsible for maintaining a given number of pods at all times in a k8s cluster. Earlier versions of k8s had ReplicationControllers. ReplicaSet is an evolution of ReplicationController. Thus it’s recommended to be used instead of ReplicationControllers. Deployments are higher-level concepts that manage ReplicaSets. Thus it’s better to deal with Deployments than ReplicaSets although one can use ReplicaSet directly. When we created the Deployment earlier it also automatically created a pod and a ReplicaSet with a desired count of 1. Let’s scale the deployment with the below command.

$ kubectl scale deployments/flask-rest-api --replicas=3

Next issue the below commands to see that you have a ReplicaSet with the desired count of 3. The second command shows that you have three pods running.

$ kubectl get rs

NAME DESIRED CURRENT READY AGE

flask-rest-api-69c9f844dd 3 3 1 24m $ kubectl get pods

NAME READY STATUS RESTARTS AGE

flask-rest-api-69c9f844dd-gcl64 1/1 Running 0 24m

flask-rest-api-69c9f844dd-hhsx5 1/1 Running 0 24m

flask-rest-api-69c9f844dd-lc68p 1/1 Running 0 36m

Now let’s call the below minikube command. It creates a tunnel between your local machine and the k8s cluster so that you can invoke the k8s load balancer service you created earlier.

$ minikube tunnel

🏃 Starting tunnel for service flask-rest-api.

Now if you look into the k8s service, you’ll see an EXTERNAL_IP (In my case it just happened to be the loopback address 127.0.0.1)

$ kubectl get svc

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE

flask-rest-api LoadBalancer 10.106.66.134 127.0.0.1 5000:30464/TCP 28s

Now let’s call the below API resource. It just prints the hostname where the Flask API is running. As you can see it shows different hostnames indicating the Flask API is hit in three different pods.

$ curl http://127.0.0.1:5000/api/host

"Hostname = flask-rest-api-69c9f844dd-gcl64"

(FlaskAPI) shazni:FlaskAPI shazni$ curl http://127.0.0.1:5000/api/host

"Hostname = flask-rest-api-69c9f844dd-lc68p"

(FlaskAPI) shazni:FlaskAPI shazni$ curl http://127.0.0.1:5000/api/host

"Hostname = flask-rest-api-69c9f844dd-gcl64"

(FlaskAPI) shazni:FlaskAPI shazni$ curl http://127.0.0.1:5000/api/host

"Hostname = flask-rest-api-69c9f844dd-hhsx5"

(FlaskAPI) shazni:FlaskAPI shazni$ curl http://127.0.0.1:5000/api/host

"Hostname = flask-rest-api-69c9f844dd-gcl64"

Let’s wrap up the exercise by looking at the k8s dashboard. k8s dashboard is a UI to interact with the k8s. cluster. Cloud vendors will provide a URL to access the k8s dashboard. Since we are running on minikube, we need to enable it to see the dashboard. The below command will show the enabled addons in minikube

$ minikube addons list

|-----------------------------|----------|--------------|

| ADDON NAME | PROFILE | STATUS |

|-----------------------------|----------|--------------|

| ambassador | minikube | disabled |

| dashboard | minikube | disabled |

| default-storageclass | minikube | enabled ✅ |

.... << more output >>

....

As you can see the dashboard is disabled. Enable it with the below command, which should open a web page in the browser. Navigate the UI to see useful information which you were able to see with kubectl get commands. I’ll leave that for you to verify.

$ minikube dashboard enable

🤔 Verifying dashboard health ...

🚀 Launching proxy ...

🤔 Verifying proxy health ...

🎉 Opening http://127.0.0.1:63855/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/ in your default browser..

Kubernetes dashboard

Cleaning up

Now we are done with this brief exercise. Let’s delete the service and the deployment to clean up. Also, don’t forget to Ctrl + C minikube tunnel you started earlier.

$ kubectl delete svc flask-rest-api

service "flask-rest-api" deleted $ kubectl delete deployment flask-rest-api

deployment.apps "flask-rest-api" deleted

Stop minikube

shazni:WSO2 shazni$ minikube stop

✋ Stopping "minikube" in docker ...

🛑 Powering off "minikube" via SSH ...

🛑 Node "minikube" stopped.

Recap

In this article, we looked at the initial steps you can take to play with k8s. We looked at how to spin up a k8s cluster with minikube. We also interacted with the cluster using kubectl commands. Although we only looked at creating k8s objects using commands, an ideal way of creating k8s objects is by declaring these objects using YAML or JSON files. You can see the YAML definition for the pod with the below command.

kubectl get pod flask-rest-api-69c9f844dd-gcl64 -o yaml

Let’s keep further discussions on that for another day.

K8s is becoming increasingly popular as a state of the art application deployment and management system with containers. One reason is because it makes a lot of tasks easier for DevOps. k8s has become an ecosystem. It also brings monitoring and many more into the picture that’s vital for product deployments.

👋 Join FAUN today and receive similar stories each week in your inbox! ️ Get your weekly dose of the must-read tech stories, news, and tutorials.

Follow us on Twitter 🐦 and Facebook 👥 and Instagram 📷 and join our Facebook and Linkedin Groups 💬