WEBVTT

00:00.170 --> 00:00.740
Hey guys.

00:00.740 --> 00:01.520
Welcome back.

00:01.520 --> 00:07.220
In this section we're going to be developing and deploying a cloud native application to a Kubernetes

00:07.220 --> 00:08.030
cluster.

00:08.030 --> 00:11.270
We're going to work our way up towards doing that.

00:11.270 --> 00:15.860
Before doing so I want to re-explore some very key concepts okay.

00:15.890 --> 00:25.760
Number one is Kubernetes is simply a tool, a software that runs across a cluster of machines, that

00:25.760 --> 00:28.640
runs across many machines, many nodes.

00:28.640 --> 00:31.490
Some of these machines are master nodes.

00:31.490 --> 00:34.340
The other machines are called worker nodes.

00:34.340 --> 00:42.200
The master nodes are responsible for scheduling when and where your applications will run.

00:42.230 --> 00:45.770
The worker nodes are what actually run your application.

00:45.770 --> 00:53.150
They are the machines that provision the physical resources, the CPU and memory that your applications

00:53.180 --> 00:54.560
need in order to run.

00:54.560 --> 01:00.990
So if you take that cluster of machines, all of these machines, the worker nodes and the master nodes.

01:00.990 --> 01:02.550
They all work together.

01:02.550 --> 01:10.410
They all collaborate under the supervision of Kubernetes in order to provide you, the developer, with

01:10.410 --> 01:16.890
a seamless experience when you're developing and deploying your cloud native apps to that Kubernetes

01:16.890 --> 01:18.600
cluster of machines.

01:18.630 --> 01:22.170
Okay, so what is a cloud native app?

01:22.200 --> 01:30.570
Slide two depicts it as one that can be distributed into many microservices, each one running inside

01:30.570 --> 01:31.560
of a container.

01:31.590 --> 01:32.160
Okay.

01:32.190 --> 01:38.580
Each microservice is like a mini application that performs a single function.

01:38.610 --> 01:39.930
Each microservice.

01:39.960 --> 01:46.650
Each containerized microservice is a building block of the overarching cloud native app.

01:46.650 --> 01:53.070
If you take all of these building blocks, you end up with many microservice applications, all of them

01:53.070 --> 02:00.450
working together to perform the complete set of functionality that is promised by this cloud native

02:00.480 --> 02:03.450
app to all of its end users.

02:03.480 --> 02:10.710
Okay, so a standard example is an e-commerce application that can be distributed across six different

02:10.710 --> 02:12.270
microservice applications.

02:12.270 --> 02:19.650
One microservice handles order management, another microservice handles the product catalog, one manages

02:19.650 --> 02:21.120
the inventory, and so on and so forth.

02:21.120 --> 02:26.820
All of them come together to provide a complete e-commerce experience.

02:26.850 --> 02:32.820
Now, when you've got so many applications, you want to make sure that you don't have difficulty running

02:32.820 --> 02:38.730
them reliably, regardless of the platform or environment that they've been deployed in.

02:38.760 --> 02:41.580
That's where containers are very, very crucial.

02:41.610 --> 02:48.030
Because containers only contain the application and the dependencies that that application needs in

02:48.030 --> 02:50.250
order to run nothing else.

02:50.280 --> 02:55.890
Containers are very portable because they isolate the application and its dependencies from the outside

02:55.890 --> 03:02.920
world, ensuring that they can reliably run, no matter what platform or environment you deploy them

03:02.920 --> 03:03.520
in.

03:03.550 --> 03:05.050
All right.

03:05.110 --> 03:12.520
Now in this section, we're only going to have one great submission app that can be distributed into

03:12.520 --> 03:20.680
two containerized services, one great submission portal that acts as a front end so that users can

03:20.680 --> 03:23.260
interact with it and submit great data.

03:23.350 --> 03:29.980
And when it receives great data from the user, it's going to send it over to a great submission API.

03:29.980 --> 03:37.480
That one is a back end, which contains the business logic for actually managing how the great data

03:37.480 --> 03:38.230
is stored.

03:38.260 --> 03:44.260
So one great submission portal front end that the user can interact with to submit great data, and

03:44.260 --> 03:50.290
one great submission API back end that will manage the storage of the submitted great data.

03:50.320 --> 03:56.440
So we've got all of these containers, and the best place to deploy containers is within a Kubernetes

03:56.440 --> 03:56.860
cluster.

03:56.860 --> 04:02.120
Because Kubernetes, remember, is a very powerful container orchestration tool.

04:02.210 --> 04:07.370
But in Kubernetes, um, well, let's look at an analogy.

04:07.370 --> 04:15.200
If you think of the atom in the physical world as the smallest unit of life in the world of Kubernetes,

04:15.230 --> 04:19.160
the pod is the smallest unit of deployment.

04:19.190 --> 04:19.670
Okay.

04:19.700 --> 04:26.120
So although Kubernetes is this excellent container orchestration tool, you can't deploy a container

04:26.120 --> 04:27.620
directly in Kubernetes.

04:27.620 --> 04:31.130
It has to be wrapped inside of a pod.

04:31.250 --> 04:32.060
Give me one second.

04:32.060 --> 04:34.040
Guys, my battery is dying.

04:35.300 --> 04:38.480
All right, let's plug this guy right in.

04:39.830 --> 04:40.880
Um, yes.

04:40.880 --> 04:44.300
You need to wrap your containers in a pod.

04:44.330 --> 04:53.810
The reason is because, uh, the pod is a very specialized Kubernetes object that has the necessary

04:53.810 --> 05:02.310
abstractions for Kubernetes to automate things like scaling, self-healing, resource allocation, so

05:02.310 --> 05:03.090
on and so forth.

05:03.090 --> 05:10.890
So to really reap the benefits that Kubernetes provides, we wrap the container inside of a pod.

05:10.890 --> 05:16.410
Well, you have no choice but to wrap the container inside of a pod anyways.

05:16.410 --> 05:23.940
When you're setting up a pod, we can distinguish between the metadata and the runtime requirements.

05:23.970 --> 05:31.890
Okay, there is typically a 1 to 1 relationship between the pod and the containerized microservice that's

05:31.890 --> 05:32.820
running in it.

05:32.820 --> 05:38.070
So usually we just name the pod whatever the name of the microservice is.

05:38.220 --> 05:42.210
Some people go as far as calling the pod the microservice.

05:42.210 --> 05:43.710
That's valid too.

05:43.710 --> 05:49.560
Anyways, first we specify the name, then we specify the label groupings.

05:49.590 --> 05:57.210
Okay, labels are used to place the pod into logical groups.

05:57.210 --> 06:05.700
So one group that this pod could belong to is the fact that it collaborates with another microservice

06:05.700 --> 06:08.850
to provide a great submission experience.

06:08.850 --> 06:16.350
So this container, this pod in this case belongs to the Group cloud native app.

06:16.350 --> 06:17.490
Great submission.

06:17.850 --> 06:23.340
Another group that this pod could belong to is the fact that it's a front end.

06:23.340 --> 06:28.410
We could group it alongside every other microservice within this cloud native app.

06:28.410 --> 06:29.640
That is a front end.

06:29.640 --> 06:32.220
In this case, it's the only front end.

06:32.220 --> 06:34.200
But use your imagination.

06:34.290 --> 06:35.190
All right.

06:35.190 --> 06:41.730
And the reason that we label pods into logical groups is because it then makes the pod really easy to

06:41.760 --> 06:43.860
query and perform operations on it.

06:43.860 --> 06:47.730
So I could say something like delete every pod.

06:47.760 --> 06:52.050
That is part of the great Submission Cloud Native app.

06:52.050 --> 06:58.180
And that operation would effectively query every pod that is in that group and delete it.

06:58.300 --> 07:04.420
I could have an operation that says scale every pod that is of type front end.

07:04.450 --> 07:10.210
It would effectively query all pods that have that front end label and scale it up.

07:10.210 --> 07:10.600
All right.

07:10.600 --> 07:12.460
So that's all for the metadata.

07:12.490 --> 07:18.970
The next step is the more interesting step which is to define the runtime requirements.

07:18.970 --> 07:24.640
So the containerized microservice that's actually going to run inside of the pod.

07:24.670 --> 07:25.420
Okay.

07:25.420 --> 07:32.860
Once the container is created we also specify the container port where the underlying microservice will

07:32.860 --> 07:34.600
be serving requests.

07:34.630 --> 07:35.350
Okay.

07:35.380 --> 07:40.390
In this case the underlying app runs on port 5001.

07:40.420 --> 07:42.460
That's just how it's been programmed.

07:42.460 --> 07:50.410
And so what the pod is going to do is automatically expose this container port for internal traffic

07:50.410 --> 07:52.750
within the Kubernetes cluster.

07:53.050 --> 07:53.590
All right.

07:53.590 --> 08:01.040
So after you've specified the microservice, the port that it serves requests on, then you specify

08:01.040 --> 08:09.290
the resource requirements, the memory and CPU that you anticipate this pod will need in order to function

08:09.290 --> 08:10.220
properly.

08:10.250 --> 08:18.080
And what Kubernetes would do if we were running it on an AWS cluster, for instance, is it would look

08:18.080 --> 08:26.870
for a node that can comfortably provision the requested memory and CPU in order to run the app.

08:26.870 --> 08:32.510
But in this case, because we're just prototyping, we only have the one node our laptop.

08:32.510 --> 08:39.710
But the resource requirements essentially decide which node our pod ends up running in.

08:40.010 --> 08:40.910
All right.

08:40.910 --> 08:42.200
That's all for theory.

08:42.200 --> 08:45.050
Let's go ahead and implement all of this now.

08:46.070 --> 08:46.670
All right.

08:46.670 --> 08:53.490
We can start off by creating a new folder called I'm going to call it Kubernetes Is.

08:53.490 --> 09:00.210
Course, this folder is going to contain all the project files that we develop in this course.

09:00.210 --> 09:02.160
So take good care of it.

09:02.160 --> 09:07.560
Launch it, launch your project workspace in an instance of VSCode.

