Welcome back everyone.
This section is very exciting because we are going to connect all of these applications to databases.
Before we start, go to containers.
Delete every container that you may already have running.
Delete every single image that you may already have in your local cache.
Delete.
Delete every single volume as well that you may have.
And once you're sure that you're off to a clean slate, let's begin.
Now, the first task I'm going to give you, you're going to probably hate me for it because it's a
bit tedious, and that is to build an image out of each Docker file inside of oh five starter projects.
Why are we rebuilding the images?
Well, because the source code for each API here is very different from the source code in oh three
starter projects.
All of these applications are now designed to connect to a database.
So when you're creating your images, uh, name each one according to your Docker Hub username, followed
by the service name, and tag each one as version 2.0.0.
All right.
The e-commerce UI code doesn't really change from section three, so you can just leave the tag as latest.
Pause the video until you have that set up.
All right.
Once you do, we're ready to begin.
So all of these applications except for the e-commerce UI, the e-commerce UI is stateless.
It's not connected to a database.
All it does is it communicates with all of these APIs which do persist data to databases, which means
that for each API, we need to create a volume.
Well, let me start by specifying a version of three.
Um, we'll specify a mapping for services.
But first we're going to define we're going to define 123456 named volumes one volume for each service.
So four of these services use MongoDB.
So we're going to define four MongoDB volumes.
The first one is going to be called MongoDB product catalog data.
Because if you look inside the product catalog API it relies on MongoDB.
Uh, so do the contact support API, as well as the shipping API and the order Management API.
So we're going to say MongoDB contact uh support data.
That's another volume we're going to create.
Another volume will create is MongoDB uh shipping data and MongoDB order management data.
All right.
Now we need to create two more volumes.
Um, the profile management API.
If you were to look into it it relies on MySQL.
So we're going to create a named volume called MySQL Profile Management.
And that's going to store all the MySQL data for profile management.
Why do I have a colon here.
And the last service uh I believe it's product inventory.
This one relies on PostgreSQL.
It does.
So here we'll define a named volume called Postgres Product Inventory data.
All right.
So all of these named volumes, named volumes are going to take up actual space inside of my computer.
The reason these are important is because when each database container persists its data, once we destroy
that container, we don't want that data to be erased.
We want it to be redirected to these volumes where they are more durable.
Okay.
Um, I want to start with MySQL.
So let's go ahead by creating a MySQL container for the Profile Management API.
What should I call the container?
I'm thinking of a name.
How about, um.
Well, under services we create a container called MySQL Profile Management.
That's going to be the name of the container.
The image from which we're going to create the container is MySQL version 8.0.
So if you were to look inside of Docker Hub, this is the official repo for the MySQL image.
You can find various versions of this image.
The one we're going to pull is specifically tagged 8.0.
This one right over here.
So let's pull MySQL version eight, the container name we're going to explicitly specify to be MySQL
profile management.
All right.
And um, now we're going to set up some environment variables.
Okay.
So when the MySQL container starts up and launches the MySQL app, it needs to give the MySQL instance
running inside of it the environment variables that it needs to properly initialize one of them.
Let's go to the environment variables section to see what we can pass into the app, so that it can
do what we want it to do.
One of them is MySQL database.
This variable is optional, but it allows us to specify the name of the database that we want MySQL
to create when it starts up.
So when the MySQL instance starts up within the container, we want the container to give it an environment
variable named MySQL database.
And that's going to tell the MySQL instance to start up a database called profile management.
All right.
The next environment variable we want to give the MySQL instance when it starts up is MySQL user and
MySQL password.
This basically tells MySQL the credentials that are needed in order to access the MySQL database that
we initialized in this step, so only users named profile user with a certain MySQL password equal to
a profile password are allowed to access the profile management database.
Now there's one more environment variable we need to pass in to the MySQL instance from the container
that runs it, and that's the MySQL root password.
The only reason I'm doing that is because this variable is mandatory.
We need to specify a password for the root superuser account.
So let's just go ahead and do it.
Get it out of the way.
We're just going to say root password.
All right.
We're not actually going to end up using the root uh user, the root super user.
But whatever we need to do this and I think no, we're not done yet.
The last thing we got to do is remember that, um, well, there's nothing to remember because I haven't
explained anything yet.
Uh, MySQL by default persists its data to slash var lib slash MySQL.
So this is the directory within the container where the MySQL instance is going to persist all the data.
By default, what we want to do is redirect any data that gets saved to slash var lib slash MySQL to
the named volume.
Um.
MySQL profile management data.
That way, if we ever destroy the container, all of the data that was saved here within the container
was redirected to the more durable named volume.
That's that is taking up actual space inside of our host machine.
All right.
Now finally, this is just information that we need for later.
MySQL by default runs on port 3306.
So uh, MySQL here, I can comment and say we'll run on container port 3306.
Do we want to map this container port to a host machine port?
No, because I don't anticipate that I'm going to be connecting to this MySQL app from my host machine.
The profile Management API is going to connect to it directly through the Docker network and use the
container port.
All right.
There's no reason to expose a host machine port if we don't need it.
Um, okay.
That's pretty much it.
Now we're ready to set up the, uh, profile management container.
What I want to do is copy the setup from this docker compose YAML, but instead of pulling version one
that we have pushed to Docker Hub, we're going to pull version two that we have stored locally in our
local Docker cache.
So this container is going to be created from the image that we just built, the image that's inside
of our local Docker cache.
We don't have this on Docker Hub yet.
We will later.
Um, everything here is fine, but now we need to provide, uh, the Profile Management API version
two with the environment variables that it needs in order to connect to MySQL.
Let's just copy this over into our Docker compose YAML.
And specify the environment variables.
We start with the host okay.
We're going to set this equal to the container MySQL profile management.
So the host environment variable is going to tell the profile management API where the application is
running.
Once we help it locate where the application is running then we need to tell it the port where the application
is serving requests.
The MySQL app runs on the container port 3306.
So at this point it found the container where the app is running.
It found the port where the application is serving requests.
And now the MySQL instance contains a profile management database.
That's the database that we need to connect to from our profile management application.
All right.
And the credentials needed to connect to that database are where set to be profile user.
And profile password.
Okay.
So now our authentication API has all the information that it needs to locate the MySQL instance, locate
which port it's serving requests on, authenticate against the database where we want to write and read
data.
And it's going to use all of this information to connect to my SQL.
This should work because both containers are running inside of the same network.
Let's try it out.
We're going to say docker compose up.
And you know what?
One other thing I could do is say depends on the profile management container.
Depends on the MySQL profile management container.
All right.
Um.
So after MySQL profile management is done initializing the database and all that, then the profile
management application is able to connect to it.
It tries to do so.
At first it fails, but I programmed the application to be resilient.
It connects to it eventually.
All right.
Now we're going to do the same thing for the PostgreSQL database.
So the application that's going to try to connect to a PostgreSQL database is product inventory which
means what I'm going to do is set up a container called Postgres Product Inventory.
And the image from which we're going to create this container.
Um.
You know what?
Let's just say Postgres latest.
Why not?
All right.
I don't have a specific version in mind.
Container name.
Postgres product inventory.
All right.
And now we need to specify the environment variables that the container needs to pass into its underlying
Postgres application so that it can initialize a database and also set up the credentials needed to
authenticate against that database by whatever service tries to connect to it.
Okay, so, uh, obviously I'm not a magician.
I can't predict what these environment variables are.
I need to go to the documentation just like you.
So let's go to the environment variables.
Um, one of these here we see Postgres user Postgres uh db and postgrespassword.
We've got all the information we need to start setting this up.
So back inside of my Postgres product inventory container, I'm going to pass uh, three environment
variables into uh, the underlying app.
So Postgres db let me just copy it over.
We want, uh, the Postgres instance to initialize a database called product inventory.
All right.
And the credentials needed to authenticate against that database, the Postgres user will be inventory
user.
So anyone that has a user of inventory user and a password.
Of inventory password will be able to access the database successfully.
All right.
Now we need to redirect, um, the path in the container where the data is saved to a named volume.
So if I go here and say slash var the default path where data is going to be saved within the container.
Within the Postgres container is the following.
For durability, we need to redirect the data that gets saved here to the named volume.
Postgres product inventory data.
All right.
And now, by default, uh, PostgreSQL runs on the port to seven something.
Um, PostgreSQL port.
We're going to need this information.
Never mind.
It's port 5432.
So PostgreSQL is going to run on port 5432.
All right.
So now what I can do is set up the service that will actually interact with this with this database.
And that's going to be uh product inventory.
So let's go to this docker-compose.yaml.
Copy over the following again make sure the spacing is consistent.
So this should be at the level of services.
All right.
We want to pull product inventory version 2.0.0.
The image that we just built that's in our local Docker cache.
And we want to give the updated product inventory version two with a bunch of environment variables.
What will these variables be?
The following.
These are the variables that our application is going to rely on in order to establish connection with
a PostgreSQL database.
So let's go ahead and temporarily copy these variables over here for reference.
Um.
The first variable is Postgres host the host.
Once we pass it into the underlying app, it's going to help it locate the container where PostgreSQL
is running.
That container is called Postgres product inventory.
All right, the port tells our Product inventory API.
Once it locates the container that the app is running in.
Now, it needs to know the port in the container where Postgres is serving requests.
That's port 5432.
I was able to determine that by googling it.
Um, next we specify the database that we want to connect to within our PostgreSQL instance.
That database is called product inventory.
This was the database that was initialized within PostgreSQL.
Now I need to specify the credentials needed to authenticate against that database, and therefore be
able to save data to it.
Those were set to be inventory user as well as inventory password.
All right.
And now I've given my product inventory application all of the information that it needs to connect
to this PostgreSQL instance PostgreSQL instance and be able to authenticate against its database.
So I'm going to stop the runtime.
Control C then say docker compose down to make sure things get fully removed.
Then I'm going to rerun.
Docker.
Uh, before I do that let me just say here it depends on Postgres product inventory.
Okay.
Let me make sure everything's good.
Everything is fine.
All right.
Famous last words.
Docker compose up.
So the profile management service was able to connect to my SQL.
What about the product inventory service?
Was it able to connect to PostgreSQL?
Um, I don't see any error messages if you do.
By the way, I programmed the application to retry connecting to it every five seconds.
So if you see a failed message, as long as that failed message doesn't persist or it doesn't keep printing,
that means your product inventory app was successfully connected to Postgres.
But if you keep saying failed, retrying retrying in five seconds, if that keeps printing, that means
it didn't connect.
But I don't see anything.
So we're good.
As the programmer of this application, I think we're all good.
Profile management struggled a bit at first, but then it was able to connect.
All right.
And now what I'm going to do is do all of these applications at once.
Product catalog support, shipping and order management.
Okay.
I'm going to go ahead and start by creating the MongoDB instance that will be responsible for storing
data for the order management microservice that's going to this container is going to be created from
the image Mongo.
I won't specify a version.
Let's just use the latest one container name Mongo DB order management.
All right.
Um, I don't want to specify.
I don't want to map the container port to a host machine port, but just know that the MongoDB instance
that's going to be running within this container will use.
Container port
27017, I believe.
Um, let me just validate this.
Yep.
All right.
And here we can just say volumes.
We're not going to need to set any environment variables in Mongo.
Our apps are going to be able to connect to it fairly seamlessly by virtue of just providing a host
and a port.
We could set up authentication and all that within Mongo, but since we're not obliged, we're not going
to do it.
So anyways, in, uh, Mongo by default is going to save its data to slash data slash DB.
We're just going to redirect all that data to, um, this named volume mongo DB order management data.
Let me make sure I got it correctly.
I did.
All right.
Now we connect the order management application to this to, uh, the MongoDB instance running inside
of this container.
So we'll go back to the docker-compose.yaml over here.
Copy the following.
But make sure that we're pulling version two that we just recently built in this video.
And now if you were to look inside the Order Management API, uh, the only other, the only environment
variables that it needs, the only environment variable that it needs in order to connect to, uh,
MongoDB is the following.
But what we're going to have to do is set this equal to the scheme MongoDB followed by slash slash the
container name MongoDB order management.
So the host is always the container name because that's where the app is running.
The host allows you to find where the app is running.
The port where the app is serving requests within this container is 27017.
And then we say slash.
That's going to be order management basically telling it connect to a database called order management.
All right.
And finally here we say depends on the MongoDB order management service.
All right.
Um I think we're good for order management.
Let's go ahead and try it out.
Docker compose down.
Docker compose up.
Oh, um, I think the image for order management is doesn't actually install the dependencies inside
the image, so it does it during the runtime.
Um, whatever.
It's okay.
We can wait a little bit.
But our Spring Boot app, as you can see, is able to connect to the MongoDB application.
This environment variable here overrode the following property.
We set this property equal to the following connection, which means our Spring Boot app is able to
connect to the Mongo application inside this container at that port, and will read and write to a database
called Order Management.
Beautiful.
Did we do the product catalog yet?
We didn't.
Okay.
What I'm going to do.
Is set up a MongoDB container for the product catalog.
So.
We'll say MongoDB product catalog.
This container will be created from the Mongo image that's going to run a mongo application.
The container that will run the application is MongoDB product catalog.
Um, the volume.
Is MongoDB product catalog data.
And what that's going to do is, Um, so all the data from Mongo is going to be saved to this path in
the container.
We want to redirect it to the named volume MongoDB product catalog data.
All right.
And if we look at the product catalog itself, it expects two environment variables.
So it expects a MongoDB host and a MongoDB port.
So depending on the application and how it expects to receive the environment variables, you need to
modify your docker-compose.yaml.
So for the Spring Boot app, it expected an environment variable that has the entire URL.
In this application it expects two environment variables a host and a port, and it's going to embed
those into its URL that it already made.
But regardless of the application, the URL is always the same MongoDB followed by a host followed by
a port.
And it also expects the database name that it will read and write data to.
All right.
Um, so here what we can do is say, um, well, we're going to copy over.
The product catalog container definition from the previous Docker compose file.
Make sure to, uh, fix the spacing so that this is at the level of services we want to pull, version
two, the one we just built.
And then we provide the environment variables that the app needs in order to connect.
To Mongo.
So these are the variables.
Let's just copy them over here for reference.
So it relies on a variable called Mongo host, which is going to be the container where Mongo is running.
Once the app is able to locate the container where the Mongo app is running, then we give it the port
within that container where it's going to be serving requests.
Mongo by default serves requests on the container port to 7017.
And then the MongoDB database that we're going to try connecting to, we can actually create any database
that we want.
And the JavaScript application is going to use that information to connect to a database.
Let's just call it product catalog.
So MongoDB is flexible enough to create this database if it doesn't already exist, if the app tries
accessing it.
All right.
Um, that's the last one I'm going to do the last.
The rest I'm going to leave up to you.
But I will show you what the code should look like.
Docker compose down.
Docker compose up.
I really wish this image.
Um.
Pulled the dependencies during the image building phase, not during container runtime, but whatever.
It's the last lesson.
It doesn't matter.
We can wait a bit.
It seems like everything was able to successfully connect to their respective databases.
Let me make sure the product catalog one did as well.
Product catalog connected to MongoDB.
Perfect.
All right, so I believe there are two more databases you need to create alongside two applications
that need to connect to those databases.
So your task.
This is actually good for you to challenge yourself.
Your task is going to be to create those two MongoDB containers.
All right.
And then you're going to look inside of the two applications that need to connect to the MongoDB containers.
Look at the environment variables that the applications rely on so that it connects to a certain database.
Uh, set that up.
Pause the video.
Once you're done.
Um, I'll show you the solution.
Okay.
All right.
So here is what I came up with.
Um, contact support relied on three environment variables.
If you were to look inside the application and then shipping and handling only relied on one environment.
Variables that defines the scheme, the host and the port.
You'll notice if you went inside the code that it already defines that it wants to connect to or create
in this case, upon connecting to Mongo.
So you only need it to define the host and the port.
That database was already hard coded, so it's just extra practice for you to actually look inside the
code base and make sense of what it needs and what you need to provide from your container.
So that's it for shipping and handling MongoDB shipping.
We have all of our applications connected to the databases that they need to connect to.
We have everything being backed up into volumes.
Uh, the last service that remains unchanged is the e-commerce UI.
So let's put that over here.
And that's it.
We should now be ready to.
I think we're done, guys.
Uh, product catalog depends on MongoDB product catalog.
Order management depends on MongoDB.
Order management.
Product inventory depends on the following.
All right, let's do it.
Docker compose down ecommerce UI depends on an undefined service contact support team.
So this is contact support team.
This is contact support.
My apologies.
Like I said things never work out from the get go.
It is what it is.
Make sure the volumes are right.
We're good.
Now that pesky spring boot up clock cluttering up all of our logs.
Uh, feel free to take it upon yourself to change this Docker file so that it installs the dependencies
during the image building phase.
That way, the spring boot run command doesn't need to do it as the container, uh, during the containers
runtime.
All right.
So I didn't see any errors while all of this was happening.
I believe everything should have been started up correctly.
There is only one way to test this, which is by going over to localhost 4000.
All right.
Fingers crossed.
We're going to log out and we're going to create an account.
We'll say Bob.
Bill, address 123 private road postal code B1B b2b email bill gmail.com.
Password.
Love.
All right.
Beautiful.
So authentication works.
Um, if it didn't, um, if it showed a failure, that means it had a problem in connecting to its database.
Um, a sign in.
Product catalog.
Everything works.
Shipping.
Everything works.
Profile management.
We already saw that.
That worked.
Subject.
Um.
Trouble?
Trouble buying a backpack?
Submit.
Everything works.
Inventory management.
Beautiful.
Uh, let's try ordering a product at the cart.
Amazing.
Okay, um, we're pretty much done, guys.
Uh, the last thing that I want you to do Docker compose down.
So we have all of these Docker images.
Um, we have Mongo, MySQL and Postgres as well.
Ignore these.
I want you to push all of these over to Docker Hub.
Okay.
Once you do I want you to paste in the updated Readme to each repository.
Overview.
The updated Readme should include a section for the version 2.0.0 update.
All right.
Once you push version two, I want you to rebuild all of these images and tag them as latest, and then
push those onto Docker Hub as well.
So each one of your services should have a version of one where everything happens in memory.
A version of two where, uh, the app is actually connected to a database, and a version of latest,
which is effectively version two.
Once you have all of that set up, congratulations on being able to containerize a fully loaded e-commerce
application whereby each microservice is running alongside a database.
We have a flask microservice, we have NodeJS microservices, we have a spring boot microservice, a
go microservice, all of them connected to different types of databases Mongo, Postgres, MySQL.
We've done a lot with Docker in this course.
I hope you're proud of yourself, and I hope you were able to take a lot from this lesson.
I should be creating a Kubernetes course in the next month or two, so look out for that.
And, uh, thank you so much for taking this course and trusting me with your education.
I'll see you in the next one.