# Kubernetes 101: Part 2

So, in case we have 1 container in a pod, it might get destroyed

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728379419460/e772b6c9-1e4e-49b5-9f7e-3fa7311e9a41.png align="center")

To solve this issue, we can have multiple pods using replication controller.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728379443636/a92be6ea-3ccd-4383-ae69-467f6a5ae72d.png align="center")

Now, if one container gets destroyed, other is up and running.

We can also have replication controller for 1 pod too.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728379537452/48175317-7632-417f-82b3-bc514508d2b3.png align="center")

So, when this pod will be destroyed,

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728379576221/ad99ebed-a067-4efc-b677-280af18c103e.png align="center")

replication controller will delete this one and create another.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728379587863/10cb5b7c-03ed-4a0e-9dd9-f0311a6538ab.png align="center")

Also, to balance loads , we can have multiple pods .

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728379651244/62114eea-da6f-46a1-9a5f-7231b32adc88.png align="center")

When the demand increases, it can also distribute load in other pods residing in other nodes.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728379632935/06217aa7-e514-4273-8109-7d84f7bd4f6a.png align="center")

### Replication controller vs replica set

Replication controller was user earlier but now we use replica set to distribute loads and others.

A replication controller’s yaml file might look like this

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728379878031/fb35efb9-20a5-4f7f-8efd-4e97b2ea0900.png align="center")

apiVersion, kind, metadata and spec are basic 4 parts. Here , kind has ReplicationController enabled.

Replication controllers do have pod instructions. So, we will add that within template. So, that it can create a pod (container instruction is kept in the pod ) once a pod is unhealthy.

For example, this is a pod yaml file

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728380087143/850e7c32-a35d-4ff9-9079-711871fb24ba.png align="center")

We can modify our rc-definition file now (excluding apiVersion and kind)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728380114846/a0cd8ba0-27d2-4fbd-a032-0f9b07e9e94c.png align="center")

We also need to mention how many replicas we can have

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728381032684/1d7c03c0-39e6-455a-be35-f3ad7956f155.png align="center")

Now you can see if the replication controller is created or not and how many replicas we have within that.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728381107793/bdeffbcf-cbc9-4a52-98c8-5f712bcf5444.png align="center")

SO, these replicas are basically pods. We have 3 pods created by the replication controller

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728381147265/676087c9-3cd7-47c4-9bd0-d4e4f9202ba5.png align="center")

Then delete the pods by deleting the replication controller.

`kubectl delete replicationcontroller demoapp-rc`

Now, let’s talk about replicaset

here the apiVersion has to be `apps/V1`

Then rest other are almost same

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728381340038/94768514-a92b-44a4-87c8-9ca53b85afca.png align="center")

but that’s not the end.We have another thing to add called “`selector`” which defines what pods fall under this replicaset

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728381568185/215271ab-b7a9-465f-9001-17fdb7486a90.png align="center")

Here this replica set looks for pods which has label `front-end`

Then you can create the pods/replicas using this

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728381788233/df55c84a-6867-4458-b2bf-8a87c2c3a358.png align="center")

But where did we use selector???

Assume that you have 3 pods created and you are monitoring that

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728381839396/4a9716bb-19dc-49cb-a5a9-5ae473471e32.png align="center")

So, assume you are monitoring pods which has label “front-end”. We already mentioned the labels when creating the pod.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728381981428/ad4967d5-2cf7-4377-8119-1d4e3fa18073.png align="center")

Now, if one pod /set is destroyed, replicaset will create a new pod.

Now, what about scaling the replicas?

We can modify the replicaset file (upgrade 3 to 6) and then use

`kubectl replace -f <replicaset yaml>`

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728382178032/ac4baca4-fa48-439a-8c3c-bdec6d8baf8e.png align="center")

or, without modifying we can just make the change from command line

`kubectl scale —replicas=6 <yaml file>`

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728382225631/359e9ec9-51d6-4476-9b86-958a8332cefa.png align="center")

But the issue is, the replicaset-definition.yml file won’t be edited to 6. It will still be 3.

**Practical:**

assume that, we have generated a pod using pod.yaml first and then created the replicaset using replicaset.yaml

Here is the code for replicaset which used template from pod.yaml file

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728382971040/a53a06f7-3510-45c7-b13a-9589d6e74737.png align="center")

Now, once we create the replicaset, we can see this.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728383206324/98d4a339-f3c3-4c65-805c-d905222932c1.png align="center")

**this replicaset has the goal to create 3 pods which will have label “frontend”.** Gladly we used to have a nginx pod which had this pod. So, we already have 1 with frontend label. We need 2 more, right?

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728383426652/ec1942cb-0611-4bfa-ac84-5b66024d3958.png align="center")

