Docker容器网络栈管理全解析
1. 网络控制器概述
网络控制器在Docker容器和Docker引擎之间的网络管理中起着关键作用。每个网络控制器会引用以下内容:
- 数据结构驱动表中的一个或多个驱动。
- 数据结构中的一个或多个沙箱。
- 一个数据存储。
- 一个IP地址管理表(ipamTable)。
网络控制器位于Docker引擎、容器以及它们所连接的网络之间,负责协调和管理网络通信。
2. CNM属性
CNM(Container Network Model)具有以下重要属性:
2.1 选项(Options)
选项是用户不可见的键值对数据,用于提供一种灵活的机制,将特定于驱动程序的配置直接从用户传递给驱动程序。只有当键与已知标签匹配时,libnetwork才会对这些选项进行操作,并获取由通用对象表示的值。
2.2 标签(Labels)
标签是选项的一个子集,是最终用户可通过UI使用
--labels
选项设置的变量。其主要功能是执行特定于驱动程序的操作,并且这些标签是从UI传递过来的。
3. CNM生命周期
CNM的使用者通过CNM对象及其API来为他们管理的容器建立网络连接。驱动程序会向网络控制器进行注册,其中内置驱动程序在libnetwork内部注册,而远程驱动程序则使用插件机制向libnetwork注册。
3.1 网络和端点的创建与管理
-
网络控制器对象创建
:使用
libnetwork.New()API创建网络控制器对象,用于管理网络的分配,并可选择使用特定于驱动程序的选项配置驱动程序。 -
网络对象创建
:使用控制器的
NewNetwork()API创建网络对象,需要提供名称和NetworkType作为参数。NetworkType参数有助于选择驱动程序,并将创建的网络绑定到该驱动程序上。所有网络操作都将由使用上述API创建的驱动程序处理。 -
端点创建
:调用
Network.CreateEndpoint()在给定网络中创建新的端点。此API还接受随驱动程序而异的可选选项参数。创建端点时,CreateEndpoint()可以选择预留IPv4/IPv6地址,驱动程序使用driverapi中定义的InterfaceInfo接口分配这些地址。 -
容器连接到端点
:使用
Endpoint.Join()将容器连接到端点。如果该容器没有沙箱,此操作将创建一个沙箱。驱动程序使用沙箱键来识别连接到同一容器的多个端点。
3.2 端点和网络的删除操作
-
端点离开
:当容器停止时,调用
Endpoint.Leave()。驱动程序可以清理在Join()调用期间分配的状态。当最后一个引用端点离开网络时,libnetwork会删除沙箱。只要端点仍然存在,libnetwork就会保留IP地址,以便容器再次加入时可以重用这些资源。 -
端点删除
:
Endpoint.Delete()用于从网络中删除端点,这将导致删除端点并清理缓存的沙箱信息。 -
网络删除
:
Network.Delete()用于删除网络,但只有在网络没有连接的端点时才允许删除。
以下是CNM生命周期的mermaid流程图:
graph LR
A[创建网络控制器对象] --> B[创建网络对象]
B --> C[创建端点]
C --> D[容器连接到端点]
D --> E{容器停止?}
E -- 是 --> F[端点离开]
F --> G{最后一个端点离开?}
G -- 是 --> H[删除沙箱]
C --> I[删除端点]
B --> J{无端点连接?}
J -- 是 --> K[删除网络]
E -- 否 --> D
G -- 否 --> F
4. 基于覆盖和底层网络的Docker网络工具
4.1 覆盖网络概述
覆盖网络是构建在底层网络基础设施之上的虚拟网络,其目的是实现物理网络中不可用的网络服务。网络覆盖显著增加了可以在物理网络之上创建的虚拟子网数量,从而支持多租户和虚拟化功能。
在Docker中,每个容器都被分配一个IP地址,用于与其他容器进行通信。如果容器需要与外部网络通信,则需要在主机系统中设置网络,并将容器的端口暴露或映射到主机上。但由于容器无法获取外部IP和端口信息,因此无法宣传这些信息。解决方案是为每个Docker容器在所有主机上分配唯一的IP地址,并使用一些网络产品来路由主机之间的流量。
4.2 常见的Docker网络工具
4.2.1 Flannel
Flannel为每个容器分配一个可用于容器间通信的IP地址。它通过数据包封装在主机网络上创建一个虚拟覆盖网络。默认情况下,Flannel为每个主机提供一个
/24
子网,Docker守护进程将从该子网中为容器分配IP地址。
Flannel在每个主机上运行一个代理
flanneld
,负责从预配置的地址空间中分配子网租约。它使用etcd(https://github.com/coreos/etcd)来存储网络配置、已分配的子网和辅助数据(如主机的IP地址)。为了提供封装,Flannel使用通用TUN/TAP设备,并使用UDP封装IP数据包来创建覆盖网络。子网分配借助etcd完成,etcd维护着覆盖子网与主机的映射关系。
4.2.2 Weave
Weave创建一个虚拟网络,连接部署在不同主机/VM上的Docker容器,并实现它们的自动发现。Weave可以穿越防火墙,在部分连接的网络中运行,并且可以选择对流量进行加密,从而允许在不可信网络上连接主机/VM。Weave增强了Docker现有的(单主机)网络功能,如
docker0
桥,以便容器可以继续使用这些功能。
4.2.3 Project Calico
Project Calico为连接容器、VM或裸机提供了可扩展的网络解决方案。它采用可扩展的IP网络原理作为第3层方法来提供连接性,并且可以在不使用覆盖或封装的情况下进行部署。Calico服务应作为容器部署在每个节点上,为每个容器提供自己的IP地址,并处理所有必要的IP路由、安全策略规则以及跨节点集群的路由分发。
Calico架构包含四个重要组件:
-
Felix
:Calico的工作进程,是Calico网络的核心,主要负责路由并为宿主上的工作负载提供所需的连接性,还为外出端点流量提供与内核的接口。
-
BIRD
:开源的BGP路由分发器,用于在主机之间交换路由信息。BIRD将内核端点信息分发给BGP对等体,以提供主机间的路由。在
calico-node
容器中运行两个BIRD进程,分别用于IPv4(bird)和IPv6(bird6)。
-
confd
:一个模板化进程,用于自动生成BIRD的配置文件。它监视etcd存储,以获取BGP配置的任何更改,如日志级别和IPAM信息。根据etcd中的数据动态生成BIRD配置文件,并在数据更新时自动触发BIRD加载新文件。
-
calicoctl
:用于配置和启动Calico服务的命令行工具。它允许在数据存储(etcd)中定义和应用安全策略,还为Calico配置的一般管理提供了简单的接口,支持以下命令:
$ calicoctl
Override the host:port of the ETCD server by setting the environment
variable
ETCD_AUTHORITY [default: 127.0.0.1:2379]
Usage: calicoctl <command> [<args>...]
status Print current status information
node Configure the main calico/node container and establish
Calico networking
container Configure containers and their addresses
profile Configure endpoint profiles
endpoint Configure the endpoints assigned to existing containers
pool Configure ip-pools
bgp Configure global bgp
ipam Configure IP address management
checksystem Check for incompatibilities on the host system
diags Save diagnostic information
version Display the version of calicoctl
config Configure low-level component configuration
See 'calicoctl <command> --help' to read about a specific subcommand.
Calico有多种集成方式,包括作为Docker网络插件、不使用Docker网络、与Kubernetes集成、与Mesos集成以及与Docker Swarm集成等。
5. 多主机Docker网络解决方案比较
| 解决方案 | 网络模型 | 名称服务 | 协议支持 | 分布式存储 | 加密通道 |
|---|---|---|---|---|---|
| Calico | 第3层解决方案 | 否 | TCP,UDP, ICMP & ICMPv6 | 是 | 否 |
| Flannel | VxLAN或UDP | 否 | 所有 | 是 | TLS |
| Weave | VxLAN或UDP | 是 | 所有 | 否 | NaCI库 |
| Docker覆盖网络 | VxLAN | 否 | 所有 | 是 | 否 |
6. 配置Docker引擎Swarm节点的覆盖网络
随着Docker 1.9的发布,多主机和覆盖网络成为其主要特性之一,它能够建立私有网络以连接多个容器。下面将介绍如何在不使用外部键值存储的情况下,在Swarm集群的管理节点上创建覆盖网络,使Swarm网络为需要该网络的服务节点提供服务。
6.1 安装Docker Machine
使用Docker Machine应用程序在虚拟化或云平台上创建Docker守护进程,以VMware Fusion作为虚拟化平台为例,安装步骤如下:
$ curl -L https://github.com/docker/machine/releases/download/v0.7.0/docker-machine-`uname -s`-`uname -m` > /usr/local/bin/docker-machine && \
> chmod +x /usr/local/bin/docker-machine
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 601 0 601 0 0 266 0 --:--:-- 0:00:02 --:--:-- 266
100 38.8M 100 38.8M 0 0 1420k 0 0:00:28 0:00:28 --:--:-- 1989k
$ docker-machine version
docker-machine version 0.7.0, build a650a40
6.2 创建服务发现的Docker Machine和Consul容器
多主机网络需要一个服务发现存储,因此创建一个Docker Machine来运行该服务:
$ docker-machine create \
> -d vmwarefusion \
> swarm-consul
Running pre-create checks...
(swarm-consul) Default Boot2Docker ISO is out-of-date, downloading the latest
release...
(swarm-consul) Latest release for github.com/boot2docker/boot2docker is v1.12.1
(swarm-consul) Downloading...
To see how to connect your Docker client to the Docker Engine running on this virtual machine, run docker-machine env swarm-consul.
启动Consul容器进行服务发现:
$(docker-machine config swarm-consul) run \
> -d \
> --restart=always \
> -p "8500:8500" \
> -h "consul" \
> progrium/consul -server -bootstrap
Unable to find image 'progrium/consul:latest' locally
latest: Pulling from progrium/consul
...
Digest: sha256:8cc8023462905929df9a79ff67ee435a36848ce7a10f18d6d0faba9306b97274
Status: Downloaded newer image for progrium/consul:latest
d482c88d6a1ab3792aa4d6a3eb5e304733ff4d622956f40d6c792610ea3ed312
6.3 创建Docker集群的节点
创建两个Docker守护进程来运行Docker集群,第一个是Swarm主节点,会自动运行一个Swarm容器来协调集群:
$ docker-machine create \
> -d vmwarefusion \
> --swarm \
> --swarm-master \
> --swarm-discovery="consul://$(docker-machine ip swarm-consul):8500" \
> --engine-opt="cluster-store=consul://$(docker-machine ip swarm-consul):8500" \
> --engine-opt="cluster-advertise=eth0:2376" \
> swarm-0
Running pre-create checks...
Creating machine...
(swarm-0) Copying /Users/vkohli/.docker/machine/cache/boot2docker.iso to /Users/vkohli/.docker/machine/machines/swarm-0/boot2docker.iso...
(swarm-0) Creating SSH key...
(swarm-0) Creating VM...
...
Docker is up and running!
To see how to connect your Docker client to the Docker Engine running on this virtual machine, run docker-machine env swarm-0.
第二个是Swarm辅助节点,会自动运行一个Swarm容器并将状态报告回主节点:
$ docker-machine create \
> -d vmwarefusion \
> --swarm \
> --swarm-discovery="consul://$(docker-machine ip swarm-consul):8500" \
> --engine-opt="cluster-store=consul://$(docker-machine ip swarm-consul):8500" \
> --engine-opt="cluster-advertise=eth0:2376" \
> swarm-1
Running pre-create checks...
Creating machine...
(swarm-1) Copying /Users/vkohli/.docker/machine/cache/boot2docker.iso to /Users/vkohli/.docker/machine/machines/swarm-1/boot2docker.iso...
(swarm-1) Creating SSH key...
(swarm-1) Creating VM...
...
Docker is up and running!
To see how to connect your Docker client to the Docker Engine running on this virtual machine, run docker-machine env swarm-1.
6.4 配置Docker客户端与集群通信并创建网络和容器
确保Docker客户端与集群中的Docker守护进程通信:
$ eval $(docker-machine env --swarm swarm-0)
创建一个使用覆盖驱动的私有
prod
网络:
$ docker $(docker-machine config swarm-0) network create --driver overlay prod
启动两个使用
prod
网络的
ubuntu:12.04
容器:
$ docker run -d -it --net prod --name dev-vm-1 ubuntu:12.04
426f39dbcb87b35c977706c3484bee20ae3296ec83100926160a39190451e57a
$ docker run -d -it --net prod --name dev-vm-7 ubuntu:12.04
d073f52a7eaacc0e0cb925b65abffd17a588e6178c87183ae5e35b98b36c0c25
查看容器的网络接口信息:
$ docker attach 426
root@426f39dbcb87:/# ip address
23: eth0@if24: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP
link/ether 02:42:0a:00:00:02 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.2/24 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:aff:fe00:2/64 scope link
valid_lft forever preferred_lft forever
25: eth1@if26: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.2/16 scope global eth1
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe12:2/64 scope link
valid_lft forever preferred_lft forever
$ docker attach d073
root@d073f52a7eaa:/# ip address
26: eth0@if27: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP
link/ether 02:42:0a:00:00:03 brd ff:ff:ff:ff:ff:ff
inet 10.0.0.3/24 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:aff:fe00:3/64 scope link
valid_lft forever preferred_lft forever
28: eth1@if29: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:12:00:02 brd ff:ff:ff:ff:ff:ff
inet 172.18.0.2/16 scope global eth1
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe12:2/64 scope link
valid_lft forever preferred_lft forever
root@d073f52a7eaa:/#
以下是创建覆盖网络的mermaid流程图:
graph LR
A[安装Docker Machine] --> B[创建服务发现的Docker Machine]
B --> C[启动Consul容器]
C --> D[创建Swarm主节点]
D --> E[创建Swarm辅助节点]
E --> F[配置Docker客户端与集群通信]
F --> G[创建覆盖网络]
G --> H[启动容器并使用覆盖网络]
7. 配置OpenvSwitch(OVS)与Docker协同工作
7.1 OVS概述
Open vSwitch(OVS)是一个开源的支持OpenFlow的虚拟交换机,通常与虚拟机管理程序一起使用,用于在主机内和跨网络的不同主机之间互连虚拟机。覆盖网络需要使用支持的隧道封装(如VXLAN或GRE)创建虚拟数据路径,OVS在Docker主机的隧道端点之间提供覆盖数据路径,使给定提供商段内的所有主机看起来直接相互连接。
7.2 OVS与Docker通信原理
当新容器上线时,路由协议会更新前缀以通过隧道端点宣布其位置。其他Docker主机接收到更新后,会在OVS中安装转发规则,指示数据包应通过哪个隧道端点转发。当主机被停用,类似的过程会发生,隧道端点的Docker主机会删除停用容器的转发条目。
7.3 单主机OVS配置与测试
在单主机上安装OVS并配置两个容器连接到OVS桥的步骤如下:
1. 安装OVS:
$ sudo apt-get install openvswitch-switch
-
安装
ovs-docker实用程序:
$ cd /usr/bin
$ wget https://raw.githubusercontent.com/openvswitch/ovs/master/utilities/ovs-docker
$ chmod a+rwx ovs-docker
- 创建OVS桥:
$ ovs-vsctl add-br ovs-br1
$ ifconfig ovs-br1 173.16.1.1 netmask 255.255.255.0 up
-
创建两个
ubuntuDocker容器:
$ docker run -i-t --name container1 ubuntu /bin/bash
$ docker run -i-t --name container2 ubuntu /bin/bash
- 将容器连接到OVS桥:
# ovs-docker add-port ovs-br1 eth1 container1 --ipaddress=173.16.1.2/24
# ovs-docker add-port ovs-br1 eth1 container2 --ipaddress=173.16.1.3/24
- 测试两个容器之间的连接:
# docker exec container1 ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:ac:10:11:02
inet addr:172.16.17.2 Bcast:0.0.0.0 Mask:255.255.255.0
inet6 addr: fe80::42:acff:fe10:1102/64 Scope:Link
...
# docker exec container2 ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:ac:10:11:03
inet addr:172.16.17.3 Bcast:0.0.0.0 Mask:255.255.255.0
inet6 addr: fe80::42:acff:fe10:1103/64 Scope:Link
...
# docker exec container2 ping 172.16.17.2
PING 172.16.17.2 (172.16.17.2) 56(84) bytes of data.
64 bytes from 172.16.17.2: icmp_seq=1 ttl=64 time=0.257 ms
64 bytes from 172.16.17.2: icmp_seq=2 ttl=64 time=0.048 ms
64 bytes from 172.16.17.2: icmp_seq=3 ttl=64 time=0.052 ms
# docker exec container1 ping 172.16.17.2
PING 172.16.17.2 (172.16.17.2) 56(84) bytes of data.
64 bytes from 172.16.17.2: icmp_seq=1 ttl=64 time=0.060 ms
64 bytes from 172.16.17.2: icmp_seq=2 ttl=64 time=0.035 ms
64 bytes from 172.16.17.2: icmp_seq=3 ttl=64 time=0.031 ms
通过以上步骤,可以实现Docker容器网络栈的有效管理,包括网络控制器的使用、CNM的操作、不同网络工具的应用以及OVS与Docker的协同工作,为容器化应用提供稳定、高效的网络环境。
超级会员免费看
687

被折叠的 条评论
为什么被折叠?



