docker-proxy 是 Docker 网络架构中的一个"传声筒"。当你启动一个容器并使用 -p 参数映射端口时,它就在幕后默默工作。如下的一个docker-compose配置:

注意这里的端口映射,就类似于你运行 docker run -p 30003:30003 的命令时,你实际上是要求宿主机将发往 30003 端口的流量转发到容器内部的 30003 端口。
为了实现这个转发,Docker 使用了两种机制:
-
DNAT (iptables 规则): 这是主要方式,效率极高,直接在内核层面处理流量。
-
docker-proxy: 这是一个运行在用户态(Userland)的小程序。每当你映射一个端口,Docker 就会为该端口启动一个独立的
docker-proxy进程。
以上两个动作是由docker自动完成的,这时,你使用如下命令(netstat, ps)可以查看到该docker-proxy进程:

但是,如果你使用命令sudo kill -9 2152 把这个docker-proxy进程杀死,你再次访问该主机的30003端口,仍然可以正常访问!!!但是你ss 或 netstat搜索不到任何关于30003端口的信息。
1. 为什么进程杀了,网页还能访问?
这就是 Docker 的"双保险"机制:
-
保险 A (iptables): 只要容器还在运行,Docker 就会在 Linux 内核中写入一条
iptables转发规则(DNAT)。这条规则在内核态生效,不依赖任何进程。 -
保险 B (docker-proxy): 这是一个用户态进程,主要负责处理一些
iptables覆盖不到的边角情况。
当你杀掉 docker-proxy 进程后,内核态的 iptables 规则依然稳如泰山 。所以,外部流量打到 30003 时,内核直接把包转给了容器,网页自然能打开。这时你输入命令,大概率会看到:
bash
[root@localhost ~]# sudo iptables -t nat -L DOCKER -n | grep 30003
DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:30003 to:172.21.0.3:30003
2. 为什么 ss 搜不到了?
ss 和 netstat 查的是系统中的 Socket 监听表。
-
当
docker-proxy运行时,它会占用(Bind)30003端口,ss就能看到它。 -
你把它杀了,这个端口在用户态就处于"空闲"状态。
-
但是,内核
iptables就像一个"隐形拦截者",它在数据包还没到达 Socket 层之前就把包抢走了。
3. 会有什么后果?
虽然现在访问正常,但杀掉 docker-proxy 可能会导致以下小问题:
-
宿主机局部回环失效: 在某些配置下,你在宿主机本地执行
curl localhost:30003可能会失败(尽管从外网访问是好的)。 -
状态不一致: Docker 此时并不知道你手动杀了它的组件。当你下次
docker stop或rm这个容器时,Docker 可能会因为找不到该进程而报一个小错误(尽管它通常会自动忽略)。
4. 怎么恢复?
如果你想让 docker-proxy 重新出现,最简单的方法是重启容器:
docker restart web-ui
重启后,Docker 会重新创建 iptables 规则并启动一个新的 docker-proxy 进程。
总结:
一个很重要的结论:Docker 的端口映射本质上是内核行为(iptables),docker-proxy 只是一个辅助。 只要内核规则在,服务就不会断。