09:07.920 --> 09:15.360
And we're going to start by creating a folder called section one.

09:15.600 --> 09:22.470
Section one is going to contain the pod definition for the grade submission portal pod.

09:25.110 --> 09:25.950
All right.

09:25.950 --> 09:34.140
And if you installed the Kubernetes extension then you should be able to just write pod.

09:34.140 --> 09:39.210
And it will auto generate a skeleton for a pod definition.

09:39.390 --> 09:40.050
All right.

09:40.050 --> 09:48.210
And you'll remember that first we specify the metadata followed by the container runtime requirements.

09:48.210 --> 09:54.780
There is typically a 1 to 1 relationship between the pod and the containerized microservice that's running

09:54.780 --> 09:55.500
in it.

09:55.500 --> 10:00.780
So typically we give it the same name as the microservice app.

10:00.780 --> 10:05.880
So I'm going to say pod grade submission portal.

10:06.570 --> 10:16.380
And the the other piece of metadata is labeling our pod so that we can identify it and categorize it

10:16.380 --> 10:18.150
into distinct groups.

10:18.180 --> 10:24.570
Now instead of just defining the application name that this microservice belongs to, I'm not just going

10:24.600 --> 10:30.330
to say name, I'm going to say app.kubernetes.io.

10:31.110 --> 10:40.290
It is recommended to preface your keys with this prefix, in order to avoid potential collisions with

10:40.290 --> 10:44.670
other third party labels within the Kubernetes ecosystem.

10:44.670 --> 10:50.370
So this prefix ensures adherence to Kubernetes labeling conventions.

10:50.400 --> 10:50.790
All right.

10:50.790 --> 10:53.200
So here we can start with the application name.

10:53.200 --> 11:00.400
This great submission portal microservice belongs to the grade submission application.

11:00.400 --> 11:07.750
It works alongside another microservice to provide a complete grade submission experience.

11:08.950 --> 11:16.480
Okay, so the highest level of identification is the cloud native app name.

11:16.480 --> 11:23.680
The second highest level is app dot Kubernetes.io slash component.

11:24.910 --> 11:33.760
So this specifies the component or role of this microservice app within the overall application architecture,

11:33.760 --> 11:37.990
one of them being a front end, the other being a back end.

11:38.020 --> 11:41.830
Our great submission portal microservice is a front end.

11:42.100 --> 11:43.000
Okay.

11:43.090 --> 11:50.680
And then we get even more granular app.kubernetes.io/instance.

11:50.710 --> 11:58.640
We end with the unique instance identifier, as it represents the most specific and granular level of

11:58.640 --> 11:59.420
labeling.

11:59.420 --> 12:05.060
It allows us to differentiate between multiple instances of the same great submission app.

12:05.090 --> 12:10.250
Here we are setting up the Great Submission Portal instance.

12:10.820 --> 12:17.690
So we've effectively used labels to identify our pod and categorize it into distinct groups.

12:17.690 --> 12:22.340
This is going to help with querying and performing operations on the pod later on.

12:22.370 --> 12:24.740
Now we specify the runtime requirements.

12:24.740 --> 12:26.360
We're done with the metadata.

12:26.600 --> 12:27.320
All right.

12:27.320 --> 12:33.020
Within this pod we're going to create a container called Great Submission Portal.

12:33.050 --> 12:38.600
Remember the 1 to 1 relationship between the containerized microservice and the pod itself.

12:38.630 --> 12:39.230
All right.

12:39.230 --> 12:43.250
And our container will be created from a container image.

12:43.250 --> 12:48.050
If you've taken my Docker course or if you're familiar with containerization in general.

12:48.080 --> 12:55.830
An image is a snapshot shot that captures a single piece of code and the dependencies that that code

12:55.860 --> 12:58.620
needs in order to run nothing else.

12:58.620 --> 13:02.100
So let me just show you something real quick.

13:03.210 --> 13:07.920
So here is the great submission portal application that I coded up myself.

13:07.920 --> 13:14.370
So here we have the Python file, the HTML, the CSS, the dependencies that this code needs in order

13:14.370 --> 13:14.880
to run.

13:14.880 --> 13:22.200
So I've taken this code as well as the dependencies, and I wrapped all of them up into a single Docker

13:22.200 --> 13:23.040
image.

13:23.070 --> 13:23.940
All right.

13:23.940 --> 13:29.880
And I published that image to Docker Hub for public use okay.

13:29.910 --> 13:33.690
So that you and I can pull this image during our lesson.

13:33.690 --> 13:42.120
So you can go ahead and go to Docker Hub, search for my name and copy and paste the image name into

13:42.120 --> 13:45.780
your Pod definition so that we can pull it.

13:46.260 --> 13:46.890
All right.

13:46.890 --> 13:53.010
If you're too lazy to go to my Docker Hub, you can just be very careful in copying this down and getting

13:53.010 --> 13:53.910
it right.

13:54.480 --> 13:54.840
All right.

13:54.840 --> 14:02.250
So the container image is a snapshot a self-contained snapshot of our code and dependencies.

14:02.250 --> 14:07.050
And we bring that image to life by creating a container out of it.

