同事把 docker run 里的 -p 8080:80 换成了 --net=host,容器起来了,8080 却打不开,他还以为是镜像的问题,来回 rebuild 了三次。

--net=host 的意思是容器不再套一层网络命名空间,直接用宿主机的网卡和端口。容器里监听 80,外面就是 80,跟 -p 没关系,写了也白写。

它省掉的是什么

默认的 bridge 网络里,容器有自己的 IP,外面访问要经过端口映射,NAT 一层,回包再一层。--net=host 把这两层去掉,转发损耗没了,UDP 和组播也顺了。做 DNS、DHCP、组播发现这类服务,基本都得用它。

代价是端口全暴露。容器里随手起个 3306,宿主机 3306 就被占了,防火墙规则也是宿主机的,容器那层隔离感基本没有。

只有在 Linux 上才是真的 host

Windows 和 macOS 上跑 Docker Desktop,宿主机本身是个虚拟机,--net=host 指向的是那个虚拟机,不是你本机。所以在 Mac 上写 --net=host 再访问 localhost,一样连不上。

Docker Desktop 后来加了 host 网络的开关,打开之后行为才接近 Linux,版本太老就没有这个选项,得先升级。

端口冲突是怎么来的

  • 宿主机上 nginx 占着 80,容器再起一个,第二个直接报 address already in use
  • 两个容器都用 host 模式且端口相同,先起的活着,后起的起不来
  • firewalld 或 ufw 只放行了映射端口,host 模式下规则得另外加

排查三步:ss -lntp 看谁占着,docker ps 数一下有几个 host 模式,再看防火墙。别急着删镜像。

compose 里怎么写

compose 文件里没有 --net 这个参数,对应的是 network_mode: host,写在服务下面。写了它就不能再写 ports,两条同时出现,compose 直接报错退出。

要做端口映射、要多容器互通,老老实实用 bridge;只有性能敏感或者协议特殊的服务,才值得上 host 模式。省下的那点转发开销,通常换不回排查端口冲突的时间。