Docker-compose: Docker containers can't connect using service names

Viewed 1489

I have 3 containers. One is a lighttpd server serving static content (front). I have 2 flask servers handling the backend (back and model)

This is my docker-compose.yml

version: "3"
services:
  front:
    image: ecd3:latest
    ports:
      - 4200:80
    tty: true
    links:
      - "back"
    depends_on:
      - back
    networks:
      - mynet

  back:
    image: esd3:latest
    ports:
      - 5000:5000
    links:
      - "model"
    depends_on:
      - model
    networks:
      - mynet

  model:
    image: mok:latest
    ports:
      - 5001:5001
    networks:
      - mynet

networks:
  mynet:

I'm trying to send an http request to my flask server (back) from my frontend (front). I have bound the flask server to 0.0.0.0 and even used the service name in the frontend (http://back:5000/endpoint)

Trying to curl the flask server inside the frontend container (curl back:5000) gives me this:

curl: (52) Empty reply from server

Pinging the flask server from inside the frontend container works. This means that the connection must have been established.

Why can't I connect to my flask server from my frontend?

1 Answers

We discovered several things in the comments. Firstly, that you had a proxy problem that prevented one container using the API in another container.

Secondly, and critically, you discovered that the service names in your Docker Compose configuration file are made available in the virtual networking system set up by Docker. So, you can ping front from back and vice-versa. Importantly, it's worth noting that you can do this because they are on the same virtual network, mynet. If they were on different Docker networks, then by design the DNS names would not be available, and the virtual container IP addresses would not be reachable.

Incidentally, since you have all of your containers on the same network, and you have not changed any network settings, you could drop this network for now. In other words, you can remove the networks definition and the three container references to it, since they can just join the default network instead.

Thirdly, you learned that Docker's virtual DNS entries are not made available on the host, and so front and back are not available here. Even if the were (e.g. if manual entries were made in the hosts file) those IPs would not work, since there is no direct networking route from the host to the containers.

Instead, those containers are exposed by a Docker device that proxies connections from a custom localhost port down to those containers (4200, 5000 and 5001 in your case).

A good interim solution is to load your frontend at http://localhost:4200 and hardwire its API address as http://localhost:5000. You may have some CORS issues with that though, since browsers will see these as different servers.

Moreover, if you go live, you may have some problems with mobile networks and corporate firewalls - you will probably want your frontend app to sit on port 443, but since it is a separate server, you will either need a different IP address for your API, so it can also go on 443, or you will need to use another port. A clean solution for this is to put a frontend proxy in front of both containers, and then just expose the proxy in Docker. This will send HTTP requests from the outside to the correct container, depending on a filtering criteria set by you. I recommend Traefik for this, but there are undoubtedly several other approaches.

Related