14:07.050 --> 14:09.060
So the image contains the code.

14:09.060 --> 14:14.010
And the container is what actually runs the code and creates a running process.

14:14.040 --> 14:14.760
All right.

14:14.760 --> 14:21.630
And when you've got a running process, you need to allocate the necessary amount of resources for that

14:21.630 --> 14:23.220
process to run properly.

14:23.220 --> 14:27.720
So we can distinguish between limits and requests.

14:27.750 --> 14:30.180
I'll get to limits in a bit.

14:31.140 --> 14:42.900
So requests what it is is it's the minimum amount of memory and CPU that the application needs in order

14:42.900 --> 14:43.980
to function properly.

14:43.980 --> 14:54.280
The minimum amount, the values that you specify here, they dictate which node our pod is going to

14:54.280 --> 15:00.910
be scheduled on, because Kubernetes is going to look at the amount of memory and CPU that you're requesting,

15:00.910 --> 15:10.300
and it's going to decide which node can most comfortably provision these resources for our app to run.

15:10.330 --> 15:10.960
All right.

15:10.990 --> 15:20.170
So this is the minimum amount of memory and CPU that our app is guaranteed to have when our container

15:20.200 --> 15:21.370
gets deployed.

15:21.400 --> 15:22.000
All right.

15:22.030 --> 15:26.890
Now 500 Millicores for my very very small app is a bit excessive.

15:26.890 --> 15:30.370
So I'm only going to give it 200 millicores of CPU.

15:30.400 --> 15:38.710
The node that our app is running in is only going to give it 200 millicores of CPU, 128 bytes of memory.

15:38.740 --> 15:39.430
Okay.

15:39.460 --> 15:45.580
Now, before we move forward, talking about limits, I want to start off with some definitions.

15:45.610 --> 15:51.920
Memory is the workspace where a computer stores and retrieves data for immediate use.

15:51.980 --> 15:59.060
CPU is the compute that performs calculations and executes instructions.

15:59.420 --> 16:02.720
You can throttle compute.

16:02.750 --> 16:05.180
You can't throttle data.

16:05.330 --> 16:13.400
So that makes CPU a compressible resource and memory an incompressible resource.

16:13.430 --> 16:14.180
Okay.

16:14.180 --> 16:20.900
What implications does this have if we don't place a limit on the amount of memory that this container

16:20.930 --> 16:21.680
can use?

16:21.710 --> 16:29.240
If you don't place a cap, then it's simply going to consume however much memory it can get its hands

16:29.240 --> 16:29.780
on.

16:29.780 --> 16:35.960
And if other containers start doing the same thing, this can lead to an out of memory situation for

16:35.960 --> 16:36.620
the node.

16:36.620 --> 16:43.250
And this out of memory situation on the node results in a disastrous situation where containers are

16:43.280 --> 16:45.800
being terminated left and right.

16:45.800 --> 16:48.630
Suddenly you have no more apps running.

16:48.660 --> 16:56.310
Okay, so you typically never want your containers to exceed the amount of memory that they've been

16:56.310 --> 16:58.200
initially allocated.

16:58.200 --> 17:01.260
So we're going to set the memory equal to the.

17:01.290 --> 17:07.590
So so we're going to set the memory limit equal to the exact amount that it will be initially allocated

17:07.590 --> 17:09.630
by the node it's been deployed in.

17:09.630 --> 17:14.760
Now for CPU you normally never want to place a limit on that.

17:14.970 --> 17:19.110
Let me explain why CPU is a compressible resource.

17:19.110 --> 17:26.940
If the node just happens to have some unused resources, we would want our app to take advantage of

17:26.940 --> 17:31.380
it and use as much CPU as it can get its hands on.

17:31.500 --> 17:39.210
And if our node ends up running out of CPU to a point where there's contention between containers to

17:39.240 --> 17:47.190
claim some CPU, then the kernel scheduler will automatically throttle our container to just use the

17:47.190 --> 17:50.460
amount of CPU that it initially was given.

17:50.490 --> 17:51.240
All right.

17:51.270 --> 17:55.410
Because CPU can be throttled, we don't need to put a limit on it.

17:55.440 --> 18:02.280
Memory cannot be throttled, so we need to cap it to ensure that no excessive memory is used beyond

18:02.280 --> 18:04.500
what's been initially allocated.

18:04.500 --> 18:08.730
And we get this error, which I personally disagree with.

18:08.760 --> 18:15.390
It says that no CPU limit was specified for this container and that we should the creators of Kubernetes

18:15.420 --> 18:23.160
themselves, they actually advise not specifying CPU limits for your containers or rarely ever doing

18:23.160 --> 18:23.580
so.

18:23.580 --> 18:28.440
So what I'm going to do is I'm going to say command shift P, control shift P.

18:28.470 --> 18:34.260
If you're using windows, I'm going to open settings JSON.

18:36.210 --> 18:41.250
And then what I'm going to say inside of VS Kubernetes.

18:41.280 --> 18:45.990
All right is disable Linters.

18:48.700 --> 18:50.200
Resource.

18:53.560 --> 18:54.880
Limits.

