介绍

  • None:不为容器配置任何网络功能,–net=none
  • Bridge:Docker设计的NAT网络模型(默认)
  • Container:与另一个运行中的容器共享Network Namespace,–net=container:containerID(K8S)
  • Host:与宿主机共享Network Namespace,–net=host 性能最高

image-20200728171247040

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 启动一台容器
[root@docker01 ~]# docker run -d -P --name tomcat01 tomcat

# 查看容器的网卡信息
[root@docker01 ~]# docker exec -it tomcat01 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
21: eth0@if22: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever

# linux宿主机可以ping通容器内部
[root@docker01 ~]# ping 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.060 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.053 ms

原理:

  • 每启动一个docker容器,docker都会给容器分配一个ip,我们只要安装了docker,就会有一个网卡docker0,Bridge桥接模式使用的技术是evth-pair技术。
  • evth-pair 就是一对虚拟设备接口,他们都是成对出现的,一段连着协议,一段彼此相连,正因为有这个特性,evth-pair充当一个桥梁,专门连接各种虚拟网络设备。每开启运行一个容器,就会增加一对 对应的网卡。
  • Openstack、Docker、OVS都是使用的 evth-pair技术。
  • 容器删除,对应的网桥也被删除

None模式

使用none模式,Docker 容器拥有自己的 Network Namespace,但是,并不为Docker 容器进行任何网络配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。需要我们自己为 Docker 容器添加网卡、配置 IP 等。

1
2
3
4
5
6
7
8
9
# 运行一个none模式的容器
docker run -it -d --name centos-none --network none centos

# 进入容器查看网卡发现没有ip地址
[root@docker01 ~]# docker exec -it centos-none ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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

Bridge模式

Docker进程启动时,会在主机上创建一个名为docker0的虚拟网桥,此主机上启动的Docker容器会连接到这个虚拟网桥上。虚拟网桥的工作方式和物理交换机类似,这样主机上的所有容器就通过交换机连在了一个二层网络中。从docker0子网中分配一个 IP 给容器使用,并设置 docker0 的 IP 地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair设备,Docker 将 veth pair 设备的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样类似的名字命名,并将这个网络设备加入到 docker0 网桥中。可以通过brctl show命令查看。

bridge模式是 docker 的默认网络模式,不写–net参数,就是bridge模式。使用docker run -p时,docker 实际是在iptables做了DNAT规则,实现端口转发功能。可以使用iptables -t nat -vnL查看。

自定义网络

查看网络

1
2
3
4
5
[root@docker01 ~]# docker network ls
NETWORK ID NAME DRIVER SCOPE
1eda1ef538b0 bridge bridge local
208c3474ff10 host host local
b4129f3c1c5e none null local
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# 清除测试的所有容器
docker rm -f $(docker ps -aq)

# 创建一台容器; --network brigde 就是docker0
docker run -d -P --name tomcat01 --network bridge tomcat

# 创建一个网络mynet
# --driver : 网络模式
# --subnet : 子网地址
# --gateway : 子网的网关地址
docker network create --driver bridge --subnet 172.20.0.0/16 --gateway 172.20.0.1 mynet

