How to resolve 'Connection reset by peer' or 'Connection closed by foreign host' when connecting to a Docker container?
1. Purpose
In this post, I will demonstrate how to resolve connection errors when connecting to a Docker container.
2. Environment
- Docker Server Version: 20.10.2
- Kernel Version: 4.15.0-128-generic
- Operating System: Ubuntu 18.04.5 LTS
- OSType: Linux
- Architecture: x86_64
3. The Code and the Problem
3.1 The RESTful Web Service Inside the Container
I am developing a simple Flask web service (RESTful) for testing purposes. This small app does the following:
- Exposes a web service on port 8080
- When accessed at
http://localhost:8080
, it returns a “hello world” JSON response.
The core code is as follows:
If you don’t know flask-restful, here is the simple introduction:
Flask-RESTful is an extension for Flask that adds support for quickly building REST APIs. It is a lightweight abstraction that works with your existing ORM/libraries. Flask-RESTful encourages best practices with minimal setup. If you are familiar with Flask, Flask-RESTful should be easy to pick up.
Just install it as follows:
More information about flask-restful can be found here.
When I run it as follows:
I got this result, it indicates that the app is running.
Then we test the service via curl command:
we got this:
3.2 The Dockerfile
Now I want to package the app as a docker image, and then run it as a docker container, so I must write a dockerfile to construct the docker image.
First, we define a file named requirements.txt to define the dependency requirements for pip command , which would be used inside the container.
requirements.txt
Dockerfile
In the above Dockerfile, we have done these steps:
- This docker image is based on python:3.6-buster, which is an offical python image
- The ‘WORKDIR’ defines our working directory inside the docker container, docker would create a directory named /app inside the docker container, and all the files copied would be put to this directory
- Then we copy the requirements.txt and do the ‘pip install -r …’ to install the python dependencies for the app, the ‘-r’ option of pip is explained as follows:
- Then we copy the app1.py to our working directory
- At last, we execute the python command to start our application
3.3 Build and run the docker image
Run the ‘docker build ’ command in the project’s root directory:
The above command build a docker image named ‘app1’.
Then we run the docker image :
The above docker command runs the image ‘app1’, create a container named ‘app1’, exported the network port 8080 to host port 8080.
3.4 The connection problem
After running the docker container, we can verify it’s running:
Check the logs of the service inside the container:
Now we use ‘curl’ to connect to the docker container:
We get this error or exception:
Or if we try to telnet the service’s port, we get this :
Why did this happen? I think it should run, but it does not work!
4. Debug
I am suspecting that the docker network caused the problem, so I’d like to change the docker network to ‘host’ , by default, docker use the ‘bridge’ network :
bridge
: The default network driver. If you don’t specify a driver, this is the type of network you are creating. Bridge networks are usually used when your applications run in standalone containers that need to communicate. See bridge networks.host
: For standalone containers, remove network isolation between the container and the Docker host, and use the host’s networking directly. See use the host network.
If we switch to ‘host’ network, the service is bound to the host’s network interface directly.
4.1 Stop the old container
We stop the old container as follows:
4.2 Start the docker container with network host
4.3 Test the connection
It works, so the problem is identifed, the service is working on its own, but it can not be accessed from outside(docker network bridge), so ,we should change our app, it should bind to ‘0.0.0.0’ instead of ‘localhost’.
0.0.0.0
has a couple of different meanings, but in this context, when a server is told to listen on 0.0.0.0
that means “listen on every available network interface”. The loopback adapter with IP address 127.0.0.1
from the perspective of the server process looks just like any other network adapter on the machine, so a server told to listen on 0.0.0.0
will accept connections on that interface too.
5. The Solution
5.1 Change the network bound policy
Now we should bind to the network interface ‘0.0.0.0’.
5.2 Repackage the docker image
5.3 Rerun the docker container
5.4 Test the connection again
Now it works.
6. Summary
In this post, we demonstrated how to solve the connection problem when connecting to a docker container, the key point is that the container’s service is bound to localhost or 127.0.0.1, which can not be accessed from outside, you should change the code or configuration to bind to ip address ‘0.0.0.0’.
Final Words + More Resources
My intention with this article was to help others who might be considering solving such a problem. So I hope that’s been the case here. If you still have any questions, don’t hesitate to ask me by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!