Deployments in Kubernetes

Series of hands-on Kubernetes tutorials to make your app highly-available and scalable.

This is the third post in the series of posts related to Kubernetes. If you have not read the previous posts in this series, I highly encourage you to read them. This post is in continuation of the previous post about deploying custom applications on Kubernetes. This post is a hands-on tutorial in which we will see how we can scale-out or scale-in the containerized application, that we built in the previous post, using Kubernetes.

Scaling your application on Kubernetes

In the previous post, I showed how we can deploy a containerized app on Kubernetes and I also showed how we can ensure in a rudimentary way that the app is running within the container that is managed by Kubernetes. In this post, we will use the same app to scale-out and scale-in horizontally in a few seconds, using Kubernetes deploy command.

In a real-world scenario, we want our application to be scalable to better utilize computing resources and handle sudden spikes in traffic as well as ensure fault tolerance. To make our service (any workload in general) scalable, Kubernetes can help us achieve that seamlessly. Kubernetes allows us to quickly spin up additional instances (of workload) within a few seconds in case of spikes in traffic - it takes just one command or can even be taken care of automatically when configured. Similarly, we can also bring down the number of running instances quickly with just one command. Let's see how we can do that using Kubernetes.

In Kubernetes, we can define deployment - it is a logical grouping of similar pods (running the same workload in containers) that can be horizontally scaled-out or scaled-in on-demand. Let's create our deployment to see it in action.

> kubectl create deployment demo-web-app-deployment --image=gauravdhiman05/k8s-demo-web-app --port=80
deployment.apps/demo-web-app-deployment created
>

When we create a deployment using the above command, a single pod will be created on one of the nodes, running the containerized custom application in it. It is very similar to the pod that we earlier created manually. The difference is just that this new pod will be managed and monitored by deployment. Try exploring the details of deployment, using the below commands.

# short summary of deployments
> kubectl get deploy
NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
demo-web-app-deployment   1/1     1            1           5m25s

# little more details of deployments
> kubectl get deploy -o wide
NAME                      READY   UP-TO-DATE   AVAILABLE   AGE     CONTAINERS         IMAGES                            SELECTOR
demo-web-app-deployment   1/1     1            1           5m33s   k8s-demo-web-app   gauravdhiman05/k8s-demo-web-app   app=demo-web-app-deployment

# very detailed information about deployment and pods managed within that
> kubectl describe deploy demo-web-app-deployment
Name:                   demo-web-app-deployment
Namespace:              default
CreationTimestamp:      Thu, 03 Feb 2022 23:49:44 -0700
Labels:                 app=demo-web-app-deployment
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=demo-web-app-deployment
Replicas:               1 desired | 1 updated | 1 total | 1 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=demo-web-app-deployment
  Containers:
   k8s-demo-web-app:
    Image:        gauravdhiman05/k8s-demo-web-app
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
  Volumes:        <none>
Conditions:
  Type           Status  Reason
  ----           ------  ------
  Available      True    MinimumReplicasAvailable
  Progressing    True    NewReplicaSetAvailable
OldReplicaSets:  <none>
NewReplicaSet:   demo-web-app-deployment-6d64d6ff4b (1/1 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  6m29s  deployment-controller  Scaled up replica set demo-web-app-deployment-6d64d6ff4b to 1
>

You can also run the below command to see what all pods are running under the default namespace. This will show pods managed by any deployments or manually created pods too. For instance, in the below output, demo-web-app is the name of the pod that we earlier created manually (it is not part of any deployment), whereas demo-web-app-deployment-6d64d6ff4b-hkb5d is a pod that has been created and managed by a deployment that we created above with name demo-web-app-deployment.

> kubectl get pods
NAME                                       READY   STATUS    RESTARTS   AGE
demo-web-app                               1/1     Running   0          9h
demo-web-app-deployment-6d64d6ff4b-hkb5d   1/1     Running   0          8s
>

Now once the deployment is done, we can easily scale-out using the below command.

> kubectl scale deployment demo-web-app-deployment --replicas=5
deployment.apps/demo-web-app-deployment scaled
>

The above command immediately increases the number of pod instances within deployment from 1 to 5 instances. These pods could be running on any of the nodes within the Kubernetes cluster. Kubernetes manages that internally and we do not need to worry about it. Run the below commands to see the effect of the above command. You will realize that now there are 5 pods whose name starts with common string demo-web-app-deployment which is the name of the deployment.

# summary of deployments. Now 5 pods are running under deployment
> kubectl get deploy -o wide
NAME                      READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS         IMAGES                            SELECTOR
demo-web-app-deployment   4/5     5            4           18m   k8s-demo-web-app   gauravdhiman05/k8s-demo-web-app   app=demo-web-app-deployment

# summary of pods.
> kubectl get pods
NAME                                       READY   STATUS    RESTARTS   AGE
demo-web-app                               1/1     Running   0          9h
demo-web-app-deployment-6d64d6ff4b-5kp79   1/1     Running   0          16s
demo-web-app-deployment-6d64d6ff4b-ftzzt   1/1     Running   0          16s
demo-web-app-deployment-6d64d6ff4b-hkb5d   1/1     Running   0          18m
demo-web-app-deployment-6d64d6ff4b-l787g   1/1     Running   0          16s
demo-web-app-deployment-6d64d6ff4b-lk8qw   1/1     Running   0          16s
>

Now let's scale-in and reduce the number of pod instances that are under deployment demo-web-app-deployment. To scale-in and run only a single pod, run the below command with --replicas option as 1.

> kubectl scale deployment demo-web-app-deployment --replicas=1
deployment.apps/demo-web-app-deployment scaled
>

You can now see that there would be only one pod running under that deployment. To see that, again run the command to get deployment and pod details.

# get deployment details
> kubectl get deploy -o wide
NAME                      READY   UP-TO-DATE   AVAILABLE   AGE   CONTAINERS         IMAGES                            SELECTOR
demo-web-app-deployment   1/1     1            1           7m   k8s-demo-web-app   gauravdhiman05/k8s-demo-web-app   app=demo-web-app-deployment

# get all pods details, including pods under deployment or independent pods that are created without deployments
> kubectl get pods
NAME                                       READY   STATUS    RESTARTS   AGE
demo-web-app                               1/1     Running   1          9h
demo-web-app-deployment-6d64d6ff4b-l787g   1/1     Running   1          7m
>

That's it for this post. In this quick tutorial, we learned how to scale-out and scale-in the containerized application on Kubernetes. We used kubectl scale deployment command to scale and deploy multiple pods, but that is not how normal deployments are done on Kubernetes. Normally we define Kubernetes config file (YAML files) to declare what all entities (deployments, services, replica sets and pods we need in our infrastructure). Declaring things using YAML files is much simpler and does not require us to run multiple Kubernetes commands manually. It also encourages best practices of code-as-infrastructure. In later posts, we will see how to define YAML files that can spin up the required infrastructure in minutes on Kubernetes. For now, we should stick to running kubectl commands manually to learn more about how Kubernetes perform operations. I hope you enjoyed reading this post in addition to the earlier two posts. Drop your comment and let me know if you have any feedback or thoughts to share.

In the next post, I will introduce the service construct of Kubernetes and in what scenarios we want to use that.