简体   繁体   English

docker-compose:在容器中打开端口但不从主机绑定它

[英]docker-compose: open port in container but not bind it from host

I created a service (a small web server) using docker-compose .我使用docker-compose创建了一个服务(一个小型 web 服务器)。 The network part is defined as网络部分定义为

services:
  service:
    image: ... (this image uses port 9000)
    ports:
      - 9000:9000
networks:
  default:
    name: my-network

After docker-compose up , I observe:docker-compose up之后,我观察到:

  • the host gets an IP address 127.22.0.1 and the client gets 127.22.0.2 .主机获得 IP 地址127.22.0.1 ,客户端获得127.22.0.2
  • I can successfully ping the client from the host ping 127.22.0.2 .我可以从主机ping 127.22.0.2成功 ping 客户端。
  • From the host machine: the web server can be reached using从主机:web 服务器可以使用
    • 127.22.0.1:9000
    • 127.22.0.2:9000
    • localhost:9000
    • 192.168.0.10:9000 (This is the host's IP address in the LAN) 192.168.0.10:9000 (这是局域网中主机的IP地址)

Now I want to restrict the access from the host using 127.22.0.2:9000 only.现在我想仅使用127.22.0.2:9000限制来自主机的访问。 I feel this should be possible if I don't bind the container's 9000 port to the host's 9000 port.如果我不将容器的 9000 端口绑定到主机的 9000 端口,我觉得这应该是可能的。 Then I deleted the ports: 9000:9000 part from the docker-compose.yml .然后我从docker-compose.yml中删除了ports: 9000:9000部分。 Now I observe:现在我观察到:

  • All the above four methods do not work now, including 127.22.0.2:9000以上四种方法现在都不行了,包括127.22.0.2:9000
  • The client can still be pinged from the host using 127.22.0.2仍然可以使用127.22.0.2从主机 ping 客户端

I think: since the the host and the container are both in a bridge network my-network and have obtained their IP addresses.我认为:由于主机和容器都在桥接网络my-network中,并且已经获得了它们的 IP 地址。 The web server should still be reachable from 127.22.0.2:9000 . web 服务器应该仍然可以从127.22.0.2:9000访问。 But this is not the case.但这种情况并非如此。

My questions:我的问题:

  • why does it work like this?为什么它会这样工作? Shouldn't the host/container in the same subnet 127.22.0.0/16 be able to talk to each other freely?同一个子网127.22.0.0/16中的主机/容器不应该能够自由地相互交谈吗?
  • How to achieve what I want: do not forward port 9000 from host to container and only allow accessing the container using its subnet IP address.如何实现我想要的:不要将端口 9000 从主机转发到容器,只允许使用其子网 IP 地址访问容器。

Docker is also playing with your host iptables in order to achieve its isolation standarts. Docker 也在使用您的主机 iptables 以实现其隔离标准。

These are the default iptables rules with no container running:这些是没有容器运行的默认 iptables 规则:

$ sudo iptables-save 
# Generated by iptables-save v1.8.4 on Tue Jan 11 13:11:52 2022
*filter
:INPUT ACCEPT [49:15900]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [53:4709]
:DOCKER - [0:0]
:DOCKER-ISOLATION-STAGE-1 - [0:0]
:DOCKER-ISOLATION-STAGE-2 - [0:0]
:DOCKER-USER - [0:0]
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN
COMMIT
# Completed on Tue Jan 11 13:11:52 2022
# Generated by iptables-save v1.8.4 on Tue Jan 11 13:11:52 2022
*nat
:PREROUTING ACCEPT [3:1112]
:INPUT ACCEPT [3:1112]
:OUTPUT ACCEPT [11:899]
:POSTROUTING ACCEPT [11:899]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A DOCKER -i docker0 -j RETURN
COMMIT
# Completed on Tue Jan 11 13:11:52 2022

After running a container which binds on port 8080 you can see that 3 rules where added to my iptables rules:运行绑定到端口 8080 的容器后,您可以看到 3 条规则添加到我的 iptables 规则中:

$ sudo iptables-save 
# Generated by iptables-save v1.8.4 on Tue Jan 11 13:14:36 2022
*filter
:INPUT ACCEPT [79:25192]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [75:8565]
:DOCKER - [0:0]
:DOCKER-ISOLATION-STAGE-1 - [0:0]
:DOCKER-ISOLATION-STAGE-2 - [0:0]
:DOCKER-USER - [0:0]
-A FORWARD -j DOCKER-USER
-A FORWARD -j DOCKER-ISOLATION-STAGE-1
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A DOCKER -d 172.17.0.2/32 ! -i docker0 -o docker0 -p tcp -m tcp --dport 8080 -j ACCEPT
-A DOCKER-ISOLATION-STAGE-1 -i docker0 ! -o docker0 -j DOCKER-ISOLATION-STAGE-2
-A DOCKER-ISOLATION-STAGE-1 -j RETURN
-A DOCKER-ISOLATION-STAGE-2 -o docker0 -j DROP
-A DOCKER-ISOLATION-STAGE-2 -j RETURN
-A DOCKER-USER -j RETURN
COMMIT
# Completed on Tue Jan 11 13:14:36 2022
# Generated by iptables-save v1.8.4 on Tue Jan 11 13:14:36 2022
*nat
:PREROUTING ACCEPT [33:4634]
:INPUT ACCEPT [9:3254]
:OUTPUT ACCEPT [13:2363]
:POSTROUTING ACCEPT [13:2363]
:DOCKER - [0:0]
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A POSTROUTING -s 172.17.0.2/32 -d 172.17.0.2/32 -p tcp -m tcp --dport 8080 -j MASQUERADE
-A DOCKER -i docker0 -j RETURN
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 8080 -j DNAT --to-destination 172.17.0.2:8080
COMMIT
# Completed on Tue Jan 11 13:14:36 2022

So regarding question1: The reason your host/container can't talk to each other freely eventhough they are in the same subbet 127.22.0.0/16 is because of the iptables preventing it.所以关于问题1:您的主机/容器即使在同一个子赌注 127.22.0.0/16 中也不能自由交谈的原因是因为 iptables 阻止了它。

Regarding question2: You can play with docker iptables configuration in order to achieve your wanted behaviour.关于问题2:您可以使用 docker iptables配置来实现您想要的行为。 But IMO you should just bind port 9000 only on localhost instead see , that way it won't listen on your LAN但是 IMO 你应该只在 localhost 上绑定端口 9000 而不是看到,这样它就不会在你的 LAN 上监听

Your understanding of the networking is correct.您对网络的理解是正确的。 Removing the port binding from the docker-compose.yml will remove the exposed port from the host.docker-compose.yml中删除端口绑定将从主机中删除暴露的端口。 Since the host is also part of the virtual network my-network with an IP in the same subnet as the container, your service should be reachable from the host using the container IP directly.由于主机也是虚拟网络my-network的一部分,其中 IP 与容器位于同一子网中,因此您的服务应该可以直接使用容器 IP 从主机访问。

But I think, this is actually a simple typo and instead of但我认为,这实际上是一个简单的错字,而不是

127.22.0.0/16

you actually have你实际上有

172.22.0.0/16

as the subnet for my-network !作为my-network的子网! This is a typical subnet used by docker in the default configuration, while 127.0.0.0/8 is always bound to the loopback device !这是docker在默认配置中使用的典型子网,而127.0.0.0/8始终绑定到环回设备

So connecting to 127.22.0.2 will actually connect you to localhost - which is consistent with the symptoms you encountered:因此,连接到127.22.0.2实际上会将您连接到localhost - 这与您遇到的症状一致:

  • connecting to 127.22.0.2:9000 will work only if the port is exposed on the host仅当端口在主机上公开时,连接到127.22.0.2:9000才有效
  • you can always pint 127.22.0.2 since it is the loopback address你总是可以品脱127.22.0.2因为它是环回地址

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM