'Max retries exceeded with URL' with two Docker containers sending POST request to each other, running on localhost

Viewed 3711

I'm running two Flask apps on two separate Docker containers together on localhost, with port mapping 3000:3000 and 5000:5000. Each of them has a route that accepts a POST request and do some functions. Here's the code for app 1:

@app.route('/preprocess', methods=['POST'])
def app_preprocess():
    req_data = request.get_json()

    bucket = req_data['bucket']
    input_file = req_data['input']
    upload_file = input_file + "_1"

    # do some functions

    to_send = {"bucket": bucket, "input": upload_file}
    to_send_string = json.dumps(to_send)

    requests.post("http://127.0.0.1:3000/postprocess", json=to_send_string)
    return "Sent request to 2"

if __name__ == "__main__":
    app.run(debug=True, host='0.0.0.0', port=5000)

And app 2:

@app.route('/postprocess', methods=['POST'])
def app_postprocess():
    req_data = request.get_json()

    bucket = req_data['bucket']
    input_file = req_data['input']
    upload_file = input_file + "_2"

    # do some functions

    return "Uploaded 2"

if __name__ == "__main__":
    app.run(debug=True, host='0.0.0.0', port=3000)

I used Postman to send the POST request to each app separately. Both app 1 and 2 does its job (the "do some functions" bit). App 2 would return "Uploaded 2" nicely.

App 1 stopped at the requests.post part, and returning an error:

requests.exceptions.ConnectionError: HTTPConnectionPool(host='127.0.0.1', port=3000): Max retries exceeded
        with url: /postprocess (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at
        0x7f74d3fc6b10>: Failed to establish a new connection: [Errno 111] Connection refused')) // Werkzeug Debugger

Please help with fixing this, thank you. Also I'm a novice at Flask and HTTP routing so I might missed something.

EDIT: here's the docker-compose.yaml

version: '3'
services:

  uploader-1:
    build: ./uploader-1
    image: uploader-1
    container_name: uploader-1
    ports:
        - 5000:5000

  uploader-2:
    build: ./uploader-2
    image: uploader-2
    container_name: uploader-2
    ports:
        - 3000:3000
3 Answers

So when you create a docker instance, it creates a virtual network on your machine - so each docker instance thinks that 127.0.0.1 (or localhost) is itself, not your actual computer (what you think is 127.0.0.1). For this reason you should look into docker network, and either

a) reference the docker instance you want to connect to, or b) add a port (which is what you did) then reference the parent machines ip.

Look at the second answer here: How to get the IP address of the docker host from inside a docker container

You have 2 separate containers where app runs on ports 5000 in the first and 3000 in the second.

You get requests.exceptions.ConnectionError: HTTPConnectionPool(host='127.0.0.1', port=3000) when you send request from within first container where app runs on port 5000.

This is because there's no app running inside the first container on 3000.

Each container's localhost is different and it's different from docker host's localhost.

If you want to send request this way you need to allow containers to reuse host network stack by adding network: host to docker compose:

  uploader-2:
    build: ./uploader-2
    image: uploader-2
    container_name: uploader-2
    network: host
    ports:
        - 3000:3000

Another better option is to connect to hostnames which are container names.

From the docs:

By default Compose sets up a single network for your app. Each container for a service joins the default network and is both reachable by other containers on that network, and discoverable by them at a hostname identical to the container name.

So the code would look like:

requests.post("http://uploader-2:3000/postprocess", json=to_send_string)

Even, better option is send request to service names. It's possible to do so in docker compose or docker-swarm:

any service can reach any other service at that service’s name

The error comes from the use of IP address 127.0.0.1

Docker introduces a virtual network, so each docker-isntance sees itself as 127 not the host machine

(thx @Jmons)


To launch your code locally, use your fixed IPv4 address.

For Windows users: open a command prompt (cmd) and run the ipconfig command, retrieve the IP@ which is at IPv4 address. . . . . . . . . . . . . .: it is generally of type 192.168.x.x

IPv4 address in command prompt

Related