WEBVTT

00:00.020 --> 00:06.170
Okay, so we're ready to start actually creating additional microservices, in this case, the authentication

00:06.170 --> 00:07.330
microservice.

00:07.340 --> 00:14.420
However, before we go ahead and do that, I want to actually start Dockerizing our existing reservations

00:14.420 --> 00:15.440
application.

00:15.440 --> 00:20.870
And the reason for this is because when we have to run multiple applications at once, I want to take

00:20.870 --> 00:26.300
advantage of Docker compose to be able to run multiple images at once.

00:26.300 --> 00:29.930
So let's go ahead and get started in Dockerizing our application.

00:29.930 --> 00:32.000
So this is a pretty straightforward process.

00:32.000 --> 00:35.930
Of course you need to make sure you have Docker installed on your machine.

00:35.930 --> 00:41.090
You of course need to make sure you have Docker installed on your machine, which of course I'll have

00:41.090 --> 00:45.350
a separate video going over how to set up and install.

00:45.350 --> 00:51.620
Assuming you have Docker already set up, I'm going to go into the reservations folder and in the root

00:51.620 --> 00:56.630
folder I'm going to create a new file here called a Docker file.

00:56.630 --> 01:04.740
Docker file is responsible for the instruct Asians on how to actually build the application.

01:04.740 --> 01:07.050
You can think of it almost as like a template.

01:07.050 --> 01:13.230
So we're going to provide the template for how to build the application and actually create the container

01:13.230 --> 01:15.240
that we want to run.

01:15.240 --> 01:21.840
So in Docker we can actually extend pre-existing images using the from keyword.

01:21.840 --> 01:24.840
So this is going to be the base image we want to extend from.

01:24.840 --> 01:32.820
So I want to use the Node Alpine image, which is a base alpine image that already has node inside of

01:32.820 --> 01:36.090
it and which of course we're going to need to run our application.

01:36.270 --> 01:43.380
So I'm going to label this base image development because we're going to break up the stages of this

01:43.410 --> 01:45.240
image into two different stages.

01:45.240 --> 01:47.010
The first will be development.

01:47.100 --> 01:53.880
Next, I'm going to set the working directory for our container to be in the user source app directory.

01:53.910 --> 02:02.070
Next, we're going to use the copy command here to copy our package.json into the working directory.

02:02.070 --> 02:08.490
So after we specify the working directory here, you can see here all the subsequent commands that we

02:08.490 --> 02:10.950
run will be run in this directory.

02:10.950 --> 02:14.130
So this directory here is our working directory.

02:14.130 --> 02:16.410
So we copy the package.json.

02:16.410 --> 02:25.560
Let's also copy the npm loc yaml and then I'm going to run a command here to actually install NPM.

02:25.560 --> 02:33.930
So we'll use NPM to install pmpm globally and then we can actually run npm install here.

02:33.930 --> 02:36.240
So that will install all of our dependencies.

02:36.240 --> 02:42.480
After installing all the dependencies we need to build the application, we're going to actually copy

02:42.480 --> 02:51.750
over our whole app into the root of our Docker container and then we can finally run here, NPM run

02:51.750 --> 02:58.830
build, which of course we know will execute the nest build command here to actually build our app with

02:58.830 --> 03:00.450
all of our dependencies.

03:00.450 --> 03:05.700
So after we've done that, we're going to move on to the next stage of our Docker image.

03:05.700 --> 03:11.850
So to do that we'll do the same from command here to extend the Node Alpine image and we'll label this

03:11.850 --> 03:13.860
the production image.

03:13.920 --> 03:21.630
And importantly, we're going to set an argument here where the node env is equal to production and

03:21.630 --> 03:27.450
the ARG keyword here is going to allow us to specify this as a variable that we can override at build

03:27.480 --> 03:30.900
time if we want to with a default value.

03:30.900 --> 03:33.240
So by default this will be production here.