When the replica set was created, these 2 got created as well. You can easily say that these are actually part of the replica set by seeing their names.

What if I delete the nginx pod? Shouldn’t we have new pod here?? Will it have the nginx or something related to replicaset?

Let’s check

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728383579161/b0cad415-fd53-4f46-a360-536d77940038.png align="center")

Once we deleted the nginx pod, automatically one new pod got created.

Now, you can see it’s up and running

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728383616635/21e821f0-b075-41dd-b7b6-a970952ee1af.png align="center")

If you want to see what this replicaset did by now, you can see the events generated by this

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728383733341/bde81578-48f7-44a8-aa0b-58e87668da20.png align="center")

Now, what if we decide to create a pod using the pod.yaml file we had (which has label : frontend)

Let’s guess, should that happen? because replicaset was told that we expect 3 replicas having label frontend.

So, my guess is : We can’t create it

Let’s check

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728384191797/cddfe0f9-c079-4e5f-aa09-35c18dbac6a9.png align="center")

Ahhaa! the pod is created.

But, now, we should have 3 pods right? Let’s check

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728384240321/ec4fc05e-6280-49a6-9a12-fff0b99d9391.png align="center")

Yes!! Basically the new pod got created, but as it had the label “frontend”, it was terminated.

Now, if we check if that termination was done by the replicaset or not, we can see

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728384334218/0eab700b-658d-4101-a165-1c5e6da5cc05.png align="center")

We can see that the new nginx pod was deleted by the replicaset.

### Deployments

Deployment gives us opportunity to upgrade the underlying instances seamlessly using rolling updates, pause or resume changes as required.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728388189737/e00178cc-59c1-47a2-ba9e-0c1309e225a9.png align="center")

The only change we have is “kind : Deployment”

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728388237950/01aba9c6-fe63-4dbd-a3f7-559f02a5be69.png align="center")

Now, if we create the deployment, a replicaset will be created with the same name and some numbers associated with it. And surely, it will maintain the replicas/pods

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728388305846/6d4d870b-3f5b-44c9-b4b6-fb9e7f1f90dd.png align="center")

**Practical:**

Let’s code this down

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728389032702/3b65d0df-cb45-463e-a319-ca6f23441f30.png align="center")

We have created deployment.yaml and pod.yaml file

deployment.yaml has `kind: Deployment` set

Then we create the deployment.

Here the deployment name should be `myapp-deployment`

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728389126125/b03128f8-ad9f-4983-9457-ecfda64399a8.png align="center")

Now, you can see we have created the deployment and the replicaset was automatically created and got the name (myapp-deployment-7f….)

then we are expecting 3 more pods to be created by this deployment.

They are ==&gt; myapp-deployment-7f…….-2x….,myapp-deployment-7f…….-bb…., myapp-deployment-7f…….-78x….

So, replica set and pods got the name from deployment name.

You can also see if deployment actually created a replicaset from the Events portion

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728389606187/618ad417-5b7e-4ced-855e-1b3ff078393e.png align="center")

We can also see all information using `kubectl get all`

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728390242405/c3434547-204d-4b30-86a8-4ff1c02653ab.png align="center")

### Rollout and versioning (used to update the pods within the replica set)

When we create a deployment first, it creates a rollout called “revision 1”

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728393955693/bd80c440-d6c4-45dd-afdd-44b96d0ae7f0.png align="center")

Assume that, we have made some changes to our pod details. When we update the content and create a new deployment, a new rollout gets created called “revision 2”

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728394035133/a8e44cc1-232a-410a-ada4-d49b7c77fc68.png align="center")

For this example, All of these 10 pods were generated in deployment. This can be the command to create a rollout. Rollout basically create a revision.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728394255214/49c55180-5a4c-466a-8328-46bcf33f6418.png align="center")

In this example, revision 1 means that 10 pods were created first and then , there was some changes made and the developer used the kubectl apply -f ………… command to generate the deployment again. But the command was recorded because, —record=true was set.

Note: We will see the practical in the later portion.

### Deployment strategy (How you want the pods to be updated)

Assume you have 5 pods,

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728394323310/8619e68a-2a2a-4c9d-aa43-b145416e6895.png align="center")

You can destroy old 5 pods and create new 5 pods.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728394293774/3484982b-af6f-4e3a-91c1-76f383601918.png align="center")

But the issue is, if anything of our product is dependent on any of the old 5 pods, our product will be down.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728394371533/ca71dd41-bee1-4eb1-bc5c-0810f04e2ef7.png align="center")

