我正在使用带有--network host
设置的 Docker 容器并意识到,如果我绑定到一个容器中的端口,我仍然可以启动第二个容器,该容器绑定在同一端口上而不会出现任何错误消息。然后
netstat
将显示第二个容器的 PID 作为监听,而不是第一个容器的 PID。
重现步骤:
[root@test]# cat /etc/os-release
NAME="Red Hat Enterprise Linux"
VERSION="9.2 (Plow)"
...
[root@test]# docker --version
Docker version 23.0.6, build ef23cbc
[root@test]# docker run -d --rm --network host --name container01 debian nc -l -p 80
7bc250856c7ddde57eb48f57ba800391577c728ec856da24bf80a9df8e766c84
[root@test]# netstat -tulpen | grep 80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 0 10435480 2162661/nc
[root@test]# docker run -d --rm --network host --name container02 debian nc -l -p 80
10897d7dea695446db48bff9d3b338554a7cd0535f30625f06b6e5f959bf8df2
[root@test]# netstat -tulpen | grep 80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 0 10436217 2162708/nc
[root@test]# ps auxf
root 2162640 0.0 0.5 720496 10608 ? Sl 11:03 0:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 7bc250856c7ddde57eb48f57ba800391
root 2162661 0.0 0.0 3200 1116 ? Ss 11:03 0:00 \_ nc -l -p 80
root 2162686 0.0 0.5 720496 10028 ? Sl 11:03 0:00 /usr/bin/containerd-shim-runc-v2 -namespace moby -id 10897d7dea695446db48bff9d3b33855
root 2162708 0.0 0.0 3200 1060 ? Ss 11:03 0:00 \_ nc -l -p 80
即使第二个容器启动后,与第一个容器的现有连接仍保持有效。所有新连接都将转到第二个容器。
当然,直接在主机上绑定到相同的端口是行不通的,并且容器也不能绑定到主机已经列出的端口。
所以我的问题是:容器到底有什么不同,以便它们可以超越已经存在的端口绑定?
答案1
这与从同一客户端在单个端口上进行多个会话的方式大致相同。连接使用插座对(其中包括一个唯一的客户端临时端口)来标识自己。主机使用这些唯一的对将流量发送到正确的进程 ID - 有时甚至在主机端口本身已被其他进程绑定之后也是如此。它们应该保持活动状态,直到主机关闭端口、结束这些会话、结束该进程 ID 等。
软件如何允许基于操作系统和可用选项重新绑定到端口存在一些限制。我在以下答案中找到了有关此问题和绑定过程(在 Linux 中)的一些详细信息:两个应用程序可以监听同一个端口吗?