Docker Compose端口映射,主机端口!=容器端口

7

我该如何在不更改docker文件的情况下,使得从foobar容器中执行curl http://barfoo:8002命令能够正常工作?

我有以下compose文件:

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

我在我的电脑上的 hosts 文件中添加了以下内容。
127.0.0.1     foobar
127.0.0.1     barfoo

现在我通过 docker-compose up 命令开始了这个项目。
当我在终端执行以下命令时,逻辑上没有任何问题:curl http://barfoo:8002 但是,当我从 foobar 容器的 Bash 中执行相同的命令 (docker-compose exec foobar /bin/bash) 时,它会显示 Failed to connect to barfoo port 8002: Connection refused。如果我使用 curl http://barfoo:80,它可以正常工作。
原因是我想模拟生产环境,生产环境中不需要端口号,而是使用不同的主机名,并且都可以直接使用端口 80。

你需要做的是将“容器”内的端口“8001”映射到主机的端口“80”。因此,当您访问端口80时,会被重定向到8001。 - DUDANF
3个回答

4
我该如何在不更改Docker文件的情况下,使curl http://barfoo:8002 在foobar容器中正常工作?
简单的解决方案是将主机端口8002映射到barfoo端口8002。但这可能不是你想要的。
barfoo是注册在内部Docker DNS中的服务名称,只能通过运行docker-compose up时创建的相同docker网络中的服务(foobar)访问。
8002是映射到Docker主机的端口。
因此,当您从foobar容器运行curl http://barfoo:8002时,您尝试连接到服务栏foo以获取8002端口。然而,barfoo在容器内部监听端口80而不是8002。
另一种解决方案:
您可以将network_mode:host添加到barfoo和foobar中。
  foobar:
    build:
      context: ./foobar
    network_mode: host
    ports:
      - 8001:80
    depends_on:
      - barfoo
  barfoo:
    build:
      context: ./barfoo
    network_mode: host
    ports:
      - 8002:80

但是foobar需要使用localhost:8002进行连接。

原因是我想模拟生产环境,生产环境中不需要端口,因为它们使用不同的主机名,并且两者都可以直接使用端口80。

如果这确实是您想要的,一个更好的选择是使用docker stack。

您的服务将是docker swarm服务:

您可以使用以下命令部署它们:

docker deploy --compose-file path_to_compose_file

然后foobar将使用服务名称和端口barfoo:80连接到barfoo


1

目前,一个可能的解决方法是在docker-compose.yml中覆盖command,使其中的进程监听端口8002而不是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'

但如果有更好的解决方案/答案,我将非常乐意接受。


1
当你在终端执行curl http://barfoo:8002时,你会访问计算机的本地端口8002,该端口将端口80转发到容器。

然而,foobar容器直接访问容器端口,该端口仅监听端口80。

通过在docker-compose.yaml中添加另一个容器作为反向代理,你可以实现你所尝试做的事情。

新的docker-compose将看起来像这样 -

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

自定义的nginx镜像应该这样构建 -

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

将此用作nginx.conf文件 -
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;
        }
    }
}

谢谢,我明白端口是在哪里打开的以及为什么会发生这种情况。我的主要目标是docker网络内部足够“智能”,不需要额外的nginx。 - Dennis van de Hoef - Xiotin
据我所知,没有办法让程序在不启动两次或添加反向代理的情况下回答两个不同端口的请求。Docker网络有很棒的功能,但由于端口和主机的工作方式,这超出了它的能力范围。 - Yaron Idan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接