Search code examples
dockerdocker-composedocker-network

Docker compose port mapping, host port != container port


How can I make curl http://barfoo:8002 work from the foobar-container, without making changes to the docker file?

I have the following compose file:

version: '3'
services:
  foobar:
    build:
      context: ./foobar
    ports:
      - 8001:80
    depends_on:
      - barfoo
  barfoo:
    build:
      context: ./barfoo
    ports:
      - 8002:80

And I added the following to my hosts file on my computer

127.0.0.1     foobar
127.0.0.1     barfoo

Now I start this project with docker-compose up.

When I execute the following on my terminal, this logically works without any problem: curl http://barfoo:8002

When I do the same from a Bash in the foobar container (docker-compose exec foobar /bin/bash) I get Failed to connect to barfoo port 8002: Connection refused, If I use curl http://barfoo:80 it works.

The reason why is that I want to simulate a production like situation, where in production there is no port needed since they use a different hostname and both can use port 80 directly


Solution

  • How can I make curl http://barfoo:8002 work from the foobar-container, without making changes to the docker file?

    Simple solution is to map host port 8002 to barfoo port 8002. But that's probably not what you want.

    barfoo is service name registered in internal docker dns accessible only by the services (foobar) within the same docker network created when you run docker-compose up

    8002 is port mapped to the docker host.

    So when you run curl http://barfoo:8002 from foobar container you try to connect to service barfoo to port 8002. However barfoo listens on port 80 inside the container and not on 8002.

    Another solution:

    You can add network_mode: host to barfoo and foobar.

      foobar:
        build:
          context: ./foobar
        network_mode: host
        ports:
          - 8001:80
        depends_on:
          - barfoo
      barfoo:
        build:
          context: ./barfoo
        network_mode: host
        ports:
          - 8002:80
    

    But then foobar would need to connect using localhost:8002

    The reason why is that I want to simulate a production like situation, where in production there is no port needed since they use a different hostname and both can use port 80 directly

    If that's really what you want, a better alternative would be to use docker stack.

    And your services would be docker swarm services:

    You can deploy them using:

    docker deploy --compose-file path_to_compose_file

    Then foobar would connect to barfoo using service name and port barfoo:80