So, this strategy is bad for us

What if we take down 1 server at a time and create the new one then?

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728394473459/c59993f3-d87a-4a3d-a11c-393f1b8382a8.png align="center")

In this way, all of our servers/pods won’t be out of service.

And this is called “Rolling Update”

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728394516999/3acd779e-c6be-451c-8cf8-59a274459271.png align="center")

By default **Rolling Update is the default updating policy**

For now, assume that we have this as our deployment yaml file

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728394580544/5e152a90-13ae-4948-a870-f82da7df3466.png align="center")

Let’s update the image to nginx:1.7.1

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728394609118/6a7bceb1-a5c1-4788-9fb9-c640cda05aeb.png align="center")

Then apply the changes

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728394635581/0dbd61d1-017b-422b-9996-6f5975c3420b.png align="center")

You can also verify if we are using rollingUpdate or not.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728394706862/40a13bdb-0b34-484b-9ae4-e2efe5301d45.png align="center")

The events where we see replica set had pod up and down.

So, in general a deployment has a replica set

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728394814828/40ea2060-ba0b-49f4-afdd-639de643ebe7.png align="center")

One a person upgrades the deployment.yaml file and apply that Which means Upgrading, it creates a new replica set and generates new pod there. Also removes old pods as well.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728394886988/1b7b708f-84bb-49e9-87d8-8034c7d38485.png align="center")

Here one pod from replica set 1 gets down and 1 pod from replica set 2 gets up.

In this way, all pods from replica -set-1 goes down and all pods from replica-set-2 goes up

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728394950285/d06f928a-dff7-4fc6-8a5f-b1a970fdbf80.png align="center")

We can also verify this by checking the replica sets

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728394989236/27d4207d-eeca-4885-b6b7-ac51458293c3.png align="center")

What if the new version has issue and we want to get back to the old version??

Yes, we can undo the changes

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728395041371/66c7b257-4333-494e-85ec-c30a42713a84.png align="center")

So, new pods will be destroyed and old ones will be up

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728395081212/ba3790de-5ae9-4a29-a0f1-8186a784ae87.png align="center")

Once done, we can see the output

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728395102191/f354e474-fdd9-4dc0-a2f9-210803292abd.png align="center")

Also, you can now see the old replica set has all 5 pods

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728395139287/61e7e157-fe55-4d8d-8eaa-1d51f671449b.png align="center")

To sum up, once we make changes and deploy, we can enabling rolling to the pods.

Then if we delete/update them and again want to make them up, rollback/other deployment strategy works.

**Practical:**

Here, we have checked if we have pods or not. Then we deployed this file

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728470913656/5551350d-846e-4b87-b104-ce93a842bac0.png align="center")

Then we wanted to check the rollout status

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728470889512/89a57901-f6f2-41cc-aad2-08b3f6dbd59d.png align="center")

Let’s delete this deployment

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728471044382/2f74cec4-0901-4c25-bfc0-a53a98e19f22.png align="center")

Now, I am going to create the deployment and check the rollout status command as fast as possible to see how they are created.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728471126229/b30b5910-05ae-424c-95c8-fcfc617aeb3d.png align="center")

Here, you can see 3 out of 6 replicas are available, then 4, then 5 and then 6

Actually the deployment file mentioned to create 6 pods, and when we wanted to create this deployment, by default it used “RollingUpdate” strategy to create/update the pods

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728471238019/550f6270-5d53-494a-bf8a-5f24f6339d9d.png align="center")

We can also record the reasons/commands which causes new deployments.

To do that, let’s delete the deployment

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728471362525/b9119e6a-f31e-4112-9eda-c65fc56067d2.png align="center")

Now, let’s create the deployment again using `- - record`

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728471492676/91ba2c70-9a80-4bcc-8b8c-9b443dba0aaa.png align="center")

We can now see the change caused the deployment. Here, the cause was the command we used to create the deployment.

Let’s update the images from nginx to nginx:1.26.2-alpine

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728471771838/d6024565-2d49-41f7-a637-573e161f3992.png align="center")

Here we did set the image of nginx as nginx:1.26.2-alpine and you can see how old replica/pods are terminated and at the same time updated.

So, these are the pods updated

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728471880788/172db257-5402-47be-95ca-22a176918b95.png align="center")

Let’s pick one of the pods and we can see that image is set as nginx:1.26.2-alpine

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728471934739/526b5de5-f269-49e4-9c9e-8feea4f7a12b.png align="center")

We can now check the history / cause of the deployment

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728472020780/025348fc-a384-44ec-8a46-2fc89a280649.png align="center")