18:57.250 --> 18:57.730
Okay.

18:57.730 --> 18:59.770
Let me make sure I didn't misspell anything.

19:00.640 --> 19:02.770
Then I'm going to say command shift P again.

19:02.770 --> 19:04.360
Control shift P for windows.

19:04.360 --> 19:06.040
Reload the window.

19:09.220 --> 19:10.840
And the warning is gone now.

19:10.960 --> 19:12.040
All right.

19:13.330 --> 19:20.770
So in the grand scheme of things we've set up our pod.

19:20.800 --> 19:24.190
We have our containerized microservice.

19:24.220 --> 19:31.060
Our node is going to allocate this microservice a minimum amount of memory and CPU.

19:31.420 --> 19:33.910
The last step is to specify the container port.

19:33.910 --> 19:39.400
So I program the great Submission portal to serve requests on port 5001.

19:39.430 --> 19:45.740
It follows that we need to expose a container port 001.

19:49.340 --> 19:57.290
Where our containerized application can serve requests and our pod will automatically expose this container

19:57.290 --> 20:02.000
port for internal traffic within our Kubernetes cluster.

20:02.420 --> 20:03.200
Okay.

20:03.320 --> 20:04.790
And that's pretty much it.

20:04.820 --> 20:07.550
We're ready to deploy what we've got.

20:08.750 --> 20:14.570
And another thing I want to say for memory and CPU there are no magic numbers.

20:14.600 --> 20:20.150
It depends on the application itself, the nature of the things that it's doing.

20:20.180 --> 20:26.540
Typically what you want to do is load test your application with your team, monitor its performance,

20:26.540 --> 20:31.220
and determine what an appropriate amount of memory and CPU is.

20:31.220 --> 20:36.560
In this case, I've already determined that for my app, so I'm going to be using these values.

20:36.710 --> 20:37.550
Okay.

20:37.700 --> 20:40.760
And now what I can do is say kubectl.

20:41.930 --> 20:44.120
Well let me CD into section one.

20:45.950 --> 20:50.870
All right I'm going to say kubectl apply dash f.

20:50.870 --> 20:55.610
By the way if you've not used vs code before just go to terminal new terminal to open up a new terminal

20:55.610 --> 20:56.090
session.

20:56.120 --> 21:00.530
Anyways, I digress kubectl dash f so the file is great.

21:00.530 --> 21:02.090
Submission portal pod.

21:05.750 --> 21:09.620
From this pod definition we're going to create our pod.

21:09.650 --> 21:14.840
All right so I can go ahead and say kubectl get pods.

21:18.500 --> 21:21.230
Uh so here we have our pod that's been set up.

21:21.230 --> 21:29.720
The container is currently being created I can say kubectl describe pod followed by the pod name to

21:29.750 --> 21:31.790
get the status of the pod.

21:33.890 --> 21:36.320
Uh, the container was created successfully.

21:36.320 --> 21:37.820
The image was pulled.

21:37.820 --> 21:40.370
Everything seems to be good.

21:40.550 --> 21:46.530
Here we see the amount of CPU and memory that the that the container requested.

21:46.860 --> 21:47.490
All right.

21:47.490 --> 21:49.740
Everything is beautiful.

21:51.360 --> 21:54.180
Now I can say kubectl get pods again.

21:56.160 --> 22:01.290
And we see that our pod has one container in it that is running.

22:01.320 --> 22:02.850
Everything is perfect.

22:02.880 --> 22:07.020
Now, what's running inside of this pod is an actual application.

22:07.020 --> 22:12.750
If I want to find out what's going on in this application, I can view that application as logs in one

22:12.750 --> 22:13.650
of two ways.

22:13.650 --> 22:22.080
I can say kubectl logs, view the logs for the app that's running inside of great submission portal,

22:23.340 --> 22:27.360
and it outputs the logs from our app.

22:27.390 --> 22:36.540
All right, now if I want to stream the logs in real time then I can say kubectl logs dash f stream

22:36.540 --> 22:44.710
the logs within the containerized service running in the great submission portal pod And here I'm streaming

22:44.710 --> 22:45.460
the logs.

22:45.490 --> 22:51.700
Okay, so if we start getting requests or if the app starts outputting logs, it's all going to show

22:51.700 --> 22:53.110
up in real time.

22:53.140 --> 22:54.040
All right.

22:54.070 --> 22:57.160
Now I'm going to open up a new terminal session.

22:59.170 --> 23:08.230
And I'm going to say kubectl port forward and followed by the pod name.

23:08.860 --> 23:11.620
I'll explain what port forward is in a second.

23:13.330 --> 23:23.680
So if you imagine a boundary being our Kubernetes cluster, our great submission portal container can

23:23.680 --> 23:27.490
only be accessed internally within the cluster.

23:27.490 --> 23:33.760
I want to access this pod port where the application is serving requests on my local machine.

23:33.760 --> 23:41.650
So what I can do is forward the port on this pod to my local machine port 8080.

23:41.680 --> 23:44.120
This can be any value that you want.

23:44.540 --> 23:49.790
And the pod port that I'm going to forward is 5001.

