Kubernetes 101: Part 2
So, in case we have 1 container in a pod, it might get destroyed

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

Now, if one container gets destroyed, other is up and running.
We can also have replication controller for 1 pod too.

So, when this pod will be destroyed,

replication controller will delete this one and create another.

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

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

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

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

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

We also need to mention how many replicas we can have

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

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

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

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

Here this replica set looks for pods which has label front-end
Then you can create the pods/replicas using this

But where did we use selector???
Assume that you have 3 pods created and you are monitoring that

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

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>

or, without modifying we can just make the change from command line
kubectl scale —replicas=6 <yaml file>

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

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

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?

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

Once we deleted the nginx pod, automatically one new pod got created.
Now, you can see it’s up and running

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

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

Ahhaa! the pod is created.
But, now, we should have 3 pods right? Let’s check

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

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.

The only change we have is “kind : Deployment”

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

Practical:
Let’s code this down

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

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 ==> 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

We can also see all information using kubectl get all

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”

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”

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.

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,

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

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

So, this strategy is bad for us
What if we take down 1 server at a time and create the new one then?

In this way, all of our servers/pods won’t be out of service.
And this is called “Rolling Update”

By default Rolling Update is the default updating policy
For now, assume that we have this as our deployment yaml file

Let’s update the image to nginx:1.7.1

Then apply the changes

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

The events where we see replica set had pod up and down.
So, in general a deployment has a replica set

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.

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

We can also verify this by checking the replica sets

What if the new version has issue and we want to get back to the old version??
Yes, we can undo the changes

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

Once done, we can see the output

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

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

Then we wanted to check the rollout status

Let’s delete this deployment

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

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

We can also record the reasons/commands which causes new deployments.
To do that, let’s delete the deployment

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

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

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

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

We can now check the history / cause of the deployment

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

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?

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

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


Assume these pods were used to maintain the website.

Let’s check the pod details

Here, kodekloud/webapp-color:v1 image was used
Let’s see what deployment and strategy we have.

Here we can see StrategyType: RollingUpdate
Now, we will change the image of the pods using this command kubectl edit deployment frontend

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

Once done, we will save and exit.

After the update, the website now looks like this

Let’s change the deployment strategy to Recreate

We did set the strategy type to Recreate.



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

Saved and exited!
The website is now red

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.

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

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.

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?

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

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.

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

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

Then we get rid of the experimental one

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

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

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

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

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

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.

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.

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?

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.

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

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

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.

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?

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.

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

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.

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

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

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

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.

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.

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

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.

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

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

This restart happens until a threshold is reached.

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

We can change this value to Never.

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

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.

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

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

What if the container fails to complete the tasks?
If failed, it creates a new pod until it completes desired successful tasks

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.

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


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

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

Then we can create the job

Networking
A node has an IP address

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

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

Also the node has an IP of minikube/192.168.49.2
When kubernetes is configured, a internal private network gets created.

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

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

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

We need to follow these rules to solve this issue

There are some solutions which provide this networking setup

Assuming we are using one of the solutions here

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.

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

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.

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.

- NodePort: The example we used earlier was a NodePort

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)

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.


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.

Then we can create the service and use it

What if we have multiple pods?

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

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

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

We specified the ports, set kind as Service. Let’s create the service
Now create the service and pod and check the service


The service looks like this

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

If we now know the IP of our pods, we can use : <pod’s ip>:30004
As we are using minikube in our pc, we can also use
minikube service myapp-service --url to get the service IP address

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


As our pods are based on nginx, we can now check the nginx website.
ClusterIP
We can have pods for front end, backend and others

They can contact but the IP’s can go down if the pods are down. So, these IPs are not trustworthy.

We can assign services some clusterIP and thus using those, pods can communicate and that IP won’t change.

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.

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

Using all of the <node’s IP> : port (30035 or, 31061), we can access to

Assume the voters have access to two websites

But how to connect the nodes with this URL?
We can use AWS or, Azure or GCP and use their supportive load balancer here.

Let’s do some coding:
In general kubernetes creates a clusterIP service (default service is called kubernetes)

We can explore the details , targetports, labels it used (selector)
That’s it for this blog!!