We can also undo the deployment and go back to the earlier version

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728472360930/cf13b4a7-77e4-4d2b-b5b1-f9df4b24485f.png align="center")

Now, we are expecting to see the nginx images to be used instead of nginx:1.26.2-alpine

let’s check one of the pods?

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728472431822/569b324f-1109-46b1-934d-421364d89068.png align="center")

If we now check the history, we can see revision 2 and 3 created

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728472469557/1afc8854-5593-4400-84e8-b8a65212bec0.png align="center")

Here, 3 is exactly what Revision 1 was. As it has been applied again, it has got the new number and same commands used.

**Practical Lab (KodeKloud)**

Now, assume that we have a deployment responsible for this page

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728396514201/70b392c6-5ede-4e3a-b646-301f3d5a9014.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728396576107/0713b487-9c19-4cf7-8127-8cff3dd504de.png align="center")

Assume these pods were used to maintain the website.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728396669799/18557967-8882-4c4e-9f55-9c496ed7f5f8.png align="center")

Let’s check the pod details

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728396698374/9f9af39e-5beb-4d4f-86cb-e1a211849f47.png align="center")

Here, `kodekloud/webapp-color:v1` image was used

Let’s see what deployment and strategy we have.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728396881225/9f63962c-1b72-4637-98f7-13cc5600377a.png align="center")

Here we can see `StrategyType: RollingUpdate`

Now, we will change the image of the pods using this command `kubectl edit deployment frontend`

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728397069654/e20f2014-a9be-4b88-9c30-ffbb2896807b.png align="center")

Let’s upgrade it to `kodekloud/webapp-color:v2`

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728397111347/2c408142-7929-435e-a18a-0389d05279cf.png align="center")

Once done, we will save and exit.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728397161528/55d474d1-f3b0-4ce0-84bd-cb2d3ec497af.png align="center")

After the update, the website now looks like this

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728397241600/67cf0153-e323-48e2-999b-ea56d7e941fc.png align="center")

Let’s change the deployment strategy to `Recreate`

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728397604811/bea4666b-840a-44c2-8fd7-059d10ce617d.png align="center")

We did set the strategy type to **Recreate**.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743247746270/8ecd2b54-f1a3-435b-a9ff-6c1d548c4c97.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728397626487/812ee906-a3af-4aee-a363-743fa6b181e2.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743249408820/6d1f59cc-7f9a-48d9-84a3-e3ee4ad2a5e1.png align="center")

Let’s change the image to `kodekloud/webapp-color:v3`

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728397743699/0e307b24-3674-4163-9700-8c82e22f04a7.png align="center")

Saved and exited!

The website is now red

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728397843481/e1352894-8c04-49c3-962e-82f76f243a56.png align="center")

So, to sum up, we have learned two rolling update method: One was “Recreate” : In this way all old pods get down at the same time and after a while new pods get up all at the same time

For the second one, “Rolling update”: In this way, one pod goes down and another was is created with new update.

But we have more rolling update strategy

### Blue/Green Deployment

In this deployment method, we assume old pods as blue and new pods as green. All of the traffics are sent to blue pods.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732538738349/99fb083b-563a-42e5-a800-2d02c9a250a0.png align="center")

Once the tests do pass on green pods, the traffics are sent to green pods.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732538787993/039dbb67-d5ff-4f64-b894-a34ea0c9492b.png align="center")

It’s applied in **service meshes** like Istio

How does it work?

First of all, we deploy a blue deployment with a selector (versions:v1), we also deploy a service with the same selector (versions:v1). Then we route traffic from the service to the blue deployment.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732538982694/4f0c1d92-dc33-4c06-a07a-14bc42fc36f2.png align="center")

Then we create another deployment which has the latest pods. Once all of the tests pass on the new deployment (with a selector version:v2) , we change the selector (version:v2) of the service so that it routes traffic to the new deployment.

How to code that?

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732540509004/dc1745c6-04e4-4a5b-9b85-8db70096b77f.png align="center")

Here we created a deploy for the blue pods. We also created a service. In both cases, we used the same selector so that the service can track the pods.

Then we will create another deployment with new version

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732540884319/48e32e65-83e3-432b-b2e2-2b45d9d0e6d6.png align="center")

Once the testing is done, we will change the selector in the service. In this way, we can route the traffic to the new deployment.

Here, the apiVersion in the service-definition.yaml file will be v2 now.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732540956680/efefe6bd-f5cf-44fe-820b-49a151d16389.png align="center")

### Canary Deployment

In this way, we route a small portion of traffic to the new version

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732541064514/24b7fe6d-4ac1-4b28-b1bf-35f509ac2c43.png align="center")