03:33.240 --> 03:37.440
And then what we're going to do is expose this as an actual environment variable.

03:37.440 --> 03:43.650
So we'll do node N is equal to the node variable we just created right here.

03:43.860 --> 03:49.380
So if node env is production here, we're going to make sure that we build this in a production environment,

03:49.380 --> 03:55.410
which is important to get some runtime optimizations in Node, we'll have to again specify our working

03:55.410 --> 04:04.430
directory as the user source app folder and then we will, as we've done before, copy our Package.json

04:04.430 --> 04:06.050
and the NPM lock.

04:06.050 --> 04:09.470
We'll then actually install NPM again.

04:09.470 --> 04:13.670
And then importantly here we will run NPM install with the.

04:14.430 --> 04:21.870
Prod flag and the prod flag makes sure we only install dependencies specified here and not the development

04:21.870 --> 04:25.920
dependencies, which is going to make this production image much lighter.

04:25.920 --> 04:31.020
Then we're going to run this copy command where we specify the stage we want to copy from.

04:31.020 --> 04:32.430
In this case development.

04:32.430 --> 04:38.970
I want to copy from our development stage up here, specify that I want to copy in that user source

04:38.970 --> 04:40.620
app dist folder.

04:40.620 --> 04:43.470
I want to copy that to our dist folder.

04:43.470 --> 04:50.610
So in this first stage here, when we run NPM build, it's going to build our app to the dist directory

04:50.610 --> 04:53.190
here using the development dependencies.

04:53.190 --> 04:58.950
And then we want to take that app and put it into our production stage which doesn't have the development

04:58.950 --> 05:01.620
dependencies and plop it in the dist folder.

05:01.620 --> 05:08.280
So then we can finally run our command here to actually execute the running container.

05:08.280 --> 05:14.470
So in this case we know we're going to execute Node and specify the path to our application.

05:14.470 --> 05:18.940
In this case we know it's the dist folder because we just copied in the dist folder.

05:18.940 --> 05:27.310
We're going to go inside of the apps reservations and then look for the main file and we can see this

05:27.310 --> 05:29.110
outside of a Docker container.

05:29.110 --> 05:35.620
If we want to run NPM run, build right now to actually just build our reservations app.

05:35.620 --> 05:38.760
We should see in the dist folder here this same path, right?

05:38.770 --> 05:42.820
Dist apps, reservations main.js.

05:42.820 --> 05:45.850
And this is our compiled main.js.

05:45.850 --> 05:52.510
So importantly, when we copy over everything here in this stage of the Docker image, we don't want

05:52.510 --> 05:54.730
to copy over our node modules.

05:54.730 --> 06:02.560
So in order to accomplish this we'll create a docker ignore in the root of our folder here and specify

06:02.560 --> 06:05.560
we don't want to copy over the node modules folder.

06:05.560 --> 06:11.140
So now we're ready to actually test out this Docker image, go back inside of our terminal.

06:11.140 --> 06:18.520
So in my terminal here, I'm going to CD into the apps folder and then CD into the reservations folder

06:18.520 --> 06:20.920
where we actually have the Docker file.

06:20.920 --> 06:27.640
So to actually build this, we're going to run Docker build and then I'm going to specify the actual

06:27.640 --> 06:30.880
context of where I want this build to run from.

06:30.880 --> 06:36.340
And if you recall, I want to actually run it from the root of our project so that we can copy over

06:36.340 --> 06:41.860
important files like the Libs directory, the TS config and so on.

06:41.860 --> 06:48.730
So we can just specify the context path right here where we want to execute it from and then we'll specify

06:48.730 --> 06:54.430
the actual Docker file with the dash F, which in this case is in the current directory.

06:54.460 --> 07:00.250
Finally, we'll specify a tag and I'll call this sleeper underscore reservations.

07:00.250 --> 07:02.980
So we'll go ahead and let this Docker image build.

07:02.980 --> 07:09.580
So after our Docker image has finished building, we can actually test it out by running Docker Run