23:50.060 --> 23:55.640
So first you specify the name of the pod whose port you want to forward.

23:55.670 --> 24:03.410
Then you specify what that port is and which local port on your machine you want to forward traffic

24:03.410 --> 24:04.070
to.

24:05.210 --> 24:06.140
All right.

24:06.470 --> 24:10.880
So now I'll be able to access my app on localhost 8080.

24:10.880 --> 24:16.580
And any requests I make here will be redirected to pod port 5001.

24:16.580 --> 24:21.350
And as I do that I want to stream the logs over here.

24:21.860 --> 24:28.250
So I'll go ahead and say, uh, why am I using Safari or whatever?

24:28.280 --> 24:31.160
Localhost 8080.

24:35.630 --> 24:37.820
And I'm able to access the application.

24:38.360 --> 24:39.230
Beautiful.

24:39.260 --> 24:46.580
All right Now, um, what I'm going to do is stop this.

24:46.940 --> 24:48.470
Stop this as well.

24:48.500 --> 24:53.180
Now, what happens if I put an excessive amount of memory and CPU?

24:53.210 --> 25:04.670
Like, what if I put something like 10,000 maybe bytes and five 50,000 millicores.

25:04.700 --> 25:05.510
Okay.

25:05.930 --> 25:12.020
I'm going to say kubectl delete pod.

25:12.050 --> 25:13.100
Now you know what.

25:13.130 --> 25:23.120
Let me use some label selection dash l I can query all pods that have the following label.

25:23.390 --> 25:27.170
All pods that belong to the Great Submission app.

25:30.410 --> 25:31.340
Oh my apologies.

25:31.370 --> 25:32.870
Should be an equal sign.

25:32.900 --> 25:37.370
My label selector was simply not properly formatted

25:42.750 --> 25:43.710
All right.

25:43.710 --> 25:47.100
So my great submission portal was effectively deleted.

25:47.100 --> 25:54.960
I was able to use a label selector to query for my great submission portal pod and delete it accordingly.

25:54.960 --> 25:57.330
That's where labels come into play.

25:57.330 --> 26:03.540
They allow us to use label selectors to query our resources and perform operations on them.

26:03.540 --> 26:10.980
That's why you typically always want to follow this, uh, broad to more granular format where you label

26:11.010 --> 26:12.690
based on the cloud native app.

26:12.690 --> 26:18.720
It belongs to what its role is within the application architecture.

26:18.720 --> 26:21.090
And then you specify the actual instance.

26:21.120 --> 26:21.330
Okay.

26:21.360 --> 26:26.160
So we could have used any of these labels to query for our pod and delete it.

26:26.580 --> 26:28.110
Anyways, I digress.

26:28.140 --> 26:31.680
Now I'm going to say kubectl apply dash f.

26:31.680 --> 26:34.650
Great submission portal pod dot YAML.

26:34.830 --> 26:43.870
With these extravagant memory requests Oh request can't be less than limit.

26:43.870 --> 26:49.360
That should make sense, because the memory requests is the minimum amount that it can have.

26:49.360 --> 26:50.530
And this is the cap.

26:50.530 --> 26:52.930
So we'll just set it to be the same thing.

26:53.410 --> 26:54.400
All right.

26:55.540 --> 26:58.660
We'll have to delete our pod again I believe.

27:01.390 --> 27:02.350
Oh no need.

27:02.380 --> 27:02.830
Okay.

27:02.860 --> 27:04.960
We'll reapply the definition.

27:05.200 --> 27:07.180
Great submission portal created.

27:07.210 --> 27:08.020
Okay.

27:08.140 --> 27:10.150
Now I'm going to say kubectl.

27:11.140 --> 27:12.730
Let me clear the output.

27:13.810 --> 27:15.970
Kubectl get pods.

27:17.050 --> 27:18.850
Notice that it's pending.

27:18.880 --> 27:29.140
It's trying to find a node that has the resources to provision this amount of memory and CPU for our

27:29.140 --> 27:29.920
container.

27:30.100 --> 27:36.730
The node in this case is my personal machine, and it definitely doesn't have this much memory and CPU

27:36.730 --> 27:38.800
to give a single container.

27:38.850 --> 27:39.540
Okay.

27:39.600 --> 27:44.580
So if I say kubectl describe this pod.

27:47.130 --> 27:50.640
You can see that it says zero out of one nodes available.

27:50.640 --> 27:53.460
Insufficient CPU insufficient memory.

27:53.490 --> 27:57.330
My node which essentially forms this Kubernetes cluster.

27:57.330 --> 28:02.190
It doesn't have enough resources to give this container.

28:02.190 --> 28:06.480
So the overall pod just always remains in the pending state.

28:06.540 --> 28:07.140
All right.

28:07.140 --> 28:13.320
So we can go ahead and delete this pod by simply saying kubectl delete pod.

28:13.320 --> 28:19.920
Instead of using a label selector to query the pod based on the group that it belongs in, I can simply

28:19.920 --> 28:23.010
delete the pod as well based on its name.

28:23.190 --> 28:29.100
All right, now label label selectors become more handy once we talk about service discovery.