# 查看自己创建的网络详细信息
[root@docker01 ~]# docker network inspect mynet
[
{
"Name": "mynet",
"Id": "ea720ae53f20b83193bca0c1dbb6296165539aa4c547f1ef37028e705b87da6c",
"Created": "2020-06-29T14:33:22.194817791+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": {},
"Config": [
{
"Subnet": "172.20.0.0/16", #子网
"Gateway": "172.20.0.1" #网关
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {},
"Options": {},
"Labels": {}
}
]

启动两台容器;指定创建的自定义网络

1
2
docker run -d -P --name tomcat-net01 --net mynet tomcat
docker run -d -P --name tomcat-net02 --net mynet tomcat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 再次查看网络详情,可以看到启动的容器的IP
[root@docker01 ~]# docker network inspect mynet
....
"Containers": {
"2767e468d20157e43b67174eeef94267ce2b3a5b9f66446b24fd17c06549fdb3": {
"Name": "tomcat-net01",
"EndpointID": "abadd831f2591a0d2aed089abac60292cfc0925193d6f3394131955140118750",
"MacAddress": "02:42:ac:14:00:02",
"IPv4Address": "172.20.0.2/16",
"IPv6Address": ""
},
"4a70bba89baf3e98b4f3e35de9ee19d5363f06c592dff2bf81134fbc187ac0a0": {
"Name": "tomcat-net02",
"EndpointID": "8cdf9df77303ec7c3562e4b216d09ac5c5a39a7d7a5a1563b93ea7f5fd4d5060",
"MacAddress": "02:42:ac:14:00:03",
"IPv4Address": "172.20.0.3/16",
"IPv6Address": ""
}
},

# 再次测试ping连接; ping主机名也可以ping通了
[root@docker01 ~]# docker exec -it tomcat-net01 ping 172.20.0.3
PING 172.20.0.3 (172.20.0.3) 56(84) bytes of data.
64 bytes from 172.20.0.3: icmp_seq=1 ttl=64 time=0.111 ms

[root@docker01 ~]# docker exec -it tomcat-net01 ping tomcat-net02
PING tomcat-net02 (172.20.0.3) 56(84) bytes of data.
64 bytes from tomcat-net02.mynet (172.20.0.3): icmp_seq=1 ttl=64 time=0.042 ms

--------------------------------------
##现在不使用--link也可以ping通主机名了

自定义Docker0桥

自定义docker0桥的网络属性信息:/etc/docker/daemon.json文件

1
2
3
4
5
6
7
8
9
{
"bip" :"192.168.1.5/24"
"fixed-cidr" : "10.20.0.0/16",
"fixed-cidr-v6" :m2001:db8: :/64",
"mtu" : 1500,
"default-gateway" : "10.20.1.1".
"default-gateway-v6" : "2001:db8:abcd : :89",
"dns" : [ "i0.20.1.2", "10.20.1.3"]
}

核心选项为bip,即bridge ip之意,用于指定dockerO桥自身的IP地址;其它选项可通过此地址计算得出。

Container 模式

这个模式指定新创建的容器和已经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。两个容器的进程可以通过lo网卡设备通信。

具体解释:

  • 联盟式容器是指使用某个已存在容器的网络接口的容器,接口被联盟内的各容器共享使用;因此,联盟式容器彼此间完全无隔离,例如
    • 创建一个监听于2222端口的http服务容器
      ~]# docker run-d -it –rm -p 2222 busybox:latest /bin/httpd-p 2222-f
    • 创建一个联盟式容器,并查看其监听的端口
      ~]# docker run -it –rm –net container:web –name joined busybox:latest netstat -tan
  • 联盟式容器彼此间虽然共享同一个网络名称空间,但其它名称空间如User、Mount等还是隔离的
  • 联盟式容器彼此间存在端口冲突的可能性,因此,通常只会在多个容器上的程序需要程序loopback接口互相通信、或对某已存的容器的网络属性进行监控时才使用此种模式的网络模型
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 运行一个centos镜像容器
[root@docker01 ~]# docker run -it -d --name centos01 centos
[root@docker01 ~]# docker exec -it centos01 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
28: eth0@if29: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
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

# 运行一个Container模式的容器; 指定centos01容器;查看网络
[root@docker01 ~]# docker run -it -d --name centos-container --network container:centos01 centos
[root@docker01 ~]# docker exec -it centos-container ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
28: eth0@if29: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
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

Host 模式

如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# 运行一个host网络的容器
docker run -it -d -P --name tomcat-host01 --net host tomcat

# 查看此容器的ip地址和宿主机一致
[root@docker01 ~]# docker exec -it tomcat-host01 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:8a:1a:eb brd ff:ff:ff:ff:ff:ff
inet 192.168.0.10/24 brd 192.168.0.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe8a:1aeb/64 scope link
valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:8a:1a:f5 brd ff:ff:ff:ff:ff:ff
inet 172.16.0.10/24 brd 172.16.0.255 scope global eth1
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe8a:1af5/64 scope link
valid_lft forever preferred_lft forever
4: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:8d:a8:1d:4b 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:8dff:fea8:1d4b/64 scope link
valid_lft forever preferred_lft forever
21: br-45945e527658: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:16:06:bd:c9 brd ff:ff:ff:ff:ff:ff
inet 172.20.0.1/16 brd 172.20.255.255 scope global br-45945e527658
valid_lft forever preferred_lft forever
inet6 fe80::42:16ff:fe06:bdc9/64 scope link
valid_lft forever preferred_lft forever

网络联通

image-20200730122834771

image-20200730122902119

1
2
3
# 用bridge模式的容器去ping自定义网络的容器;发现ping不通,因为网络不同
[root@docker01 ~]# docker exec -it tomcat01 ping tomcat-net01
ping: tomcat-net01: Name or service not known

测试 将默认 bridge 模式的容器 tomcat01 和 自定义 mynet 网络打通

1
docker network connect mynet tomcat01

image-20200730124916203

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 一个容器 两个ip地址!
root@docker01 ~]# docker exec -it tomcat01 ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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
32: eth0@if33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
40: eth1@if41: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:14:00:04 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.20.0.4/16 brd 172.20.255.255 scope global eth1
valid_lft forever preferred_lft forever

# 可以ping通了
[root@docker01 ~]# docker exec -it tomcat01 ping tomcat-net01
PING tomcat-net01 (172.20.0.2) 56(84) bytes of data.
64 bytes from tomcat-net01.mynet (172.20.0.2): icmp_seq=1 ttl=64 time=0.045 ms

# 而其他的是依旧ping不通的
[root@docker01 ~]# docker exec -it tomcat02 ping tomcat-net01
ping: tomcat-net01: Name or service not known

总结:如果要跨网络操作其他容器,就需要使用 docker network connect连通。