一、容器网络概述 1. CNM
Docker 从 1.7 版本开始,便把网络和存储从 Docker 中正式以插件的形式剥离开来,并且分别为其定义了标准。Docker 定义的网络模型标准称之为 CNM(Container Network Model)
CNM 抽象了容器的网络接口,使得只要满足 CNM 接口的网络方案都可以接入到 Docker 容器网络,更好地满足了用户网络模型多样化的需求
CNM 定义的网络标准包含三个重要元素:
沙箱(Sandbox) :沙箱代表了一系列网络堆栈的配置,包含路由信息、网络接口等网络资源的管理。沙箱的实现通常是 Linux 的 Net Namespace,也可以通过其他技术来实现,比如 FreeBSD jail 等
接入点(Endpoint) :接入点将沙箱连接到网络中,代表容器的网络接口。接入点的实现通常是 Linux 的 veth 设备对
网络(Network) :网络是一组可以互相通信的接入点,它将多个接入点组成一个子网
Docker 团队把网络功能从 Docker 中剥离出来,成为独立的项目 libnetwork,它通过插件的形式为 Docker 提供网络功能。Libnetwork 是开源的,使用 Golang 编写,它完全遵循 CNM 网络规范,是 CNM 的官方实现
Docker 推出 CNM 的同时,CoreOS 推出了 CNI(Container Network Model)。起初,以 Kubernetes 为代表的容器编排阵营考虑过使用 CNM 作为容器的网络标准,但是后来由于很多技术和非技术原因 ,Kubernetes 决定支持 CoreOS 推出的容器网络标准 CNI
2. Libnetwork
Libnetwork 是 Docker 启动容器时,用来为 Docker 容器提供网络接入功能的插件。它可以让 Docker 容器顺利接入网络,实现主机和容器网络的互通
第一步,Docker 通过调用 libnetwork.New
创建 NetworkController 实例
第二步,通过调用 NewNetwork
创建指定名称和类型的 Network
1 2 3 4 5 type NetworkController interface { NewNetwork(networkType, name string , id string , options ...NetworkOption) (Network, error ) }
第三步,通过调用 CreateEndpoint
来创建接入点,并为容器分配 IP 和网卡接口
1 2 3 4 5 6 7 type Network interface { CreateEndpoint(name string , options ...EndpointOption) (Endpoint, error ) Delete() error }
第四步,通过调用 NewSandbox
创建容器沙箱,主要是初始化 Namespace 相关的资源
第五步,通过调用 Join
将沙箱和网络接入点关联起来,此时容器就加入了 Docker 网络并具备了网络访问能力
1 2 3 4 5 6 7 type Endpoint interface { Join(sandbox Sandbox, options ...EndpointOption) error Delete(force bool ) error }
二、Libnetwork 常见网络模式 1. null 空网络模式
一个隔离的网络环境,容器有自己独立的 Net Namespace,但没有创建任何网卡接口、IP 地址、路由等网络配置
1 2 3 4 5 6 7 8 9 10 11 $ docker run --net=none -it busybox / 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 / Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface
2. bridge 桥接模式
默认的网络模式,使用 bridge 网络可以实现容器与容器的互通以及主机与容器的互通
底层原理:
Linux veth:一个虚拟设备接口,成对出现,它在容器中通常充当一个桥梁,用来连接虚拟网络设备。可以用来连通两个 Net Namespace
Linux bridge:一个用来连接网络的虚拟设备,相当于物理网络环境中的交换机。可以用来转发两个 Net Namespace 内的流量
bridge 就像一台交换机,而 veth 就像一根网线,通过交换机和网线可以把两个不同 Net Namespace 的容器连通,使得它们可以互相通信
Docker 启动时,Libnetwork 会在主机上创建 docker0 网桥,docker0 网桥就相当于上图的交换机,而 Docker 创建出的 brige 模式的容器则都会连接 docker0 上,从而实现网络互通
1 2 3 4 5 6 $ ip a ...... 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default link /ether 02:42:84:78:c0:dc 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
3. host 主机网络模式
使用 host 主机网络模式时:
Libnetwork 不会为容器创建新的网络配置和 Net Namespace
Docker 容器中的进程直接共享主机的网络配置,可以直接使用主机的网络信息 ,此时在容器内监听的端口,也将直接占用到主机的端口
除了共享主机的网络外,其他的包括进程、文件系统、主机名等都是与主机隔离的
1 2 3 4 5 $ docker run -it --net=host busybox / 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000 2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue
4. container 网络模式
允许一个容器共享另一个容器的网络命名空间 。当两个容器需要共享网络,但其他资源仍然需要隔离时就可以使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $ docker run -d --name=busybox1 busybox sleep 3600 $ docker exec -it busybox1 sh / 4: eth0@if5: <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 $ docker run -it --net=container:busybox1 --name=busybox2 busybox sh / 4: eth0@if5: <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