Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 861
Dennis van de Hoef Avatar asked Nov 04 '19 11:11

Dennis van de Hoef


3 Answers

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

like image 149
rok Avatar answered Nov 01 '22 22:11

rok


For now, a possible workaround is to overwrite the command in the docker-compose.yml so that it the process in it listens to port 8002 instead of 80.

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

But I would be more than happy to accept a better solution/answer for this one.

like image 1
Dennis van de Hoef Avatar answered Nov 02 '22 00:11

Dennis van de Hoef


When you execute curl http://barfoo:8002 from your terminal, you are hitting the local port 8002 of your computer, which is forwarding port 80 of your container.

The foobar container, however, is hitting the container port directly, which is listening on port 80 alone.

You can achieve what you are trying to do by adding another container to the docker-compose.yaml, which will act as a reverse proxy in front of the barfoo container.

The new docker-compose will look something like this -

version: '3'
services:
  foobar:
    build:
      context: ./foobar
    ports:
      - 8001:80
    depends_on:
      - barfoo
  barfoo-host:
    build:
      context: ./barfoo
    ports:
      - 8002:80
  barfoo:
    image: custom-nginx:latest

And the custom-nginx image should be built like so -

FROM nginx:1.17-alpine
COPY nginx.conf /etc/nginx/
EXPOSE 8002
CMD ["nginx", "-g", "daemon off;"]

Using this as the nginx.conf file -

user                            root;
worker_processes                auto;

error_log                       /var/log/nginx/error.log warn;

events {
    worker_connections          1024;
}

http {
    include                     /etc/nginx/mime.types;
    default_type                application/octet-stream;
    sendfile                    off;
    access_log                  off;
    keepalive_timeout           3000;
    server {
        listen                  8002;
        root                    /usr/share/nginx/html;
        server_name             barfoo;
        location / {
            proxy_pass http://barfoo-host;
        }
    }
}
like image 1
Yaron Idan Avatar answered Nov 01 '22 22:11

Yaron Idan