Skip to content
60.Docker»20.网络模式»LV010-Host模式.md

LV010-Host模式

Host模式需要docker run --net host 或者 --network host 来手动指定。

一、Host 模式的网络拓扑

它相当于 Vmware 中的 NAT 模式,与宿主机在同一个网络中,但没有独立 IP 地址。一个 Docker 容器一般会分配一个独立的 Network Namespace。但如果启动容器的时候使用 host 模式,那么这个容器将不会获得一个独立的 Network Namespace,而是和宿主机共用一个 Network Namespace。

容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。可以通过 --net = host 指定使用 host 网络。

img

二、有什么特点

(1)host 模式可以使容器获取最佳网络性能。

(2)host 模式,它没有独立的网络空间。

(3)host 模式下的容器,完全和宿主机共用一个网络空间(端口、IP 等),所以该模式下的容器不会虚拟出容器自身的虚拟网卡,也不会配置自己的虚拟 IP。

(4)host 模式下的容器,除了网络和宿主机共享,其他的资源,如文件系统、进程列表等,容器之间依然是相互隔离的。

弊端就是同一个端口,比如宿主机的 80 端口,只能被一个服务占用,如果被某个容器占用了,宿主机就不能用,后续的容器也不能用,直到优先抢到 80 端口的服务,停止提供服务(放弃 80 端口)。

三、Host 模式示例

首先重开一个 CNB 开发环境,或者删掉之前运行的容器和镜像。

shell
docker ps -a  #列出所有容器列表
docker rm -f $(docker ps -qa)  #强制移除所有容器
docker ps -a

1. 未启动容器

1.1 宿主机网关信息

我们执行以下命令查看:

shell
docker inspect host    # 查看 host 网络模式 docker0 虚拟网卡的详细信息(子网网段、网关等)

【例】

image-20251101222943308

1.2 宿主机网卡信息

shell
ifconfig

查看目的:通过 ifconfig 查看网卡列表信息,以便验证稍后以 Host 模式启动 nginx 容器后,是否会产生新的虚拟网卡。

Tips:实际情况 Host 模式下,各容器不产生新的虚拟网卡!

【例】

