Kubernetes 101: Introduction to Container Orchestration šµ š³ ā II
In this article, we will continue developing and deploying our simple NodeJS app to our Kubernetes cluster. If you donāt have an app image pushed to the docker hub and a remote/local cluster to which you want to deploy your app, you can read the first part of the article here.
So in the last article, we set up a local manicure cluster and we also dummy node JS app code into an image and pushed it to the docker hub. The name for my image was momil56/kubernetes101-demo-image, your could be different from this.
Now we need to create nature's objects in order to deploy this app into our local minikube cluster. The object that we need to create our as follows:
1. Deployment
2. Pod
3. Service
We will talk in detail about each object as we go about creating them so first of letās start by creating a deployment object.
1. Deployment Object š§°
We need to create a new file called deployment.yaml in our project directory and add the following contents to it. The image name would be different in your case of course, but other than that all other components of the file would most be similar.
The name of the file is also up to you. Now letās dive deeper into the contents of the fileā¦.
This method of creating a Kubernetes object is called the declarative approach. We create a yaml file for each object, that needs to be created or we can declare multiple objects in the same file too and give the command to our k8s cluster to create the said resources, using kubectl CLI tool.
The main components of a kubernetes object file are:
a. apiVersion: At line:1, you can see we specify the apiVersion needed for this object, it varies for every type of object and you can check this out from the kubernetes official documentation by ākubernetes <object> yaml fileā or a better search query.
b. kind: Here you specify the type of object you are creating, like deployment or Pod or Service, etc.
c. spec: Later on you specify the specs of the object. Again it varies from object to object and you can look at specific specs of an object, from k8s official docs, for the deployment object we set:
- replicas: This specifies the number of replicas we want to create of this pod, it should be an estimated guess based on the traffic volume you expect your app to come across.
- selector: This key specifies which pods are controlled by this deployment. You can simply add any number of key-value pairs of your choice and when creating other resources you can put the same tags on them, to allow Kubernetes to understand which pods are controlled by this deployment. I used an app tag with the value k8s101-app and a tier tag, you can choose whatever you want, but mind that you need to specify the same key-value pair in the pod labels too.
- template (Pod): Template is a sub-object, in the specs of deployment, and refers to a pod. Remember a pod is the smallest unit in a Kubernetes cluster and it holds and executes one or more containers. Here, we specify labels in metadata, which needs to match at least one of the labels of deployment. We also specify the specs of the template object, which has a sub-object called containers, which is a list of containers with their name and image, which we want to run in this pod. We currently are running just one container in our pod.
1.1 Applying Deployment Object š ļø
Now that we have created our deployment object, we can apply it to our minikube cluster by using kubectl. Before you do that make sure to check the status of your minikube cluster by running the command:
minikube status
If your cluster is not up and running, you have to start it first by:
minikube start --driver=<your vm name / docker>
Again check the status of your cluster and now we need to create the deployment object using our file via:
kuebctl apply -f=deployment.yaml
Once your deployment object is created, you can see a success message and can check the created resource on the dashboard by:
minikube dashboard
or by:
kuebctl get deployment
2. Service Object šāš¦ŗ
So now we have our app running in a pod in a deployment object in our local minikube kubernetes cluster, but how do we access our app? If you check the app.js file in the project directory here, you can see the app listens on port 3000, but we cannot access it using localhost:3000, because it is not running in a simple docker container, rather our app is running in a virtual machine on our local system, inside a Kubernetes cluster.
So trying to access the app from our local system is like trying to reach the app from outside world, and that functionality is not provided in kubernetes deployment or pod object right off the shelfā¦. hence in order to make your kubernetes app accessible to world, you need a service object!
Letās create a new file called service.yaml and paste these contents into it.
As you can see from the description, we are using the same app tag to tell help kubernetes to decide which pods are going to be exposed using this service. This tag needs to be similar to one of the tags on your pod labels, that you want to make accessible.
In specs of the service, we have a protocol, which is TCP in our case. the targetPort is appās port 8080, which is mapped to port 80 in pod, to access the service running in the pod.
Type of service is another important component, for our case, we are using LoadBalancer, which allows traffic management / āload balancingā and enables the pods to communicate with the outside world. We have other two options as well.. āClusterIPā and āNodePortā, which are used for cluster internal access and node-specific outside-world access. But if you want outside-world access for your pod, LoadBalancer is the best type to go with.
2.1 Applying service object š ļø
Now letās apply our service object as well via:
kubectl apply -f service.yaml
Once your service is created, you need to access your app from the outside world / or your local system, which is possible via having a static external IP address for our pod. Now with paid cloud-based services / remote clusters, that is automatically done, but if you look at the service object that you just created in your minikube cluster, that doesnāt have an external IP assigned, because that is something you donāt get for free and hence this is missing from minikube setupā¦.
But there is a workaround for accessing our app, running in a minikube setup and that is by running:
minikube service <service_name>
You will see an output like this, check out the localhost address and voila:
If you are running into errors, check out the service and deployment object and pod to make sure the labels are correctly set and the image is pushed correctly and you are using the right image name in the deployment object, if everything is configured perfectly you should be able to see the app runningā¦ else play around with the dashboard and object logs to find the problems.
Conclusion š”
A high-level idea of what you just built is right here:
You set up an app in a single node minikube cluster, running in a virtual machine on your system, that is talking to the outside world via a service object. Your app has a deployment object, with a single pod hosting a single container with your appās imageās running instance. This containerās port 8080 is mapped to port 80 of your pod, which is then mapped to a dynamic external IP by the service, that you use to access your app.
Your app would be now monitored by Kubernetes, and would autoscale (depending on the number of pod replicas) to handle incoming traffic load and would spin up again if the container or pod crashes.
Congratulations! Thatās an MLOps feast you just didā¦. I am excited for you to use kubernetes for your own amazingly auto-scalable, reliable and monitored apps and projects!
Happy Learning ā¤ļø