If everything looks goo, we update the original versions (app:1.0) with the newer version (app:2.0)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732541315370/efaef749-b148-4656-ab96-41f598e81e8f.png align="center")

Then we get rid of the experimental one

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732541360746/592f7a87-a896-429b-8755-81d07c4fcf09.png align="center")

How to apply this one?

First we create a deployment and a service with same selector . The selector routes all traffic to the primary deployment

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732541424941/727d425a-19d3-435e-a2be-ca4a1017d461.png align="center")

As our target is to send traffic to both deployment, lets have a common selector

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732541489479/ce9b7ff8-be87-4bf7-8f6e-97817e19883b.png align="center")

Then we update the selector for the service. So, both deployment gets equal traffic

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732541526381/4c41b4be-6837-46b4-929f-f8abc6b04d9b.png align="center")

But do we want that? We want less traffic to be sent to canary deployment.So, let’s remove pods from here.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732541568819/4aed30f2-f3d5-4f99-991c-c651d00cbc7e.png align="center")

As there are less pods, surely there are less traffic going to canary deployment.

***The issue here is, we can’t fix the percentage of traffic on the canary deployment. To solve this, istio service mesh gives us the opportunity to select the desired percentage of traffic.***

Firstly, we create these 3 files

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732542019347/4ab7b870-e710-4d4a-aba3-5c6c15841524.png align="center")

### StatefulSets

Deployment and statefulsets are almost the same. In deployment, pods which are part of the replica sets are created *at the same time.* Whereas in statefulset, *pods are created one by one.* Once a pod is successfully running,another one gets deployed.

Cases like multiple containers with read and write access can be created using stateful set. Assume that, there is one mysql server running and we have decided to copy the data to two new servers.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732551879227/c43c87d8-f16a-4c46-86e5-ec4a7bb423ab.png align="center")

The way we can clone other servers are:

Firstly clone data from master(middle) to slave -1 (left). Then enable replication from master to slave-1 so that, if any new data arrives in master, slave-1 gets the update. Then we wait for slave-1 to be ready and clone the data from slave-1 to slave-2(right) rather than from master to slave-2. We have to avoid clone from master several times as there are networking and other settings which is going to be hard then.Once the clone is done for slave-2, enable replication from master to slave-2 rather than slave-1 to slave-2.

On the slave servers, properly configure the *master server address (MASTER\_HOST=mysql-master)*

If we had to use deployment to deploy them, it would have been impossible as pods/servers are launched all at the same time. Also the IP address changes for the pods as they may get deleted.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732552181861/3a53f505-b176-4cc4-ab21-b7d2174359a4.png align="center")

If we use statefulsets, servers/pods will have unique name and once a pod is launched successfully, another one gets created. So, it is helpful for us.

How to create that?

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732552816775/ea9480ab-86ff-46e7-83c2-7d889d839f8d.png align="center")

Here we had to add **headless service name** (mysql-h) and kind as StatefulSet

Then we can create the pods , scale the pods (—replicas=5), scale down the pods (—replicas=3), or delete pod. When you scale , it scales one by one. When it scale it down,it starts removing pods from the back (in a reverse order)

Note: We can change the order , we need to set podManagementPolicy to *Parallel* so that, it does not follow any order.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732553031239/db317835-9f31-46a8-9f83-ad9e317fb5bf.png align="center")

**Headless services**

We did mention headless service in the StatefulSet’s yaml file

`serviceNaame: mysql-h`

But why?

In general, the way we can do this is, using `service`

Let’s first learn what a normal service can do. A normal service acts as a load balancer and distribute traffic across all pods in the statefulstes. The service here has a cluster IP and the DNS name associated with it is like “mysql.default.svc.cluster.local”

Any other application can now contact the service

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732554583837/ee4307f4-3e77-4170-bebc-094ca7114a01.png align="center")

So, anyone can serve the application but the server which has write access must only be processed through master server (mysql-0)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732555430639/cb8a9709-030a-4ebf-9b02-14505cd97744.png align="center")

Other servers can be used for reading just. What if the application want to reach the master server or slave server directly?

How can it reach that? Surely no one should the IP and DNS of the pod servers as those may change.

So, here comes headless service. Once we create that(mysql-h) , it assigns each pod a DNS.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732555679242/7ccebef8-79b2-4d15-a126-21ee0a761e5d.png align="center")

The application can now reach the pod using that DNS. Remember, this special service does not work as a load balancer.

How to create the headless service?

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732555747755/139f8355-3f1a-43af-b445-74441ce3cd3b.png align="center")