28:29.100 --> 28:34.410
That was just a demo to show you that we query based on labels in Kubernetes.

28:34.410 --> 28:36.780
But anyways, we've deleted that.

28:36.780 --> 28:47.150
Let's reset our container to use meaningful values, and that's pretty much it for deploying a microservice

28:47.180 --> 28:49.220
app in Kubernetes.

28:49.700 --> 28:50.270
All right.

28:50.270 --> 28:55.040
Let's go ahead and wrap this lesson up with one final topic a small topic I promise.

28:55.070 --> 28:59.510
So a pod can actually run more than one container.

29:00.260 --> 29:01.040
Okay.

29:01.370 --> 29:06.050
Um, does that mean we would want to run the great submission API inside of the Great Submission Portal

29:06.080 --> 29:06.740
pod?

29:06.770 --> 29:08.690
That wouldn't make any sense.

29:08.720 --> 29:15.860
Remember the 1 to 1 relationship between the pod and the containerized microservice that's running in

29:15.860 --> 29:16.310
it?

29:16.340 --> 29:23.960
It doesn't make sense to have two separate microservices with distinct roles and distinct responsibilities

29:23.960 --> 29:26.570
running inside of the same pod.

29:26.570 --> 29:33.650
Running two containers inside of the same pod implies that the containers need to be created and terminated

29:33.650 --> 29:34.880
at the same time.

29:34.880 --> 29:41.220
They need to be scaled up or down at the same time, these are two very separate applications and need

29:41.250 --> 29:44.430
to be scaled and created independently.

29:44.460 --> 29:45.120
All right.

29:45.150 --> 29:48.660
So when would you ever want to have two containers in the same pod?

29:49.530 --> 29:58.320
When the microservice relies on a sidecar to provide it with additional behavior and functionality?

29:58.350 --> 30:04.560
In this case, the great submission portal microservice, which is still the meat and potatoes of this

30:04.560 --> 30:05.100
pod.

30:05.100 --> 30:07.470
It's the core component of this pod.

30:07.500 --> 30:16.770
It relies on a great submission portal health checker in order to monitor its health and display information

30:16.770 --> 30:17.550
about it.

30:17.580 --> 30:18.420
Okay.

30:18.450 --> 30:20.700
The great submission portal health checker.

30:20.700 --> 30:25.560
It cannot exist without the great Submission portal microservice.

30:25.590 --> 30:31.530
It needs to be run inside of the same pod as the Great Submission Portal microservice, so that when

30:31.530 --> 30:38.950
we create the pod, they are both scheduled on the same node at the same time, when we destroy the

30:38.950 --> 30:41.380
pod, both containers are destroyed.

30:41.410 --> 30:45.640
Together, this container cannot exist without the Great Submission Portal.

30:45.670 --> 30:49.300
Okay, now I said something really important.

30:49.510 --> 30:55.600
Uh, both of these containers, by virtue of running in the same pod, they're going to be scheduled

30:55.600 --> 30:56.980
to the same node.

30:57.010 --> 30:59.950
They're going to be scheduled to the same host.

30:59.950 --> 31:05.710
They are going to share the same networking, the same network namespace, which means that these two

31:05.740 --> 31:09.820
containers can communicate with each other via localhost.

31:09.820 --> 31:15.700
This is really convenient because I programmed the Great Submission Portal health checker to make requests

31:15.700 --> 31:22.600
on localhost 5001 to make requests to the great submission portals.

31:22.600 --> 31:28.570
This container port 5001 at the Great Submission portals health endpoints.

31:28.600 --> 31:36.410
Okay, so this health checker is constantly making requests to the great submission portals health endpoint

31:36.410 --> 31:40.970
on its container port and then it displays information about it.

31:41.000 --> 31:42.320
That's all it is.

31:42.350 --> 31:49.940
Now, this great submission portal health checker, I packaged it and all of its dependencies into a

31:49.940 --> 31:56.150
Docker image, um, which is available for public use.

31:56.150 --> 32:01.250
So go to my Docker Hub registry are slim 087.

32:01.250 --> 32:08.570
You can look for the following image, or you can just copy it down to your pod file.

32:10.760 --> 32:11.330
Oops.

32:11.330 --> 32:12.620
Don't want to do that.

32:12.620 --> 32:14.930
So let me just copy it down here.

32:14.930 --> 32:16.010
For now.

32:17.450 --> 32:20.660
We're going to have two containers running inside of this pod.

32:20.660 --> 32:25.220
So let me go and copy this.

32:25.490 --> 32:29.810
The second container is the great Submission Portal health checker.

32:30.980 --> 32:39.530
This container is going to be created from the image our slim 087 slash Kubernetes course grade submission

32:39.530 --> 32:42.950
portal, health checker, uh, resources.

32:42.950 --> 32:44.210
We'll leave them the same.

32:44.210 --> 32:51.590
Now, this is not a web application, so we don't need to specify a container port.

32:51.590 --> 32:54.680
It's not going to be serving any traffic.

32:55.790 --> 33:02.540
All it's going to be doing is making requests to the great submission portal on its container port.

33:02.540 --> 33:06.320
5001 all right.

