Docker的网络类型及容器之间的访问方式

Docker安装时会自动的在Docker host上创建三种网络,我们可以使用docker network ls查看。这 三种网络分别是none网络、host网络、bridge网络,bridge网络是我们在创建容器时默认使用的网络。

[root@docker ~]# docker network ls
NETWORK ID     NAME            DRIVER    SCOPE
9cb8177d0a4a   bridge          bridge    local
ff99ed99d67b   harbor_harbor   bridge    local
ecf73b7c090a   host            host      local
a8755bdfb429   none            null      local
None

none网络就是没有网络,可以通过–network=none指定使用none网络,使用none网络时,只有一个lo口。

none网络是个封闭的网络,使用了这种网络类型的容器无法在网络层被访问。封闭意味着隔离,一些对安全性要求高并且不需要 联网的应用可以使用none网络。比如某个容器的唯一用途是生成随机密码,就可以放到none网络中避免密码被窃取。

Host

使用host网络的容器共享Docker host的网络栈,容器的网络配置与Docker host完全一样。可以通过–network=host指定使用 host网络。可以通过以下示例看到,创建容器指定容器网络为host时,容器直接共享了Docker host的网络,能够获取到Docker host 的网络信息。

[root@docker ~]# docker pull busybox  #下载busybox用于测试
[root@docker ~]# docker run --name xie -it --rm --network=host busybox:latest
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
    link/ether 00:0c:29:9a:72:9a brd ff:ff:ff:ff:ff:ff
    inet 192.168.100.10/24 brd 192.168.100.255 scope global noprefixroute ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::6dde:7fb9:b3da:5f30/64 scope link noprefixroute 
   # 直接使用Docker host的网络最大的好处就是性能,如果容器对网络传输效率有较高要求,则可以选择host网络。当然不便之处就
是牺牲一些灵活性,比如要考虑端口冲突问题,Docker host上已经使用的端口就不能再用了。
Bridge

Docker安装时会创建一个命名为docker0的linux bridge。如果不指定–network,创建的容器默认 都会挂到docker0上。如下示例,docker0上没有任何其他网络设备

[root@docker ~]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.0242b3ea18b5	no		
virbr0		8000.5254002f8b5d	yes		virbr0-nic

开启多个终端进行操作

[root@docker ~]# docker run --name xie -it --rm busybox:latest
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
6: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0

[root@docker ~]# brctl show
bridge name	bridge id		STP enabled	interfaces
docker0		8000.0242b3ea18b5	no		veth608ad4b
virbr0		8000.5254002f8b5d	yes		virbr0-nic

当我们使用默认网络bridge时,一个新的网络接口被挂到了docker0上,veth608ad4b就是新创建容器的虚拟网卡

5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:b3:ea:18:b5 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:b3ff:feea:18b5/64 scope link 
       valid_lft forever preferred_lft forever
7: veth608ad4b@if6: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default 
    link/ether 72:d3:f4:f9:38:f2 brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet6 fe80::70d3:f4ff:fef9:38f2/64 scope link 
       valid_lft forever preferred_lft forever

在容器创建时,如果使用默认网络,则会从docker0中随机分配ip给容器使用

自定义bridge

通过bridge驱动创建类似默认bridge的网络,当容器需要ip时,可以自动分配ip给容器,也可以加上–ip手动分配,但这个ip必须是地址池里的