Here, notice that we have set clusterIP as *None*. This is how we can create a headless service. To create a DNS record for the pods, we need to set

`subdomain : <headless-server-name>` and

`hostname: <a name>` in the pod definition file (not in the statefulset definition file)

Note: If we set the `subdomainand & hostname` in the *deployment file* (Note: For deployment. Not as a statefulset), we get the DNS set for all pods using **subdomain and hostname.**

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732556136209/dcebe017-98a1-49ad-96ce-9724fcbb2498.png align="center")

The problem is, all of the 3 pods have **the same DNS now(when used deployment)**. But we want them to be different and that’s where StatefulSet helps.

Here you don’t even need to set the subdomain and hostname. It automatically creates DNS for all the pods. It uses the unique `pod name.headless_servername.svc.cluster.local` as the DNS

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732556440211/b2aaea3a-b4e6-4ea3-9ece-f7c4c874764a.png align="center")

So, we have unique DNS now all of the pods whereas we could never get that using deplpoyment. So, thanks to statefulsets.

### Storage in StatefulSets

When we specify Persistent Volume Claim (PVC) under the pod definition, all pods created by that stateful set tries to use the same volume.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732556799840/c596b62c-7329-497f-ad3a-14ce8d1b4948.png align="center")

But if we want to keep different volumes for each pod, we need to specify PVC for each pod

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732556880762/f835bfb4-128d-4ffc-843a-94454a41641b.png align="center")

Each PVC needs a Persistent Volume (PV) and they may be part of one or multiple storage classes (SC).

So, how to create different PVC for each pod?

Add this pvc-definition.yaml file to the end the statefulset-definition.yaml

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732557036728/d3c84efb-13a8-4c2e-8846-1fe4ae6c5805.png align="center")

Here under volumeClaimTemplate, we have pasted the lines from pvc-definition.yaml

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732557061942/10b17e0e-ac6a-4f01-941c-6abd18a0725d.png align="center")

So, how does it work?

When the first pod is created, a PVC is created.The PVC is associated to a Storage Class. The Storage class *provisions a volume* on the GCE (if we use GCE )

Then PV is created and ***associates the PV with the volume*** and ***binds the PVC to the PV.***

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732557644403/ed6ff488-34cc-4933-8ca6-62e477f784f2.png align="center")

Then the *second pod is created and PVC is created* .

The storage class(SC) then provisions a new volume on Google Cloud , associates that to PV and binds the PV to the PVC.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732557795645/335a900d-f4ba-4cc3-af5e-44469ad6affa.png align="center")

Same goes for the third one………………..

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732557767895/fbf7cbb1-d2fa-4f09-bdd0-01604aebe86c.png align="center")

Now, pods will use their associated PVCs.

### Jobs

When a pod is created here, it runs the computation task (expr 3 + 2). The pod status is “running” at first.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732542489882/ad4edeb6-b647-461b-a904-cad9cbd1a35f.png align="center")

And once the mathematical task is done, pod still exists. Now, the pod status turns to “Completed”

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732542550436/40655898-67bd-44a2-ac23-187660858ef2.png align="center")

Then if someone re-creates the pod in order to keep the pod running, it restarts.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732542614772/7cf40d63-3077-4c48-a081-6ed56264bf28.png align="center")

This restart happens until a threshold is reached.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732542650742/30f5d4d1-5769-4b23-b6f2-699a04b38505.png align="center")

Why is it restarting? Because in the definition file, there is a setting called `restartPolicy` set as `Always`

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732542838657/c7f18d98-af2c-4109-a5f6-9da8b943cc49.png align="center")

We can change this value to *Never.*

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732542862531/411b1818-5f71-44ae-a98a-3a1e193892a5.png align="center")

Now, assume that we want *multiple pods to process at parallel*

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732542917063/f4344d42-21a6-45cc-a182-1077a4d6f9a9.png align="center")

How can we do that? We know that a **replicaset can allow us create multiple pods**. Should we use that? ‘“*No!”*

We should use Jobs instead.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732542992263/6fdc1dfa-7700-44de-bf89-f4a1eba9a0b6.png align="center")

A **job is used to run a set of pods to perform a given task to completion**. Whereas, replicaset only **deals with pod creation.**

So, how to create a job?

Follow these to create a job and check the result (“5”) from the container. Once done, we should delete the job

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732543352985/1f8a4f0c-5af6-458e-9f99-267c92092862.png align="center")

To have multiple pods with the task, we need to specify `completions` as 3 (number of times we want tasks to be completed)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732543450369/f0a34572-19fb-43ee-9daa-dd5fab962afa.png align="center")