07:09.580 --> 07:11.830
and then provide the name of the tag.

07:11.830 --> 07:16.300
We just created Sleeper Reservations, so this will run the Docker container.

07:16.300 --> 07:23.020
And now we can see here when our app starts up, of course we're failing because the MongoDB URI is

07:23.020 --> 07:25.540
not specified as an environment variable.

07:25.570 --> 07:28.630
However, we can see the app actually starting up, which is great.

07:28.630 --> 07:35.230
So now that we have this Docker image actually building, how do we actually run it and specify environment

07:35.230 --> 07:35.920
variables?

07:35.920 --> 07:38.500
Well, we can use Docker compose for that.

07:38.500 --> 07:44.440
So Docker compose is just another CLI tool that will allow us to run our Docker containers in a nice,

07:44.440 --> 07:50.290
well known format and allow us to specify environment variables and other configuration.

07:50.290 --> 07:52.060
So let's see how this works.

07:52.060 --> 07:57.640
We'll specify a docker-compose.yaml in the root of our project here, and then we're going to start

07:57.640 --> 08:01.150
off by creating a new services key here.

08:01.150 --> 08:05.050
And this is where we specify the containers we want to run.

08:05.050 --> 08:10.810
So of course, the first one we want to run here is our reservations container that we just created.

08:10.810 --> 08:13.990
Now this is going to have a build key here.

08:14.080 --> 08:14.470
Okay.

08:14.470 --> 08:18.670
Now inside of here, we're going to specify a bit of information.

08:18.670 --> 08:25.120
Firstly, the context, which if you remember from when we ran on the CLI is essentially where we want

08:25.120 --> 08:27.460
to run the Docker build from.

08:27.460 --> 08:29.800
So we'll specify the context here.

08:29.800 --> 08:35.140
And in this case, well we're already in the root of the project, so we'll just keep the context at

08:35.140 --> 08:35.530
the root.

08:35.530 --> 08:38.740
Then I'll specify the path to the Docker file.

08:38.740 --> 08:44.860
And of course, you know, this will be in the apps folder in the reservations folder and then just

08:44.860 --> 08:46.120
the Docker file there.

08:46.160 --> 08:52.270
Now importantly, we can specify the target on the Docker file that we actually want to run.

08:52.270 --> 08:53.440
So what do I mean by this?

08:53.440 --> 08:57.100
Well, if we look at the Docker file, remember we have two different stages here.

08:57.100 --> 09:00.190
We have the development stage and the production stage.

09:00.190 --> 09:06.790
And so I want to run the image from the development stage here so that we have all of the development

09:06.790 --> 09:11.170
dependencies we need when we are actually developing the app.

09:11.170 --> 09:13.930
So to do this, all we have to do is specify the.

09:14.040 --> 09:16.020
Target here, which is the target stage.

09:16.020 --> 09:17.820
In our case, it will be development.

09:17.850 --> 09:24.630
Next, we can specify a command here which will be the command to actually run the container.

09:24.630 --> 09:32.790
So in our case, instead of running the default command of running this dist main file, I want to actually

09:32.790 --> 09:36.690
override that and I want to have that hot reloading we're used to.

09:36.690 --> 09:38.490
So we're going to run P.

09:38.520 --> 09:46.290
NPM run start dev and then we're going to specify the name of the application because eventually we're

09:46.290 --> 09:49.860
going to have multiple apps and we need to specify the name of the app.

09:49.860 --> 09:52.230
So in this case it will be reservations.

09:52.230 --> 09:54.720
And so now we will get that hot reloading.

09:54.720 --> 09:59.250
Now also make sure that this command here is not in the build context.

09:59.250 --> 10:01.590
So this is actually going to be outside of the build.

10:01.590 --> 10:07.140
Now, we're also going to go ahead and specify a port section here just to specify that we know we're

