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

(3)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 博客

莫道桑榆晚 为霞尚满天.