33:06.440 --> 33:08.540
That's really all we need.

33:08.570 --> 33:12.920
I'm going to go ahead and say kubectl apply dash f.

33:12.920 --> 33:21.530
We're going to reapply this pod definition and create a pod with two containers.

33:22.400 --> 33:26.870
Beautiful kubectl get pods.

33:27.980 --> 33:32.030
Now I've got one pod with two containers.

33:32.030 --> 33:39.450
Both of them are ready yet both containers are being created based on the images that we're pulling

33:39.450 --> 33:41.550
from my Docker Hub registry.

33:42.000 --> 33:42.810
Okay.

33:45.090 --> 33:50.160
Uh, let's say kubectl describe we'll describe the status of this pod.

33:51.480 --> 33:51.690
Oh.

33:51.720 --> 33:52.410
What am I doing.

33:52.440 --> 33:54.180
Kubectl describe pod.

33:54.210 --> 33:55.380
Great submission portal.

33:55.380 --> 34:02.820
So first as it says you specify the resource type followed by the name of that resource started container.

34:02.850 --> 34:03.720
Great submission portal.

34:03.720 --> 34:05.130
Health checker started container.

34:05.160 --> 34:06.240
Great submission portal.

34:06.270 --> 34:07.140
Beautiful.

34:07.140 --> 34:12.030
So if I say kubectl get pods again everything is working as it should.

34:12.030 --> 34:17.760
We have one pod running to containers inside of it.

34:17.940 --> 34:22.260
So what I'll do is on a separate terminal I'm going to clear.

34:22.890 --> 34:29.610
We don't need to port forward this port to a local machine port, because the great submission portal

34:29.640 --> 34:35.500
health checker is in the same pod as the Great submission Portal, and is going to be making internal

34:35.500 --> 34:39.490
requests to it via its local host.

34:39.520 --> 34:40.660
All right.

34:41.740 --> 34:53.140
So here what I'm going to do is say kubectl logs dash f here I want to view the logs or I want to stream

34:53.140 --> 34:53.650
the logs.

34:53.650 --> 34:59.320
Remember dash f allows us to stream the logs of a container in real time.

34:59.350 --> 35:06.280
Now remember before all we had to do was specify the pod and it would automatically stream the logs

35:06.280 --> 35:08.350
for the container that's running in it.

35:08.350 --> 35:10.600
But this time we've got two containers.

35:10.600 --> 35:16.210
So what we need to also do is specify the container for which we want to view the pods.

35:16.210 --> 35:22.270
In this case I want to view the pods for I want to view the logs for the container.

35:22.300 --> 35:26.620
Great submission portal this one right here.

35:26.620 --> 35:32.350
And you can see that our great submission portal health checker is already making all of these requests

35:32.350 --> 35:34.370
to its health end point.

35:34.700 --> 35:37.820
I programmed the great submission portal microservice.

35:37.850 --> 35:43.070
To output logs whenever requests are made to its endpoint.

35:43.070 --> 35:45.590
And these requests are working out really well.

35:45.620 --> 35:46.970
Status 200.

35:46.970 --> 35:53.360
So now what I'll do is I'll say kubectl logs dash f over here.

35:55.070 --> 35:56.870
Great submission portal.

35:56.870 --> 36:01.730
We want to view the logs for one of the containers inside of the Great Submission Portal pod.

36:01.790 --> 36:05.930
We want to view the logs for the great submission portal health checker.

36:07.400 --> 36:08.000
Okay.

36:08.000 --> 36:10.760
And you can see it keeps making requests.

36:10.760 --> 36:16.730
The sidecar keeps making requests to the Great Submission portal via localhost 5000 001.

36:16.760 --> 36:23.870
Those requests are always working, which confirms that our application, our great submission portal,

36:23.870 --> 36:25.070
is healthy.

36:25.190 --> 36:33.860
So you ever you only ever really want to run two containers in the same pod when the main container,

36:33.890 --> 36:41.840
the meat and potatoes of the pod, relies on additional behavior and functionality by a sidecar app.

36:41.840 --> 36:46.790
So this is the microservice because it forms a core component.

36:46.790 --> 36:51.110
It is a building block of the cloud native Great Submission app.

36:51.110 --> 36:58.040
And this is a sidecar application because all it does is it provides additional functionality for our

36:58.040 --> 37:00.260
great submission portal app.

37:00.290 --> 37:00.950
All right.

37:00.950 --> 37:02.600
So that's it.

37:02.690 --> 37:04.430
We've deployed a microservice.

37:04.460 --> 37:09.860
We've deployed a microservice with a sidecar alongside it.

37:09.980 --> 37:11.780
That's all we're going to cover for this video.

37:11.780 --> 37:16.460
And the next one we're just gonna it's just going to be pretty much extra practice.

37:16.460 --> 37:18.710
And we're going to go through things a lot faster.

37:19.040 --> 37:26.150
Uh, we're going to deploy the great submission API pod so that we can eventually have these two collaborate

37:26.150 --> 37:28.940
and give us the full, great submission experience.

37:28.940 --> 37:30.530
I'll see you in the next one.