What if the container fails to complete the tasks?

If failed, it creates a new pod until it completes desired successful tasks

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732543599355/aa2cdf45-7fd1-4161-a7ad-2e0fe015c4af.png align="center")

There is another way we can deploy pods . We can deploy them parallel. To do that, we need to set parallelism as the number of pods to be deployed in parallel.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732543771533/b83a6ea4-01bb-4591-b460-446c66f95ff4.png align="center")

Here you can see 3 pods have been deployed first and 2 of them got succeeded. Then it deploys 1 pod at a time until it gets a successful pod

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732543825821/916057f4-dab9-4b92-bc5e-2bbae13009cb.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732543840797/1b16d0fb-b582-4790-a33b-27ac58c44f15.png align="center")

### Cron Jobs

A job that can be *scheduled*. For example, creating a job and schedule it and it does the task when the time comes.

This time, we need to specify the schedule in this format

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732543998343/ed3975c9-3171-40e8-b5ed-3920272407a0.png align="center")

Once the schedule is set, it runs the job on the desired time

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732544028257/8e2407ec-c9e0-4512-a913-082a03fcdd1e.png align="center")

Then we can create the job

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1732544364273/03f467a9-fbe9-4443-935f-3a8c4a007f1c.png align="center")

### Networking

A node has an IP address

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728398747749/21997135-5845-4d11-b9c2-2ba7841669e1.png align="center")

Each **pod gets an internal IP address.** (Containers don’t have any IP address)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728398787201/3124159d-c535-446c-baf0-da2dfae408a0.png align="center")

For example, the pod nginx (which has a container nginx) has an IP of *10.244.0.48*

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743349287871/6b066048-c2c3-4b83-9124-cf93f5d27de5.png align="center")

Also the node has an IP of *minikube/192.168.49.2*

When kubernetes is configured, a internal private network gets created.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728399246833/722a7f01-df51-4f3c-82c9-07e6b6be15e7.png align="center")

Now, talking about two different nodes (they have their IP), check this image

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728399311219/198cb06b-d67f-4322-afd4-e327e5738e44.png align="center")

Assuming each has their own private network and a pod associated with it

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728399344168/be465e58-7ead-45cb-9f75-98a24012d001.png align="center")

But the ***internal IP networks are same here***. So, it’s not possible to contact each other as they have the same IP

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728400355474/5cda17ff-63fa-40eb-bc53-1e99e3483193.png align="center")

We need to follow these rules to solve this issue

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728400390461/23d24144-bcf1-4b28-a657-591b759a05ee.png align="center")

There are some solutions which provide this networking setup

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728400414695/c88ca306-9b98-40cd-9c8d-f37b395856a2.png align="center")

Assuming we are using one of the solutions here

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728400467078/458cafb8-c9ff-419b-b35b-7f82c04a6f16.png align="center")

Now, this solution will provide IP to each network and thus each Internal Network IP will be different.So, communicating each other became easier now!

### Kubernetes Services

Services *help communicating between backend, frontend* and *helps connecting to external data source.*

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728400687675/7548986f-13ad-48c7-a53c-6761671bea43.png align="center")

Assume that the *python based container* in the pod has a webpage and you want to access the webpage from your laptop

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728403060408/6daac00e-3d21-4189-8583-7abde79fcd02.png align="center")

We can’t contact the pod as our laptop’s IP and pod’s one is way different.

So, how to contact the pod?

To solve this issue, what we can do is, we can use a service which will listen to a port and pass the traffic to the pod.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728403178991/5a3c57cb-4e06-4e02-ac24-ca30c8fb9598.png align="center")

Now, using the **node IP (192.168.1.2)** and the port(30008),we can contact the pod from our laptop.

Now let’s learn how to create services.

### Service types

There are various types of services.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728403270741/7fa46127-6798-45b7-977c-af7e2bf1e1e0.png align="center")

1. NodePort: The example we used earlier was a NodePort
    

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728403308575/cadea4d1-b71e-4224-8e46-dc907f7e0717.png align="center")

Here the service has port 80 to contact with pod with it’s port 80. The service has it’s IP as well which is Cluster IP (10.106.1.1)

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728403427619/b688d23c-6121-49fb-aeae-7d1dd335521f.png align="center")

How to create a service?

Here we define, kind as *Service* and specifically, spec section is the import portion. Check the image to set the value for ports.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728403539072/a7bebf20-d63f-43ed-8b07-d42bb6cad074.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728403609025/83ab9b9e-d29c-48cc-9b71-a7edd936d852.png align="center")

The NodePort range is between 30,000-32,767