shell
  /workspace git:(main) ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:d1:19:07:10  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.19.247.2  netmask 255.255.255.0  broadcast 172.19.247.255
        ether 02:42:ac:13:f7:02  txqueuelen 0  (Ethernet)
        RX packets 1650  bytes 568077 (554.7 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 1551  bytes 5437380 (5.1 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 62  bytes 4748 (4.6 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 62  bytes 4748 (4.6 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

1.3 宿主机 80 端口

先用命令 ss -lntup 或者 netstat -nalpt 验证一下,是否有未知程序占用 80,有的话 kill it,依次确保下面实验的准确性(nginx 占用的是 80 端口,稍后启动的 nginx 容器会占用宿主机的 80 端口)。:

shell
docker ps -a   # 实验前,查看是否有启动的容器,如果有暂时先停掉,特别是 nginx 容器
netstat -nalpt # 实验前,先查看宿主机的(80)端口占用情况

【例】

shell
  /workspace git:(main) netstat -nalpt
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.11:43157        0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:36000           0.0.0.0:*               LISTEN      88/sshd: /usr/sbin/
tcp        0      0 0.0.0.0:8686            0.0.0.0:*               LISTEN      72/node
tcp        0      0 172.19.247.2:8686       172.19.247.1:52020      ESTABLISHED 72/node
tcp        0      0 172.19.247.2:8686       172.19.247.1:52024      ESTABLISHED 266/node

会发现这里并没有任何服务占用 80 端口。

2. 启动两个 nginx 容器

这里我们先后启动两个 nginx 服务,这里先启动第一个。预期的情况是第一个 nginx 容器被启动后,会占用宿主机的 80 端口。因为宿主机只有 1 个 80 端口,那么第二个 nginx 自然是因为没有 80 端口可用,而启动失败了。

2.1 启动 nginxV1 容器

  • docker run 以 Host 模式,启动第一个 nginx 容器 nginxV1
shell
docker run -d --net=host --name nginxV1 nginx:alpine   # 以 host 模式启动 nginxV1

【例】

shell
  /workspace git:(main) docker run -d --net=host --name nginxV1 nginx:alpine
Unable to find image 'nginx:alpine' locally
alpine: Pulling from library/nginx
#...
Status: Downloaded newer image for nginx:alpine
342e6d721db7ccc397aef2f30fe32e48848d65e3fec8c72ece009fb9963fc11f

2.2 查看宿主机端口

shell
netstat -nalpt # 查看宿主机的端口占用情况(主要看 80 端口)

【例】

shell
  /workspace git:(main) netstat -nalpt
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 127.0.0.11:43157        0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:36000           0.0.0.0:*               LISTEN      88/sshd: /usr/sbin/
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:8686            0.0.0.0:*               LISTEN      72/node
tcp        0      0 172.19.247.2:8686       172.19.247.1:52020      ESTABLISHED 72/node
tcp        0      0 172.19.247.2:8686       172.19.247.1:52024      ESTABLISHED 266/node
tcp6       0      0 :::80                   :::*                    LISTEN      -

可以看到宿主机的 80 端口已经被占用。

2.3 查看宿主机网卡信息

shell
ifconfig

【例】

shell
  /workspace git:(main) ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        ether 02:42:d1:19:07:10  txqueuelen 0  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.19.247.2  netmask 255.255.255.0  broadcast 172.19.247.255
        ether 02:42:ac:13:f7:02  txqueuelen 0  (Ethernet)
        RX packets 4188  bytes 23593631 (22.5 MiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 3855  bytes 5615089 (5.3 MiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 132  bytes 10537 (10.2 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 132  bytes 10537 (10.2 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

可以发现,Host 模式下的容器启动后,不会创建新的网卡(桥接模式下的容器,会自动创建以 veth 开头的虚拟网卡) 。

2.4 查看 nginxV1 容器网络信息

shell
docker ps         # 查看正在运行的容器
docker inspect container_id # 根据容器 id 的首字母也可以查看容器详细信息

【例】

image-20251101224449890

可以发现,Host 模式开启的容器,容器自身是没有任何网络资源信息的,都是空的,它用的一切网络资源都是宿主机的.

2.5 访问容器的 nginx 服务

那么下面继续通过宿主机访问一下 nginxV1 吧:

shell
ifconfig # 查看宿主机(本机)IP
curl 物理网卡IP # 直接访问宿主机的 IP(eth0/ens33),注:80 默认可以不写

【例】

shell
  /workspace git:(main) ifconfig
docker0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
        inet 172.17.0.1  netmask 255.255.0.0  broadcast 172.17.255.255
        #...
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.19.247.2  netmask 255.255.255.0  broadcast 172.19.247.255
        #...

lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        #...

  /workspace git:(main) curl 172.19.247.2
#...
<h1>Welcome to nginx!</h1>
#...

尽管 host 模式下的 nginx 容器没有任何网络资源,但是以该模式启动的容器,依然可以直接通过宿主机的 IP(+端口,不同的服务,端口也不同)直接访问。

为什么呢?上面已经提及,Host 模式运行的容器,用的一切网络资源,是占用的宿主机的网络资源。

2.6 nginxV1 能联网吗?

我们使用下面的命令进入 nginxV1 容器:

shell
docker ps
docker exec -it container_id /bin/sh
ifconfig
ping www.baidu.com

【例】

shell
  /workspace git:(main) docker exec -it 342e6d721db7 /bin/sh
/ # ifconfig
docker0   Link encap:Ethernet  HWaddr 02:42:D1:19:07:10
          inet addr:172.17.0.1  Bcast:172.17.255.255  Mask:255.255.0.0
          #...

eth0      Link encap:Ethernet  HWaddr 02:42:AC:13:F7:02
          inet addr:172.19.247.2  Bcast:172.19.247.255  Mask:255.255.255.0
          #...

lo        Link encap:Local Loopback
          #...

/ # ping www.baidu.com
PING www.baidu.com (183.2.172.177): 56 data bytes
64 bytes from 183.2.172.177: seq=0 ttl=49 time=5.764 ms
^C
--- www.baidu.com ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 5.670/5.732/5.764 ms

发现是可以联网的,容器的 eth0 的 ip 和宿主机完全一样。

2.7 再启动一个 nginxV2

既然宿主机的 80 端口被 nginxV1 霸占了,那么再开启 nginxV2,是否可以启动呢?那肯定是不能启动,宿主机的 80 端口就 1 个,已经被 V1 占用了。

shell
docker ps # 查看正在运行的容器
docker run -d --net=host --name nginxV2 nginx:alpine  #再次以 host 模式,开启 nginxV2
docker ps -a # 查看 nginxV2 是否启动成功(发现,没有启动成功)

【例】

image-20251101225551376

这里 nginxV2 启动失败,我们可以用下面的命令看一下日志:

shell
docker logs nginxV2

【例】

image-20251101225800421

发现,nginxV2 失败的原因是因为 80 端口已经被占用,至此就验证了,上面提到的,Host 网络模式下宿主机中容器的网络资源是占用的宿主机的,特别是端口,先占先得,除非先得到的容器放弃了该端口的占用。

2.8 其他宿主机

开启其他主机, curl host 模式下的 nginx:

host2

这里照搬一张图,因为我是在 CNB 云原生开发中验证,暂时还不知道怎么搞一个同网段的其他主机,这里就没有尝试了。

会发现,其他同一网段的虚拟主机可以直接访问宿主机内部的容器。这一点很神奇,然而 bridge 模式下,同一网段的主机,是不能直接访问宿主机内部容器的。

之所以 Host 模式下,同一网段的主机可以直接访问宿主机内部容器,是因为容器霸占的是宿主机的资源。访问容器,相当于访问的就是宿主机,给人的感觉就是:“宿主机就是容器,容器就是宿主机”。然而除了网络资源,容器占用的是宿主机的,容器之间的其他资源依然是相互隔离的,如文件系统、进程列表等。

四、总结

Host模式的优点和缺点,都十分明显,容器内的服务只要部署成功,可以被同一网段内的局域网的其他任一主机访问,给人的错觉就是“宿主机就是容器,容器就是宿主机”。缺点就是,一个端口只能被一个服务占用,且容器的网络也缺少隔离性,故该使用场景十分有限。

因为该模式,不是默认的网络模式,所以在docker run的时候,要添加参数--net=host 或者 --network=host 来手动指定。

参考资料:

Docker:网络模式详解 - Gringer - 博客园

Docker 四种网络模式(Bridge,Host,Container,None) - wq9 - 博客园

Docker 学习:容器五种(3+2)网络模式 | bridge 模式 | host 模式 | none 模式 | container 模式 | 自定义网络模式详解-CSDN 博客

莫道桑榆晚 为霞尚满天.