使用Docker Compose运行时的端口发布

47

我似乎无法找到一种方法,使得使用docker-compose rundocker run相同的方式来实现端口发布。

使用Docker Compose(因此在docker-compose.yml中进行端口映射)会导致curl出现“连接失败”的错误:

$ docker-compose run flask
 * Running on http://0.0.0.0:2048/ (Press CTRL+C to quit)

$ curl http://localhost:2048/
curl: (7) Failed connect to localhost:2048; Connection refused

然而,当手动将端口传递给docker run时,一切都很好:
$ docker run -p 2048:2048 --name flask -t flask_image
 * Running on http://0.0.0.0:2048/ (Press CTRL+C to quit)

$ curl http://localhost:2048
Hello World!

我错过了什么?


Dockerfile

FROM centos:7

# Install EPEL repo.
RUN rpm -iUvh http://dl.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm

# Install Python and Pip.
RUN yum -y update && yum -y install \
    python \
    python-pip

# Flask is necessary to run the app.
RUN pip install flask

EXPOSE 2048

ADD hello_world_flask_app.py /src/hello_world_flask_app.py
CMD ["python", "/src/hello_world_flask_app.py"]

hello_world_flask_app.py

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

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

docker-compose.yml

version: '2'
services:
  flask:
    build: .
    ports:
      - "2048:2048"
2个回答

52

默认情况下,docker-compose run不会发布服务的端口。您可以通过传递 --service-ports 选项来按照docker-compose.yml文件中定义的端口发布端口,或使用 -p 选项发布所有端口。

请参阅docker-compose run文档。


哦,这不是我最好的时刻。我猜在工作日结束时疲惫不堪地发布SO问题总体来说不是一个好主意...对不起浪费了你的时间,感谢你的帮助。 - JimmidyJoo
1
@thaJezah。我有一个进一步的问题,它与另一个问题相关,因此不值得单独提出。在Mac OS上(运行Docker Machine),使用docker-compose--service-ports无法解决从主机使用curl时的问题,只有使用-p选项才能解决。这是我应该提交到GitHub Issue的错误吗?还是我漏掉了其他什么东西? - JimmidyJoo
1
--service-ports 应该按照 yaml 文件中定义的端口发布端口,但如果实际服务已经在运行,则可能没有完成此操作。如果无法正常工作,则一定要在 GitHub 上打开问题(但请确保搜索现有问题)。我最近几周没有密切关注 docker-compose 问题跟踪器,所以这可能是一个已知问题。 - thaJeztah
1
很奇怪这个选项没有在这里的ports选项旁边记录这里 - Elle Mundy
1
@Elle Mundy 这在v3文档的端口部分有记录 这里 - Mog0

28

编辑

尝试使用--service-ports(它不能与up命令一起使用,我们应该以某种方式stoprun它),但它并不会改变这种行为,端口已经暴露但是由于所述原因无法从127.0.0.1访问。


这是因为您正在使用docker-compose 2语法。

默认情况下,它在每个compose项目容器之间创建一个内部网络(或在某些情况下为覆盖网络)。

您可以使用docker inspect <container_name>获取容器网络状态。

同时使用netstat会出现奇怪的行为,似乎只监听tcp6接口:

$ sudo netstat -lt|grep 2048

  tcp6       0      0 [::]:2048           [::]:*         LISTEN      501/docker

可能的解决方案:

1- 从外部主机使用Curl!它可以工作:)

C:\Users\pooya>curl host:2048
Hello World!

2- 在 ports 部分指定本地 IP (127.0.0.1):

$ cat docker-compose.yml
version: '2'
services:
  flask:
      build: .
      ports:
        - "127.0.0.1:2048:2048"

您可以使用 curl localhost:2048 来轻松获取。

3 - 更改网络驱动程序(network_mode)为bridge

** 在更新的docker版本中,此方法已不再起作用 **

4- 从主机IP而非127.0.0.1上的Curl


那么问题是什么?

似乎根本问题源于docker的桥接方法。docker 使用 iptables 来将传入的连接映射到正确的容器端口。

$ sudo iptables -L|grep 2048
ACCEPT     tcp  --  anywhere             10.0.0.12            tcp dpt:2048

正如你所看到的,它只将传入连接的 dport 重定向到 10.0.0.12:2048


等等,那不使用 docker-compose 怎么办??

奇怪!但只需正确地侦听 0.0.0.0 就好了 :)

$ docker run -it -d  -p 2048:2048 test
$ netstat -ltn|grep 2048
tcp        0      0 0.0.0.0:2048   0.0.0.0:*               LISTEN

1
接受了Jeztah的答案,但仍有一些有用的信息。很奇怪, --service-ports 对我来说运行得很好。 - JimmidyJoo
这个问题有任何更新吗?我现在遇到了这个问题。 - Luke101
1
  1. 看起来不再工作了:我收到了这个错误信息,忽略IP地址(127.0.0.1:6379:6379/tcp),服务将在“0.0.0.0”上监听。
- franck

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