This is the fourth post in my series about Docker. You needn't have gone through the previous one in order to understand this. The only prerequisite is that you have an idea about what Docker containers are. If you don't I suggest you take a look at the second post.
In this post, I'm going to explain to you how you can make the app running in your container communicate with other services (APIs, databases) outside of that particular container. Now when we talk of these services which are running outside of the container we can divide them into three categories:
Running on the World Wide Web. Like a public API (for example, SWAPI)
Running locally on your machine. (for example, a database instance running locally)
Running in another container. (for example, a database instance running in another container)
Let us have a look at each of these cases separately.
Running On The World Wide Web
Guess what? You'll face absolutely no problem here. If the code in your container makes a call to some outside API then it will face no problem and will work perfectly like it would have had you not containerized it :)
Running Locally On Your Machine
If you're running a service, let's say a database locally, and want your containerized app to interact with it then you just have to make one simple change in your code.
The service you'd be running locally would have a URL something like:
localhost:8000/service
for connection. All you have to do in your code to get this to work is to replace localhost
with host.docker.internal
. So:
'host.docker.internal:8000/service
This works because host.docker.internal
is a special address that automatically gets translated to the correct address of the host machine by Docker.
Running In Another Container
This is a little complex than the other two (which shouldn't be a surprise :P ). But I'll try to explain it in as simple terms as possible.
The basic idea is that whenever you want two or more containers to be able to "communicate" with each other you put them in the same "network". A Docker Network is something you'll create before starting either of the containers, using this command:
docker network create dummy_name
This will create a network by the name of dummy_name
. Now you will specify this network while starting all the containers you want should be able to communicate with each other.
There is one other small change which you will have to make. You remember how in the second case we replaced the localhost
with host.docker.internal
? Similarly here we will replace that with the name of the container we want to access.
For example:
docker run -network dummy_name --name appCode image-one
docker run -network dummy_name --name dbInstance image-two
If I plan to do this then we will need to change localhost
in the code (from which we built image-one) like this:
dbInstance:8000/service
Docker would automatically now understand this since the two containers are part of the same network. If it's getting a bit complicated let me sum it up:
- Create a network
- If container A needs to talk to Container B then in the code of container A, replace localhost with Container B's name.
- Start the containers with the correct names and do not forget to specify the same network while starting then.
And with this, you're now good to go!
Conclusion
This solves all our problems related to networking while using containers. I hope you now have a pretty good understanding of this and will feel confident enough to use it.
Thanks for reading! :)
If you have any feedback for me or just want to talk feel free to connect with me on Twitter. I'll be more than happy to help you out! :D
Top comments (4)
How can I get rid of the port, so I can call the service like this
host.docker.internal/service
instead of this
host.docker.internal:8000/service
I think the example I used might have been a bit unclear. The service you'd be using would have a port for it on the localhost. For example let's say your backend is running at
localhost:3000
. Then you can usehost.docker.internal:3000
in the code present in your container.What I mean to say is that the serivce would be running at a port on localhost so you would have to necessarily specify the port while using
host.docker.internal
. The/serivce
I used might be a bit confusing cause it is the service it self which is actually running onlocalhost:8000
and not onlocalhost:8000/service
.I understood, but what I meant is how can we get rid the port
The default port is 80. If you can get your service to run on that then you would simply be able to use
host.docker.internal
. Otherwise I don't think so you can get by without specifying the port since your service operates on a specific port itself.