1 基本概念
网络命名空间
Linux 网络命名空间是内核中隔离的网络栈,具有自己的接口,路由和防火墙规则。它负责容器和 Linux 的安全方面,用于隔离容器。
在网络术语中,它们类似于 VRF,它将主机内的网络控制和数据隔离。网络命名空间确保同一主机上的两个容器无法相互通信,甚至无法与主机本身通信,除非通过 Docker 网络进行配置。通常,Docker网络驱动程序为每个容器实现单独的命名空间。但是,容器可以共享相同的网络命名空间,甚至可以是主机网络命名空间的一部分。主机网络命名空间容纳主机接口和主机路由表。此网络命名空间称为全局网络命名空间。
虚拟以太网设备
虚拟以太网设备或简称 veth 是 Linux 网络接口,充当两个网络命名空间之间的连接线。veth 是一个全双工链接,每个命名空间中都有一个接口。一个接口中的流量被引导出另一个接口。Docker 网络驱动程序利用 veth 在创建 Docker 网络时提供名称空间之间的显式连接。当容器连接到 Docker 网络时,veth 的一端放在容器内(通常被视为 ethX 接口),而另一端连接到 Docker 网络。
2 Bridge模式
当Docker进程启动时,会在主机上创建一个名为docker0
的虚拟网桥,默认主机上启动的Docker容器会连接到这个虚拟网桥上,从docker0
子网中分配一个 IP 给容器使用,并设置 docker0 的 IP 地址为容器的默认网关。在主机上创建一对虚拟网卡veth pair
设备,Docker 将 veth pair
设备的一端放在新创建的容器中,并命名为eth0
(容器的网卡),另一端放在主机中,以vethxxx
这样类似的名字命名,并将这个网络设备加入到 docker0
网桥中。可以通过brctl show
命令查看。
bridge
模式是 docker 的默认网络模式,不写--network
参数,就是bridge
模式。使用docker run -p
时,docker 实际是在iptables做了DNAT规则,实现端口转发功能。可以使用iptables -t nat -vnL
查看。
通过这种方式,主机可以跟容器通信,容器之间也可以相互通信。我们也可以创建自定义bridge以满足个性化的网络需求。
3 Host 模式
docker run ... --network host
如果启动容器的时候使用host模式,那么这个容器将不会获得一个独立的Network Namespace,而是和宿主机共用一个 Network Namespace。容器将不会虚拟出自己的网卡,配置自己的 IP 等,而是使用宿主机的 IP 和端口,主机名也是使用宿主机的。但是,容器的其他方面,如文件系统、进程列表等还是和宿主机隔离的。
host 模式的容器可以访问主机上的其他任一容器。
4 None模式
docker run ... --network none
使用none模式,Docker 容器拥有自己的 Network Namespace,但是,并不为Docker 容器进行任何网络配置。也就是说,这个 Docker 容器没有网卡、IP、路由等信息。需要我们自己为 Docker 容器添加网卡、配置 IP 等。
5 Container模式
docker run ... --network container:已运行的容器名称|ID
在创建容器时通过参数
--network container:已运行的容器名称|ID
指定,处于这个模式下的 Docker 容器会共享一个网络栈,这样两个容器之间可以使用 localhost 高效快速通信。
Container 网络模式即新创建的容器不会创建自己的网卡,配置自己的 IP,而是和一个指定的容器共享 IP、端口范围、主机名等。同样两个容器除了网络方面相同之外,其他的如文件系统、进程列表等还是隔离的。
6 Overlay模式
overlay 使用 Swarm 分布式控制面板,在非常大规模的集群中提供集中化管理、稳定性和安全性。
启动docker swarm之后会在host上启动了2个端口,docker_gwbridge
和ingress
:
-
ingress
是overlay网络, 用来与其他容器跨host通信. -
docker_gwbridge
bridge模式的网络,通过bridge方式提供容器与host的通信,以及与外部网络通信
- 容器的网络命名空间与overlay网络的网络命名空间通过一对veth pair连接起来,当容器对外通信时,veth pair起到网线的作用,将流量发送到overlay网络的网络命名空间中。
- 容器的veth pair对端veth2与vxlan设备通过br0这个Linux bridge桥接在一起,br0在同一宿主机上起到虚拟机交换机的作用,如果目标地址在同一宿主机上,则直接通信,如果不再则通过设置在vxlan1这个vxlan设备进行跨主机通信。
- vxlan1设备上会在创建时,由docker daemon为其分配vxlan隧道ID,起到网络隔离的作用。
- docker主机集群通过key/value存储共享数据,在7946端口上,相互之间通过gossip协议学习各个宿主机上运行了哪些容器。守护进程根据这些数据来在vxlan1设备上生成静态MAC转发表。
- 根据静态MAC转发表的设置,通过UDP端口4789,将流量转发到对端宿主机的网卡上。
- 根据流量包中的vxlan隧道ID,将流量转发到对端宿主机的overlay网络的网络命名空间中。
- 对端宿主机的overlay网络的网络命名空间中br0网桥,起到虚拟交换机的作用,将流量根据MAC地址转发到对应容器内部。
7 Macvlan模式
docker run ... --network macvlan网络名
macvlan 不使用 Linux 网桥进行隔离,而是简单地与 Linux 以太网接口或子接口相关联,以强制实现网络之间的分离以及与物理网络的连接。
macvlan 驱动程序使用父接口的概念。此接口可以是物理接口,例如 eth0,用于 802.1q VLAN 标记的子接口,如 eth0.10(.10 表示 VLAN 10),或者甚至是bond接口。macvlan 子接口和原来的主接口是完全独立的,可以单独配置 MAC 地址和 IP 地址,而 VLAN 子接口和主接口共用相同的 MAC 地址。VLAN 用来划分广播域,而 macvlan 共享同一个广播域。
Docker只支持macvlan的bridge
模式,这种模式下,模拟的是 Linux bridge 的功能,但比 bridge 要好的一点是每个接口的 MAC 地址是已知的,不用学习。所以,这种模式下,子接口之间就是直接可以通信的。
Macvlan 需要物理网口开启混杂模式,这样才能接受非网卡mac 地址的数据包。
临时开启:
ip link set [interface] promisc on
永久开启:
vim /etc/sysconfig/network-scripts/ifcfg-eth1
PROMISC=yes
7.1 不同host主机,相同macvlan网络的通信
两个host创建相同的macvlan网络,将container加入进去
docker network create -d macvlan --subnet=172.16.10.0/24 --gateway=172.16.10.1 -o parent=eth0 mac1
7.2 不同host主机,不同macvlan网络的通信
由于 macvlan 网络会独占物理网卡,也就是说一张物理网卡只能创建一个 macvlan 网络,如果我们想创建多个 macvlan 网络就得用多张网卡,使用子接口解决这个问题。
将不同macvlan绑定到不同的子接口上,不同网段的互通借助外部3层IP网关解决
docker network create -d macvlan --subnet=172.16.10.0/24 --gateway=172.16.10.1 -o parent=eth0.10 mac10
docker network create -d macvlan --subnet=172.16.20.0/24 --gateway=172.16.20.1 -o parent=eth0.20 mac20
8 IPVlan模式
IPVlan 和 macvlan 类似,都是从一个主机接口虚拟出多个虚拟网络接口。一个重要的区别就是所有的虚拟接口都有相同的 mac 地址,而拥有不同的 ip 地址。因为所有的虚拟接口要共享 mac 地址,所有有些需要注意的地方:
- DHCP 协议分配 ip 的时候一般会用 mac 地址作为机器的标识。这个情况下,客户端动态获取 ip 的时候需要配置唯一的 ClientID 字段,并且 DHCP server 也要正确配置使用该字段作为机器标识,而不是使用 mac 地址
NOTE: containers不能ping通底层host接口,Linux会将他们隔离开来。
两种模式
ipvlan 有两种不同的模式:L2 和 L3。一个父接口只能选择一种模式,依附于它的所有虚拟接口都运行在这个模式下,不能混用模式。
L2模式
ipvlan L2 模式和 macvlan bridge 模式工作原理很相似,父接口作为交换机来转发子接口的数据。同一个网络的子接口可以通过父接口来转发数据,而如果想发送到其他网络,报文则会通过父接口的路由转发出去。
L3模式
L3 模式下,ipvlan 有点像路由器的功能,它在各个虚拟网络和主机网络之间进行不同网络报文的路由转发工作。只要父接口相同,即使虚拟机/容器不在同一个网络,也可以互相 ping 通对方,因为 ipvlan 会在中间做报文的转发工作。
9 网络配置
docker network COMMAND
Commands:
connect 将container连接到一个network上
create 创建一个network
disconnect 将container与network解除连接
inspect 显示network的详细信息
ls 显示当前已创建的所有network
prune 删除所有没有被使用的network
rm 删除1个或多个network
9.1 docker network create
docker network create [OPTIONS] network名字
创建一个新的网络
Options:
--attachable Enable manual container attachment
--aux-address map Auxiliary IPv4 or IPv6 addresses used by Network driver (default map[])
--config-from string The network from which to copy the configuration
--config-only Create a configuration only network
-d, --driver 网络模式,默认是bridge,可选ipvlan、macvlan、overlay
--gateway IPv4 或 IPv6 网关,不配置docker会指定subnet第1个地址X.X.X.1,如配置ip-range,指定ip-range第1个地址X.X.X.0
--ingress overlay模式,作为与其他容器跨host通信的网络时配置
--internal 限制外部访问网络
--ip-range 执行容器的IP范围,格式同subnet参数,容器不配置--ip参数,默认从这段分配ip
--ipam-driver string IP Address Management Driver (default "default")
--ipam-opt map Set IPAM driver specific options (default map[])
--ipv6 Enable IPv6 networking
--label list Set metadata on a network
-o, --opt map 设置特殊参数,eg:macvlan/ipvlan模式设置主机接口,parent=eth0/br0...
--scope Control the network's scope
--subnet 网络地址范围,eg:172.17.0.0/16
例子:
创建bridge
模式的br0
网络
docker network create \
--driver=bridge \
--subnet=172.28.0.0/16 \
--ip-range=172.28.5.0/24 \
--gateway=172.28.5.254 \
br0
创建macvlan
模式的my-macvlan-net
网络,host物理接口是eth0
docker network create -d macvlan \
--subnet=172.16.86.0/24 \
--gateway=172.16.86.1 \
-o parent=eth0 \
my-macvlan-net
9.2 docker network connect
docker network connect [OPTIONS] NETWORK名字 CONTAINER名字
将容器连接到网络,可以按名称或ID连接容器。连接后,容器可以与同一网络中的其他容器通信。
Options:
--alias strings Add network-scoped alias for the container
--driver-opt strings 网络的驱动程序选项
--ip string 指定IPv4地址
--ip6 string 指定IPv6地址
--link list Add link to another container
--link-local-ip strings 指定IPv6 link-local地址
例子:
docker network connect --ip 10.10.36.122 multi-host-network container2
9.3 docker network disconnect
docker network disconnect [OPTIONS] NETWORK名字 CONTAINER名字
断开容器与网络的连接
9.4 docker network inspect
docker network inspect [OPTIONS] NETWORK名字1 [NETWORK名字2...]
返回有关一个或多个网络的信息。默认情况下,此命令将所有结果呈现在JSON对象中。
10 docker run --link
容器需要使用另外一些容器提供的服务,使用--link
建立两个容器间通信。link是单向的,相当于在容器内添加到目标容器name或alias的host解析,可以通过容器name或alias访问目标容器。
--link=name-or-id[:alias]
alias是可选项,是为目标容器起的别名