bigywater.tech
Docker · 54

端口发布:-p 在 iptables 里生成了哪些规则

-p 的几种写法到底差在哪?只想让本机访问怎么写?-P 的随机端口从哪来?映射的端口在 Mac 上是谁在监听?这篇逐项实测,包括端口冲突时容器的状态。

Connection refused
-p 127.0.0.1:9790:8000 时,用 Mac 的局域网地址访问的结果
55000
-P 为 8000/tcp 和 9000/udp 随机选中的宿主机端口(同一个号码)
com.docker.backend
Mac 上监听映射端口的进程(lsof 里显示为 com.docke…)

绑定地址

实测 · 本机执行输出
  -p 9780:8000:docker port → 0.0.0.0:9780
[::]:9780;docker ps 的 PORTS 列 → 0.0.0.0:9780->8000/tcp, [::]:9780->8000/tcp
    Mac 访问 127.0.0.1:9780 → hello from container
    Mac 用局域网地址访问 <本机局域网IP>:9780 → hello from container
  -p 127.0.0.1:9790:8000:docker port → 127.0.0.1:9790
    Mac 访问 127.0.0.1:9790 → hello from container
    Mac 用局域网地址访问 <本机局域网IP>:9790 → URLError:[Errno 61] Connection refused

-p 9780:8000 没写地址就是所有地址(0.0.0.0 和 [::]),局域网里的其它机器也能访问;-p 127.0.0.1:9790:8000 只在本机回环地址上监听,用局域网地址访问被拒绝。要对外暴露还是只给本机,在这里决定。

-P

实测 · 本机执行输出
  docker port → 8000/tcp -> 0.0.0.0:55000 ; 9000/udp -> 0.0.0.0:55000
  随机的宿主机端口 55000(落在 32768 以上吗?True),Mac 访问 → hello from container

-P 把 Dockerfile 里 EXPOSE 声明的所有端口映射到随机的宿主机端口(这次 TCP 和 UDP 拿到了同一个 55000)。docker port 能查到。

UDP

实测 · 本机执行输出
  Mac 发 UDP "ping" 到 127.0.0.1:9800 → udp-echo:ping
  只写 -p 9800:9000(不带 /udp)时 docker port → 9000/tcp -> 0.0.0.0:9810
9000/tcp -> [::]:9810

UDP 要写 /udp,否则按 TCP 映射。回显测试证实 UDP 可以双向通。

谁在监听

实测 · 本机执行输出
  lsof -iTCP:9780 -sTCP:LISTEN:com.docke 71668
  虚拟机里有这个端口在监听吗?LISTEN 0      4096         0.0.0.0:9780       0.0.0.0:*

在 macOS 的 Docker Desktop 上,Mac 里监听映射端口的是 Docker Desktop 自己的进程(lsof 显示 com.docke…),虚拟机里的 0.0.0.0:9780 也在监听,请求经这两层转发给容器。Linux 宿主机上通常是 docker-proxy 或 iptables 规则,我没有测。

端口冲突

实测 · 本机执行输出
  同一个宿主机端口再映射一次:退出码 125;docker: Error response from daemon: failed to set up container networking: driver failed programming external connectivity on endpoint bwlab
  失败的容器处于什么状态?created

宿主机端口已被占用时,docker run 以 125 退出,容器停在 created 状态,需要手动删除。

分步演示

端口映射
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Docker Desktop(Engine 29.8.2,容器跑在 Docker Desktop 自带的 Linux 虚拟机里,内核与宿主机的 macOS 不同);镜像为 linux/arm64;需要看虚拟机内部时用特权容器 + nsenter;计时用 time / date +%s%N,数字每次运行会有小幅抖动。HTTP / UDP 服务是 python:3.12-alpine 里的小脚本;访问用 Python urllib 和 socket;端口从 9780 起挑空闲的;局域网地址已在输出中替换为 <本机局域网IP>;lsof 的进程名被 lsof 截成 com.docke,文中据此写作 com.docker.backend,是我的推断;实验后已删除容器
    • 没有验证:IPv6 地址访问、端口范围写法(-p 9830-9840:8000-8010)、iptables / pf 规则、Linux 上的 docker-proxy、--publish-all 与 Compose 的 ports、端口映射的吞吐开销
    京ICP备2026067502号-1京公网安备11010502063487号