Following Docker best practices, each container should have only one responsibility, that’s why we usually have different containers in a project. But how can all these containers be connected and communicate with each other or use services outside the Docker? The answer for this question is a feature called networking.
Scenario overview
All examples in this article will be based on the following example: a Node JS application that needs to create, read, update and delete data (CRUD) from a Mongo database (but can be applied to any type of language and services as the main idea here is to demonstrate how we can have different but connected containers).
So, let's imagine we have a Node JS file that has methods for managing data from a Mongo database. In this file we also need to connect to the database to be able to execute all these methods.
In this scenario we will have two containers:
- a container to run the Node JS application (which contains all the methods mentioned above and also the connection to the database)
- another container to run Mongo db
Next, we will focus on connecting to the Mongo database as this is the most important part of this article.
Connecting different containers using network
“You can create custom, user-defined networks, and connect multiple containers to the same network. Once connected to a user-defined network, containers can communicate with each other using container IP addresses or container names.” - Docker docs
At this point you should know how to run containers via command line. I have an article called “How to use Docker Images, Containers and Volumes” where you can learn about it in details.
1- Creating networks
The first step is to create a network to connect the containers.
docker network create [network_name]
Example:
docker network create my_app_net
2- Running Mongo db container connected to the created network
Now it’s time to run the Mongo db container via command line and connect it to the network.
docker run -d --network my_app_net --name mongo_db mongo
Where my_app_net
is the network created above, mongo_database
is the name of this container, and mongo
is the name of the image this container is based on. The container name is important because we will use it in the next step.
3- Connecting to Mongo db container from Node JS file
As I mentioned in the Scenario Overview section, let's imagine here that we have a Node JS file that needs to connect to the Mongo database container created in the previous step. Then we can have the following code:
mongoose.connect(
'mongodb://mongo_db:27017/my_database_name',
…
);
Where mongo_db
is the name of the container created in the previous step and 27017
is just the port provided by Mongo (you can read more about this in its documentation). In a non-Docker solution, when we install Mongo on our host machine, mongo_db
would be localhost
or an IP address - in this case, it is the name of the container that contains the database we want to connect to.
4- Running Node JS container connected to the Mongo db container
Once we have the Mongo db container running - and the database connection in the Node JS file is already configured to connect to this container - all we need to do now is start this Node JS container using the same network as the Mongo container uses.
docker run -d --rm -p 3000:3000 --network my_app_net --name my_app my_node_img
Where my_app_net
is the above created network, my_app
is the name of this container and my_node_img
is the name of the image which this container is based on.
And that’s all. Now you know how to connect containers using Docker container networking. :)
You can read more about networking in the Docker documentation.
Connecting containers to services installed on our host machine
When we want to connect to a service installed on our host machine from a Docker container, we have a different way of doing it.
Now, let's imagine we have a Mongo database installed on our host machine instead of a container. When started, this service exposes a port that can be accessed using: //localhost:27017/my_database_name
.
In order to have this url working fine inside the container, and be able to execute CRUD on the db, we should replace localhost
to host.docker.internal
. This special domain will be understood by Docker and be translated to the IP address of our host machine as seen inside Docker container. So it will be something like:
mongoose.connect(
'mongodb://host.docker.internal:27017/my_database_name',
...
);
Read more about this special Docker DNS name here.
Conclusion
As we learned, communication between containers is easier to implement using the Docker network, so all we need to do is create a network and use it to run all the containers that must be connected.
We also saw that we can also use special Docker DNS names to connect services outside of Docker from our containers.
I hope you liked it. See you next time! 😁