We have specified the TargetPort but what if we have thousands of ports ? How to know which port has this TargetPort?

To solve this issue , we will use ***label and selectors*** to connect to our **desired pod.** So, we use the selector section to use the pod or track the pod.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728405915193/f37b475e-fdb6-4a7a-afd5-9d9a070b0a9a.png align="center")

Then we can create the service and use it

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728405943285/e4a81003-b2db-43e0-981a-441b154ce887.png align="center")

What if we have ***multiple pods?***

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728405988051/12495907-94f2-46b9-ac3f-224c56a90520.png align="center")

Here all the pods have ***label myapp*** and service looked for the myapp via selector.

So, the service will contact with all of the three pods. Now, ***it will work as a load balancer and distribute load among several pods.***

***Kubernetes automatically creates a service*** that spans across all the nodes in the cluster

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743350672816/5c257d04-0bcb-4eec-9713-edf5ba818a49.png align="center")

and maps the target port to the same node port (30008) on *all nodes in the cluster* .

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728406109963/2510487a-5f1d-4475-a4ba-92bedd6964ce.png align="center")

When pods are removed or added, service automatically gets updated . So, it’s highly adaptive.

**Practical:**

Let’s create a folder called service which has service-def.yaml file

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728407834580/a9db24ee-ef3c-4838-b0e4-e02f8f8daa11.png align="center")

We specified the ports, set kind as Service. Let’s create the service

Now create the service and pod and check the service

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743351087040/7a74b9c4-f156-4afa-b7e7-6b92a5a2703f.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728407908393/98650cbe-e867-46ee-830b-70560180ba0b.png align="center")

The service looks like this

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743351142326/aa35ad7b-94e1-46b9-a667-252f164962e6.png align="center")

Also, the pod looks like this. Here the node’s IP is 192.168.49.2

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743351229548/655ef3a0-18fe-4ca4-8b59-7a5692fbe2e7.png align="center")

If we now know the *IP of our pods*, we can use : *&lt;pod’s ip&gt;:30004*

As we are using minikube in our pc, we can also use

`minikube service myapp-service --url` to get the service IP address

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743351314865/fe9a4689-469a-4039-8140-3e86ef8a298e.png align="center")

Here you can see the service is within the node 192.168.49.2 and has port 30004 assigned to myapp-service.

Now using the NOde:Service port, we can connect to pod’s port 80. How? Remember this

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743351442597/4ad73a8d-e07b-4ab0-bb44-9fb97a64540a.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728407961226/2a34ac8f-2d3d-40b5-9782-ece7c86c9308.png align="center")

As our pods are based on nginx, we can now check the nginx website.

2. ClusterIP
    
    We can have pods for front end, backend and others
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728408096206/a9c288d6-f1e2-4cf0-b33a-2dca9169e665.png align="center")
    
    They can contact but the IP’s can go down if the pods are down. So, these IPs are not trustworthy.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728408148663/a1e65119-ded4-48ec-bed8-a41bcbf10fba.png align="center")
    
    We can *assign services some clusterIP* and thus using those, pods can communicate and that IP won’t change.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728408303371/33167183-e9d2-4a91-a567-91d3b793123d.png align="center")
    
    Here we have specified *which pods to target via labels* in selector, also mentioned the ports (target ports and port). Then we can run it and check the services!
    
    All of the backend pods can be reached via the ClusterIP service now.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728408390013/5e49954c-52da-4b12-add2-6fdfd8b42659.png align="center")
    
3. LoadBalancer
    
    Assume that we have 4 node cluster and blue nodes are for vote taking and green two are for the results. Simply a voting machine.
    
    We have two services which listens to port 30035 and 31061
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728408603787/120776c0-400c-4d13-944b-9acbfa64e1c7.png align="center")
    
    Using all of the &lt;node’s IP&gt; : port (30035 or, 31061), we can access to
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728408734314/4ab34348-6dd2-4789-8c54-84d16534d421.png align="center")
    
    Assume the voters have access to two websites
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728408784228/0b32f6c5-25c0-4814-b463-d46c921e14ff.png align="center")
    
    But how to connect the nodes with this URL?
    
    We can use AWS or, Azure or GCP and use their supportive load balancer here.
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1728409006491/878eaab5-b7db-4eb1-8ed3-15bcd29fed66.png align="center")
    
    Let’s do some coding:
    
    In general kubernetes creates a clusterIP service (default service is called kubernetes)
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743352065952/53082444-6ce0-4d44-959a-d128f18e44de.png align="center")
    
    We can explore the details , targetports, labels it used (selector)
    

That’s it for this blog!!