10:07.140 --> 10:12.600
going to be exposing Port 3000 and that's going to map to 3000 on our host machine.

10:12.780 --> 10:19.360
And then importantly, we need to specify a volume section here and we need to specify that we want

10:19.360 --> 10:29.260
to create a new volume that mounts the entire project in our local machine to the user source app directory

10:29.260 --> 10:36.310
inside of the container so that when we make changes to our application here, it gets reflected and

10:36.310 --> 10:38.500
overridden inside of the running container.

10:38.500 --> 10:44.980
We can test this out by running Docker compose up, which will build and create our container as well

10:44.980 --> 10:47.950
as attach to the running container here.

10:47.950 --> 10:51.010
So you should see the app start up here, which is great.

10:51.010 --> 10:58.120
And we can actually test to make sure that it will still hot reload if we go into our main.ts for reservations

10:58.120 --> 11:03.280
and just put a console log statement in here, just write test.

11:03.310 --> 11:07.900
We should see that the application restarts and we see our test message here.

11:07.900 --> 11:12.430
So if we wait a few seconds, we can obviously see that we're having trouble connecting to the database

11:12.430 --> 11:18.310
now because the Docker container isn't going to be able to access MongoDB, which is running locally

11:18.310 --> 11:19.420
on our machine.

11:19.420 --> 11:25.540
Instead, what we need to do is create a new Docker image that runs Mongo and then we can connect our

11:25.540 --> 11:27.700
running app to that mongo image.

11:27.700 --> 11:28.870
So let's go back here.

11:28.870 --> 11:34.480
I've gotten rid of that console dot log statement and firstly, let's also just update our Docker ignore

11:34.480 --> 11:41.560
here to also make sure we ignore our disk directory so we're not copying over any pre-built dist folder

11:41.560 --> 11:42.070
here.

11:42.070 --> 11:48.520
And we now need to go to our Docker compose and add a new service and this will be the Mongo service.

11:48.520 --> 11:54.580
So we're going to have a new Mongo service here and for the image we can just use the official mongo

11:54.580 --> 11:57.520
image that's hosted on Docker Hub.

11:57.550 --> 11:58.660
That's all we need.

11:58.660 --> 12:04.810
Now if we go back to our terminal and if we want, we can also tear down our containers by running Docker

12:04.810 --> 12:06.040
compose down.

12:06.220 --> 12:08.050
However, we don't really need to do that.

12:08.050 --> 12:13.660
We can just run Docker, compose up again and now we can see that we're actually pulling this Mongo

12:13.660 --> 12:14.440
image.

12:14.440 --> 12:21.010
And so now after we start up, we should see a new mongo container with its logs alongside with our

12:21.010 --> 12:23.620
reservations container, which is great.

12:23.650 --> 12:29.530
However, we're still pointing at our old MongoDB URI in our dot m file.

12:29.530 --> 12:31.180
So let's go ahead and change that.

12:31.180 --> 12:37.900
Instead of pointing to our local host here, what we need to do is actually change the host name here

12:37.900 --> 12:40.570
out for the name of the service.

12:40.570 --> 12:43.780
So of course we specify this name here, Mongo.

12:43.780 --> 12:49.630
And so networking in Docker, these containers can talk to each other by the name of the service.

12:49.630 --> 12:51.550
In this case it's going to be Mongo.

12:51.550 --> 12:59.050
So we just need to talk to Mongo here still at Port 27017 and the same database.

12:59.050 --> 13:08.290
So now if we restart our containers and bring them back up, we should see that the reservations application

13:08.290 --> 13:14.950
fully starts up and we can see the nest application has successfully started, which is great to see.

13:14.950 --> 13:22.330
And of course we can also see our mongo logs alongside with it specifying that a new client was connected.

13:22.330 --> 13:29.230
So we have our application fully running alongside with a MongoDB container in Docker, which is great.

13:29.260 --> 13:35.410
We are fully ready to start creating additional microservices and allow them to be running alongside.