[root@docker ~]# docker network create --driver bridge --subnet 192.168.0.0/24 --gateway 192.168.0.254 kami
[root@docker ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
843d308971fc   bridge    bridge    local
ecf73b7c090a   host      host      local
023449708dbd   kami      bridge    local
a8755bdfb429   none      null      local
[root@docker ~]# docker run -it --name box --rm --network=kami busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
9: eth0@if10: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:c0:a8:00:01 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.1/24 brd 192.168.0.255 scope global eth0
       valid_lft forever preferred_lft forever

手动分配

[root@docker ~]# docker run -it --name box --rm --ip 192.168.0.111 --network=kami busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
11: eth0@if12: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:c0:a8:00:6f brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.111/24 brd 192.168.0.255 scope global eth0
       valid_lft forever preferred_lft forever

创建一个默认bridge网络的容器,再创建使用kami的网络的容器,这两个容器之间是不能直接通讯的,只有指定了相同的网络的容器才能够互通,如果想要通讯,可以使用connect参数添加默认网络

[root@docker ~]# docker network connect bridge box

[root@docker ~]# docker run -it --name box --rm --ip 192.168.0.111 --network=kami busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
15: eth0@if16: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:c0:a8:00:6f brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.111/24 brd 192.168.0.255 scope global eth0
       valid_lft forever preferred_lft forever
17: eth1@if18: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth1
       valid_lft forever preferred_lft forever
/ # ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.075 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.065 ms

总结:

docker网络的类型有3种

  1. bridge(桥接网络):默认的网络模式。当Docker启动时,会自动创建一个名为docker0的虚拟网桥,并分配一个子网。除非指定其他网络,否则启动的容器会自动连接到这个桥接网络。容器之间可以通过IP地址通信,也可以通过容器名称通信(使用用户自定义的网络时)。
  2. host(主机网络):容器不会虚拟出自己的网卡,也不会分配IP,而是使用宿主机的IP和端口。这种模式可以让容器直接使用宿主机的网络接口,从而性能更好,但会牺牲一定的隔离性。
  3. none(无网络):容器有自己独立的网络栈,但不做任何网络配置,即没有网络接口、IP、路由等信息。需要用户自己手动配置。

docker容器之间的访问方式

容器之间访问可以使用以下方式

1、基于IP地址进行访问

2、基于容器名进行访问

3、多个容器共享同一个网络协议栈

注意:只有在同一个Docker网络中的容器才能够互相通讯;只有使用了默认的Bridge网络的容器是

无法使用基于容器名的方式进行容器互访的。

基于ip地址进行访问
[root@docker ~]# docker run --name xie -it --rm busybox:latest
/ # ip a
19: eth0@if20: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever

[root@docker ~]# docker run -it --name box --rm  busybox
/ # ip a
21: eth0@if22: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
       valid_lft forever preferred_lft forever
/ # ping 172.17.0.3
PING 172.17.0.3 (172.17.0.3): 56 data bytes
64 bytes from 172.17.0.3: seq=0 ttl=64 time=0.111 ms
64 bytes from 172.17.0.3: seq=1 ttl=64 time=0.064 ms

在同一个网络中的容器,是可以互相访问的

基于容器名进行访问

通过IP访问容器虽然满足了通信的需求,但还是不够灵活。因为我们在部署应用之前可能无法确定IP,部署之后再 指定要访问的IP会比较麻烦。对于这个问题,可以通过Docker自带的DNS服务解决。

从Docker 1.10版本开始,Docker daemon实现了一个内嵌的DNS server,使容器可以直接通过“容器名通信。方法很简单,只要在启动时用–name为容器命名就可以了

/ # ping box
ping: bad address 'box'

如果使用默认的bridge网络,不能用容器名进行访问

[root@docker ~]# docker run --name xie -it --rm --network=kami busybox:latest

/ # ip a
23: eth0@if24: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:c0:a8:00:01 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.1/24 brd 192.168.0.255 scope global eth0
       valid_lft forever preferred_lft forever
[root@docker ~]# docker run -it --name box --rm --network=kami busybox

/ # ip a
25: eth0@if26: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:c0:a8:00:02 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.2/24 brd 192.168.0.255 scope global eth0
       valid_lft forever preferred_lft forever

直接ping容器名进行测试

/ # ping box
PING box (192.168.0.2): 56 data bytes
64 bytes from 192.168.0.2: seq=0 ttl=64 time=0.062 ms
64 bytes from 192.168.0.2: seq=1 ttl=64 time=0.066 ms
64 bytes from 192.168.0.2: seq=2 ttl=64 time=0.060 ms

有的容器不能查看ip,直接ping容器名既能知道是否能够通讯,还能知道对方的ip地址

创建容器时,使用–name定义容器名称,当容器启动时,Docker daemon会把容器名与容 器获取的IP进行绑定,写入到Docker DNS中,这样容器之间访问就可以基于容器名实现了,如果容器停止了,该容器 所对应的DNS信息就会从Docker DNS中删除。使用Docker DNS有个限制,只能在新创建的bridge网络中使用。

joined容器

Joined(联合)容器是另一种实现容器间通信的方式。joined容器非常特别,它可以使两个或多个容器 共享一个网络栈,共享网卡和配置信息,joined容器之间可以通过127.0.0.1直接通信。

使用joined容器的方式实现容器间的通讯,需要注意的是两个容器之间的应用端口容易发生冲突, 两个容器共享一个网络栈,那么容器中的应用在运行时,绑定的IP也是一样。

[root@docker ~]# docker exec -it xie /bin/sh
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
27: eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:c0:a8:00:01 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.1/24 brd 192.168.0.255 scope global eth0
       valid_lft forever preferred_lft forever
[root@docker ~]# docker run -it --name box --rm --network=container:xie busybox
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
27: eth0@if28: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue 
    link/ether 02:42:c0:a8:00:01 brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.1/24 brd 192.168.0.255 scope global eth0
       valid_lft forever preferred_lft forever

两个容器的ip相同共享一个网络栈,可能会发生端口冲突

容器访问外部

1、 容器int_1发送Ping报文包:192.168.0.1 > www.baidu.com。

2、docker0收到报文,发现是发送到外网的,交给NAT处理。

3、NAT将源地址换成ens36的IP:192.168.100.10 > www.baidu.com。

4、Ping包从ens36发送出去,到达 www.baidu.com。

通过 NAT,docker 实现了容器对外网的访问。

如果是虚拟机,则需要进行两次nat的转换,如果是真实的服务器,则只需要进行一次的nat转换

外部访问容器

如果想实现外部访问容器,可使用host网络,容器共享Docker host网络栈,就可以实现外部访问容器。还可以使用端口映射,这也是最常用的方法

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