Welcome back, everybody.
Uh, you've seen so far just how excellent of a container orchestration platform Kubernetes is.
It provides so many benefits that allow us to manage our containers effectively.
Okay, so one of these being declarative deployment, how you can so easily declare, uh, your configuration
inside of these YAML files and deploy them.
Um, uh, you've seen just how easy it is to achieve service discovery and container networking using
the service primitive and all the hard work of networking is done for us behind the scenes.
Uh, how easy it is to provision resources for individual containers.
And now we're going to look at another benefit provided by Kubernetes in the form of resiliency and
self-healing.
So to give you some examples, if a container, uh, within a pod fails for whatever reason.
If, um, if the process inside of it terminates, if the application in it fails, regardless of what
the exit code is.
By default, Kubernetes has mechanisms in place to always restart the container to make sure that it's
always available and healthy to serve requests to minimize downtime and ensure that our applications
can always come back to life, if you will.
So let's look at an example right now.
All right.
Um, don't do what I'm about to do for this tutorial.
Just watch me demo the self-healing, uh, feature, because ultimately I'm going to end up resetting
this configuration back to what it is now.
Okay.
Let's start the lesson.
So by default, uh, every container within a pod is subject to a restart policy of always.
You don't need to write this because this is the default restart policy.
And essentially what it means is if a process within any of these containers.
So we only have one container running in this pod.
But let's imagine we have many containers if a process within them terminates, if the app inside fails
for whatever reason, um, no matter what the exit code is, as long as that process terminated, then
what Kubernetes will do according to the restart policy is try to restart that container, try to restart
the process inside of it, try to bring it back to life so that it's ready to serve requests again,
to minimize downtime and try to keep that application healthy for as long as it can.
Okay, now, in order to demonstrate this, the easiest way to do it is to really limit the amount of
memory that this app has access to.
So we'll limit it to initially request 35MB of memory, and we'll cap the memory at that.
Remember, because memory is incompressible, you can't throttle data.
So once we reach that limit, what Kubernetes will do is terminate this process.
And because this process has terminated, uh, the restart policy is going to try to run the container
again, get it back to a healthy state so that it's ready to serve requests, keeping the application
resilient and always ready to start up again regardless of past failures.
So I'm going to delete.
Let me get the pods inside of great submission.
Oh I must have already deleted the great submission API pod.
You should have a great submission API pod.
Keep it.
Don't touch it.
I'm going to redeploy a pod with this with these container configurations.
Oh, I got a CD into section three.
Kubectl apply dash f create submission API pod dot YAML.
Beautiful.
Okay.
Kubectl get pods dash and grade submission.
Wonderful.
I'm going to create a new terminal kubectl port forward.
I'm going to forward this pod port to a static port on my machine, just so that I can flood this application
with requests and try to exceed the memory limit.
So the pod whose pod port I want to.
I want to forward.
It's the great summation API, and inside of the great submission and namespace.
It's not going to find the great submission API unless you tell it to look and the great submission
namespace.
Otherwise it'll look inside of default and the port we want to forward outside of the confines of our
Kubernetes setup is the pod port 3000, and I want to forward it to a static port on my machine 9090.
Okay, so now any request I send to localhost 9090 is going to be forwarded to this great submission
API, this container port 3000.
It's going to serve as requests.
Send us back a response.
And ultimately what am I doing.
Um we minimize this, bring it back.
Ultimately, what I want to do is, um, test how the API performs under load.
Perform a load test.
Okay, I'm going to have 50 or let's say 50 too much.
We'll say 25 virtual users making requests to the application, uh, for ten minutes straight.
We're going to press run.
And as this is happening, I'm going to say kubectl get pods dash and great submission.
It's still running serving requests.
Everything is good.
So far.
My computer is just lagging right now.
That's why you're not seeing anything okay.
Our application is sending us back responses.
The responses are fine so far it's healthy, everything is good, but the responses start getting slower
and slower.
Oh, we're back.
We're back to a good, uh, series of responses.
We'll give it some time.
I'm eventually expecting this application to run out of memory, because I'm flooding it with so many
requests, and it just did.
Now it's sending us back errors.
Uh, so if I say kubectl get pods and great submission, it was already restarted and I wasn't able
to show you the on killed exception.
So what happened was let me stop this.
What happened is the the, um, it exceeded the memory limit of 35MB.
So the container, the process inside of the container was terminated Because it was terminated, Kubernetes
sought to restart it to bring it back to life so that it's ready to serve requests again, which it
indeed just did.
So that's how Kubernetes ensures that our applications are resilient to failure.
It tries to it tries to keep them as available as possible to continue serving requests.
And upon the container dying, the container port didn't exist anymore.
So I accept.
I expect my my port forward to have stopped as well.
So I'm going to re, uh, I'm going to re execute the port forward command and I'm going to try to catch
the OAM killed exception.
Uh we'll run this again.
I think 25 users was fine.
Okay, so we'll let this keep running until the app runs out of memory.
Okay, let's check now because it's a bit delayed.
It's still going so far.
Beautiful.
This response is very slow.
All right.
It's still going.
Oh, it just died.
Cut it o o m killed, uh, by sending so many requests.
Eventually our app ran out of memory, exceeded the memory limit.
Our process in the container was terminated.
But based on the restart policy of always, whenever a container process is terminated, keyword terminated.
For whatever reason, regardless of the exit code, it's going to bring it back to life, which it just
did.
That's what makes applications deployed on Kubernetes so resilient because they have the ability to
self-heal after failure.
So I demonstrated one failure, which is the running out of memory failure.
But there are many types of failures that can occur, failures that occur within the application if
they're not programmed correctly, regardless of the failure, if they happen, Kubernetes will try
to bring it back to life.
It will restart the container, hoping that it's ready to serve the next batch of requests.
Okay, I'm going to put this back to 128MB.
Don't need to specify the restart policy of always because that's what it is by default.
And yep that's it guys.
See you in the next one.
And now I know I didn't show you how to use postman, but this is not a postman.
Course.
I just wanted to demonstrate uh, self-healing and how it's achieved in Kubernetes.
And to show you just what you have at your disposal when you deploy your apps in a Kubernetes cluster.
Okay.
But you don't actually need to download postman and set up the runner.
There's no point because I've reset my configuration to what we had previously, and in the next section
we're going to move on to discuss deployments.
See you then.