Docker compose端口映射

121

我有一个 docker-compose yml 文件,如下所示

version: '2'
services:
  nodejs:
    build:
      context: .
      dockerfile: DockerFile
    ports:
      - "4000:4000"
    links:
      - redis
    expose:
      - "6379"
  redis:
    build:
      context: .
      dockerfile: Dockerfile-redis

我的目标是将nodejs-127.0.0.1端口6379转发到redis主机。我已经可以从nodejs机器上ping通redis,但端口没有映射成功。尝试使用expose选项,但也没有成功。

4个回答

142

需要指出的是,上述所有解决方案都将端口映射到您计算机上的每个接口。如果您拥有公共IP地址,或者您的计算机在一个大型网络上具有IP地址,则这不太理想。您的应用程序可能会暴露给比您希望的更广泛的受众。

redis:
  build:
    context:
    dockerfile: Dockerfile-redis
    ports:
    - "127.0.0.1:3901:3901"
127.0.0.1 是映射到你的机器上主机名为localhost的IP地址。现在,你的应用程序只暴露在这个接口上,因为127.0.0.1只能通过你的机器访问,所以你不会将容器暴露给整个世界。

有关详细信息,请参阅文档

注意:如果你使用的是Docker for mac,则此操作将使容器在Docker for Mac VM上监听127.0.0.1,并且无法从本地主机访问。如果我没记错的话。


17
安全预防做得好,值得称赞。 - aymericbeaumet
5
了解在Swarm模式下,HOST:PORT映射不起作用真的很重要。最好的方法是将端口"expose"出来,然后通过地址redis:3901连接它(这只能在相同网络中的其他容器中使用)。 - Simon Zyx
你知道是否有一种方法可以将主机端口指定为临时端口,但仍然限制只能使用127.0.0.1吗?例如,我尝试了127.0.0.1::6379(其中6379是容器端口),但没有得到预期的结果。 - rfay
@rfay 我试过了,对我有效。"127.0.0.1::6379"。 - Gatsby Lee
请注意,并非所有机器都会立即将localhost映射到127.0.0.1,因为这只适用于IPv4。许多机器会首先尝试IPv6,这可能会导致某些情况下的失败。如果您想为IPv6端口转发localhost,则还需要添加[::1]。在yaml中,整行应写为:- "[::1]:3901:3901" - undefined

112

如果你想从你的nodejs容器绑定到redis端口,你需要在redis容器中暴露该端口:

version: '2'
services:
  nodejs:
    build:
      context: .
      dockerfile: DockerFile
    ports:
      - "4000:4000"
    links:
      - redis

  redis:
    build:
      context: .
      dockerfile: Dockerfile-redis
    expose:
      - "6379"
expose标签可以让您将端口暴露给容器网络,而无需将其发布到主机上。

https://docs.docker.com/compose/compose-file/#expose

ports标签将会映射主机端口和容器端口主机端口:容器端口

https://docs.docker.com/compose/compose-file/#ports


1
是的,我明白这一部分,但问题在于当我在Node.js容器中使用127.0.0.1:6379时会出现错误。我正在寻找一种自动端口转发的方法。 - z.a.
7
这是因为它们在不同的主机/容器上运行。您可以尝试使用redis:6379而不是127.0.0.1:6379来解决此问题。 - JesusTinoco
1
是的,可以运行。但我需要学习端口转发功能。 - z.a.
1
@JesusTinoco 谢谢!使用redis:6379代替127.0.0.1:6379对我帮助很大! - J_Ocampo
这是如何工作的?docker-compose up是否会编辑您的hosts文件? - Charles Wood
显示剩余2条评论

11

似乎这里的其他答案都误解了你的问题。如果我理解正确,你想向localhost:6379(redis默认端口)发出请求,并希望它们自动转发到redis容器上的相同端口。

https://unix.stackexchange.com/a/101906/38639 帮助我找到了正确的答案。

首先,你需要在镜像上安装nc命令。在CentOS上,该包称为nmap-ncat,因此在下面的示例中,如果你正在使用不同的操作系统作为基础镜像,请将其替换为合适的包。

接下来,你需要告诉它每次容器启动时运行某个特定的命令。你可以使用CMD来实现。

# Add this to your Dockerfile
RUN yum install -y --setopt=skip_missing_names_on_install=False nmap-ncat
COPY cmd.sh /usr/local/bin/cmd.sh
RUN chmod +x /usr/local/bin/cmd.sh
CMD ["/usr/local/bin/cmd.sh"]

最后,我们需要在cmd.sh中设置端口转发。我发现即使使用-l-k选项,nc有时也会在请求完成时终止,因此我使用while循环来确保它始终运行。

# cmd.sh
#! /usr/bin/env bash

while nc -l -p 6379 -k -c "nc redis 6379" || true; do true; done &

tail -f /dev/null # Or any other command that never exits

6

如果您想从主机 (127.0.0.1) 访问 redis ,您必须使用 ports 命令。

redis:
  build:
    context: .
    dockerfile: Dockerfile-redis
    ports:
    - "6379:6379"

1
这会创建循环依赖,这是有意义的。我已经在Node.js上实现了这个。 - z.a.
@z.a. 我可能误解了你的意思,我更新了我的帖子,现在将6379暴露给主机(以及网络上的任何其他计算机,除非你有防火墙)。 - Anthon
2
嗯,恐怕那也行不通。这并不需要将端口暴露给nodejs容器。端口:将端口暴露给实际的主机。我想将rdis 6379端口映射到nodejs 6379端口。 - z.a.

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