网络

网络

DockOne微信分享(一九八):容器网络限流实践

范彬 发表了文章 • 0 个评论 • 1162 次浏览 • 2019-01-09 09:51 • 来自相关话题

【编者的话】我们需要为“上云“的应用提供流量带宽保证,使其不受到其他应用或其他用户的应用的影响。我们需要提供租户级别或者应用级别的有效隔离。今天将分享一下我们为了达到这个目标做了哪些实践工作。 # 容器平台做容器网络限流的意义 无论我们 ...查看全部
【编者的话】我们需要为“上云“的应用提供流量带宽保证,使其不受到其他应用或其他用户的应用的影响。我们需要提供租户级别或者应用级别的有效隔离。今天将分享一下我们为了达到这个目标做了哪些实践工作。
# 容器平台做容器网络限流的意义
无论我们的目标是搭建公有云的容器云平台还是为客户提供容器平台的私有部署或解决方案,我们都会面临一个问题:容器网络限流的问题。在我们实验室的环境下,如果没有对容器带宽进行限制,单Pod使用的最大吞吐量将可以独占整个带宽,从而导致其他应用不能被访问。

单用户单Pod在没有做任何网络带宽限制情况下,网络吞吐量测试结果如下:
0.png

我们需要为“上云”的应用提供流量带宽保证,使其不受到其他应用或其他用户的应用的影响。我们需要提供租户级别或者应用级别的有效隔离。今天将分享一下我们为了达到这个目标做了哪些实践工作。

在Kubernetes众多的网络插件中,我们选择使用Open vSwitch容器网络插件。通常情况下,我们根据VNID实现租户间的网络隔离,并且在此基础上我们还可以根据Networkpolicy网络策略提供更细粒度的网络隔离,可以实现Pod之间、跨Namespace的网络访问控制。
1.png

# 使用Open vSwitch容器网络插件如何进行容器网络限流
使用Open vSwitch容器网络插件如何进行容器网络限流呢?Open vSwitch本身不实现QoS,它使用Linux内核自带的traffic-control机制进行流量控制。主要两种实现方式:

* Policing管制:Policing用于控制接口上接收分组(ingress)的速率,是一种简单的QoS的功能,通过简单的丢包机制实现接口速率的限制,它既可以作用于物理接口,也可以作用于虚拟接口。
* Shaping整形:Shaping是作用于接口上的出口流量(egress)策略,可以实现QoS队列,不同队列里面处理不同策略。

2.png

##Policing的实现
Policing在OVS中采用ingress_policing_rate和ingress_policing_burst两个字段完成ingress入口限速功能,该两个字段放在Interface表中。

入口限速直接配置在网络接口上,命令示例如下:
# ovs-vsctl set interface eth1 ingress_policing_rate=1000
# ovs-vsctl set interface eth1 ingress_policing_burst=100


* eth1:加入OVS桥端口的网络接口名称;
* ingress_policing_rate:为接口最大收包速率,单位kbps,超过该速度的报文将被丢弃,默认值为0表示关闭该功能;
* ingress_policing_burst:为最大突发流量大小,单位kb。默认值0表示1000kb,这个参数最小值应不小于接口的MTU,通常设置为ingress_policing_rate的10%更有利于tcp实现全速率;

通过命令ovs-vsctl list interface eth1可以查看配置:
OpenvSwitch-QoS-fig-1.png

##Shaping的实现
Shaping用于实现出口流量的控制,使用了队列Queue,可以缓存和调度数据包发送顺序,比Policing更加精确和有效,在OVS的数据表中主要使用QoS和Queue两张表。

QoS创建命令:
ovs-vsctl set port eth1 qos=@newqos--  
--id=@newqoscreate qos type=linux-htb queues=0=@q0--
--id=@q0create queue other-config:max-rate=100000000

创建Queue:
--id=@q0 create queue other-config:max-rate=100000000

创建q0队列,设置最大速率100M,通过ovs-vsctl查看配置的Queue表内容如下:
OpenvSwitch-QoS-fig-4.png

创建Qos规则:
--id=@newqos create qos type=linux-htb queues=0=@q0

创建QoS规则newqos,类型为linux-htb,并连接key值为0的队列q0,通过ovs-vsctl查看配置的QoS表内容如下:
OpenvSwitch-QoS-fig-5.png

创建接口Qos:
set port eth1 qos=@newqos

设置接口eth1的QoS为newqos,通过ovs-vsctl list port查看配置的port表内容如下:
OpenvSwitch-QoS-fig-6.png

我们采用的技术栈是Golang。我们也可以使用红帽提供的OVS的库github.com/openshift/origin/pkg/util/ovs实现上面Policing和Shaping功能。

代码示意如下:
image.png

image1.png

在Kubernetes上,如果使用Open vSwitch CNI插件,我们可以在创建Pod资源的时候为其配置速率限制。

创建iperf-pod.yaml,并为其配置速率限制:
cat <iperf-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: iperf
annotations:
kubernetes.io/ingress-bandwidth: 3M
kubernetes.io/egress-bandwidth: 3M
spec:
containers:
- name: iperf
image: yadu/hello-openshift-iperf
imagePullPolicy: IfNotPresent
nodeSelector:
zone: default
EOF

流入测试:

Pod容器里启动iperf server:
$ iperf -s -p 12345 -i 1
------------------------------------------------------------
Server listening on TCP port 12345
TCP window size: 85.3 KByte (default)
------------------------------------------------------------

在任意节点向iperf server产生流量:
[root@a-node4 ~]# iperf -c 10.130.2.103 -p 12345 -i 1 -t 10 -w 5m
------------------------------------------------------------
Client connecting to 10.130.2.103, TCP port 12345
TCP window size: 416 KByte (WARNING: requested 4.77 MByte)
------------------------------------------------------------
[ 3] local 10.130.2.1 port 58162 connected with 10.130.2.103 port 12345
[ ID] Interval Transfer Bandwidth
[ 3] 0.0- 1.0 sec 773 KBytes 6.33 Mbits/sec
[ 3] 1.0- 2.0 sec 316 KBytes 2.59 Mbits/sec
[ 3] 2.0- 3.0 sec 314 KBytes 2.57 Mbits/sec
(omitted)

查看Pod里流入的日志:
iperf -s -p 12345 -i 1
------------------------------------------------------------
Server listening on TCP port 12345
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
[ 4] local 10.130.2.103 port 12345 connected with 10.130.2.1 port 58162
[ ID] Interval Transfer Bandwidth
[ 4] 0.0- 1.0 sec 354 KBytes 2.90 Mbits/sec
[ 4] 1.0- 2.0 sec 351 KBytes 2.87 Mbits/sec
[ 4] 2.0- 3.0 sec 349 KBytes 2.86 Mbits/sec
(omitted)

流出测试:

在任意节点上启动iperf server作为测试:
iperf -s -p 12345 -i 1
------------------------------------------------------------
Server listening on TCP port 12345
TCP window size: 85.3 KByte (default)
------------------------------------------------------------

Pod中用iperf client进行测试:
iperf -c 172.18.143.117 -p 12345 -i 1 -t 10 -w 5m
------------------------------------------------------------
Client connecting to 172.18.143.117, TCP port 12345
TCP window size: 416 KByte (WARNING: requested 5.00 MByte)
------------------------------------------------------------
[ 3] local 10.130.2.103 port 44602 connected with 172.18.143.117 port 12345
[ ID] Interval Transfer Bandwidth
[ 3] 0.0- 1.0 sec 1.62 MBytes 13.6 Mbits/sec
[ 3] 1.0- 2.0 sec 384 KBytes 3.15 Mbits/sec
[ 3] 2.0- 3.0 sec 384 KBytes 3.15 Mbits/sec
(omitted)

查看node4上流入的日志:
iperf -s -p 12345 -i 1
------------------------------------------------------------
Server listening on TCP port 12345
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
[ 4] local 172.18.143.117 port 12345 connected with 10.130.2.103 port 44602
[ ID] Interval Transfer Bandwidth
[ 4] 0.0- 1.0 sec 1.28 MBytes 10.7 Mbits/sec
[ 4] 1.0- 2.0 sec 373 KBytes 3.05 Mbits/sec
[ 4] 2.0- 3.0 sec 380 KBytes 3.11 Mbits/sec
[ 4] 3.0- 4.0 sec 339 KBytes 2.77 Mbits/sec
(omitted)

查看tc的配置:
[root@a-node4 ~]# tc -s -d class show dev vethddb66bac
class htb 1:1 parent 1:fffe prio 0 quantum 1450 rate 11600bit ceil 3000Kbit burst 1513b/1 mpu 0b overhead 0b cburst 1513b/1 mpu 0b overhead 0b level 0
Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0
lended: 0 borrowed: 0 giants: 0
tokens: 16314655 ctokens: 63083

class htb 1:fffe root rate 3000Kbit ceil 3000Kbit burst 1449b/1 mpu 0b overhead 0b cburst 1449b/1 mpu 0b overhead 0b level 7
Sent 4187548 bytes 2872 pkt (dropped 0, overlimits 0 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0
lended: 998 borrowed: 0 giants: 0
tokens: 60416 ctokens: 6041

#实现AdmissionWebhook组件:bandwidth-inject-webhook
在公有云平台中,我们可以根据租户等级,为其创建的Pod设置不同级别的限流限制。我们通过自研开发实现了AdmissionWebhook组件:bandwidth-inject-webhook。当创建Pod的配置文件yaml提交给apiserver时,可以为其增加网络限流配置。
image2.png

上面是我们基于Open vSwitch的CNI做的一些研究和开发工作。当然,我们也可以借鉴华为自研的CNI插件,去支持任何网络插件的情景。
image4.png


参考文章:Open vSwitch之QoS的实现:https://www.sdnlab.com/19208.html
#Q&A
Q:网络插件为什么没用Flannel?
A:如果选择flannel cni网络插件,可以采用华为开发的限流CNI插件。

Q:目前Istio也具有限速功能,这与tc限速共存吗?
A:SDN控制器,红帽开源的OpenShift有相应的实现。OVS选择是vxlan方式解决节点间通信。Istio的限流方式暂时我还没有了解。

以上内容根据2019年1月8日晚微信群分享内容整理。分享人范彬,现电信云容器项目研发组长。对技术保有一颗热衷的心。自2016年起开始一直从事容器、微服务等方面的研究和开发工作。熟悉Golang技术栈、Kubernetes分布式系统架构和工作原理。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesd,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

k8s calico 网络问题

回复

在别处 发起了问题 • 1 人关注 • 0 个回复 • 1289 次浏览 • 2018-08-15 15:46 • 来自相关话题

FAQ宝典之常见问题排查与修复方法

Rancher 发表了文章 • 1 个评论 • 1363 次浏览 • 2017-12-29 12:33 • 来自相关话题

一、服务/容器 #1、为什么我只能编辑容器的名称? Docker容器在创建之后就不可更改了。唯一可更改的内容是我们要存储的不属于Docker容器本身的那一部分数据。无论是停止、启动或是重新启动,它始终在使用相 ...查看全部
一、服务/容器

#1、为什么我只能编辑容器的名称?

Docker容器在创建之后就不可更改了。唯一可更改的内容是我们要存储的不属于Docker容器本身的那一部分数据。无论是停止、启动或是重新启动,它始终在使用相同的容器。如需改变任何内容都需要删除或重新创建一个容器。

你可以克隆,即选择已存在的容器,并基于已有容器的配置提前在添加服务界面中填入所有要设置的内容,如果你忘记填入某项内容,可以通过克隆来改变它之后删除旧的容器。

#2、service-link的容器/服务在Rancher中是如何工作的?

在Docker中,关联容器(在docker run中使用--link)的ID和IP地址会出现在容器的/etc/hosts中。在Rancher中,我们不需要更改容器的/etc/hosts文件,而是通过运行一个内部DNS服务器来关联容器,DNS服务器会返回给我们正确的IP。

#3、不能通过Rancher的界面打开命令行或查看日志,如何去访问容器的命令行和日志?

Agent主机有可能会暴露在公网上,Agent上接受到的访问容器命令行或者日志的请求是不可信的。Rancher Server中发出的请求包括一个JWT(JSON Web Token),JWT是由服务器签名并且可由Agent校验的,Agent可以判断出请求是否来自服务器,JWT中包括了有效期限,有效期为5分钟。这个有效期可以防止它被长时间使用。如果JWT被拦截而且没有用SSL时,这一点尤为重要。

如果你运行docker logs -f (rancher-agent名称或ID)。日志会显示令牌过期的信息,随后检查Rancher Server主机和Rancher Agent主机的时钟是否同步。

#4、在哪里可以看到我的服务日志?

在服务的详细页中,我们提供了一个服务日志的页签日志。在日志页签中,列出了和服务相关的所有事件,包括时间戳和事件相关描述,这些日志将会保留24小时。

#5、RANCHER SERVER 点击WEB shell屏幕白屏

如果RANCHER SERVER 运行在V1.6.2版本,点击WEB shell出现白屏,这是UI上的一个BUG,请选择升级server服务。

#二、跨主机通信

如果容器运行在不同主机上,不能够ping通彼此,可能是由一些常见的问题引起的。

#1、如何检查跨主机通信是否正常?

在应用->基础设施中,检查 healthcheck 应用的状态。如果是active跨主机通信就是正常的。

手动测试,你可以进入任何一个容器中,去ping另一个容器的内部IP。在主机页面中可能会隐藏掉基础设施的容器,如需查看点击“显示系统容器”的复选框。

#2、UI中显示的主机IP是否正确?

有时,Docker网桥的IP地址会被错误的作为了主机IP,而并没有正确的选择真实的主机IP。这个错误的IP通常是172.17.42.1或以172.17.x.x开头的IP。如果是这种情况,在使用docker run命令添加主机时,请用真实主机的IP地址来配置CATTLE_AGENT_IP环境变量。


sudo docker run -d -e CATTLE_AGENT_IP= --privileged \
-v /var/run/docker.sock:/var/run/docker.sock \
rancher/agent:v0.8.2 http://SERVER_IP:8080/v1/scripts/xxxx


#3、Rancher的默认子网(10.42.0.0/16)在我的网络环境中已经被使用或禁止使用,我应该怎么去更改这个子网?

Rancher Overlay网络默认使用的子网是10.42.0.0/16。如果这个子网已经被使用,你将需要更改Rancher网络中使用的默认子网。你要确保基础设施服务里的Network组件中使用着合适的子网。这个子网定义在该服务的rancher-compose.yml文件中的default_network里。

要更改Rancher的IPsec或VXLAN网络驱动,你将需要在环境模版中修改网络基础设施服务的配置。创建新环境模板或编辑现有环境模板时,可以通过单击编辑来配置网络基础结构服务的配置。在编辑页面中,选择配置选项>子网输入不同子网,点击配置。在任何新环境中将使用环境模板更新后的子网,编辑已经有的环境模板不会更改现在已有环境的子网。

这个实例是通过升级网络驱动的rancher-compose.yml文件去改变子网为10.32.0.0/16。


ipsec:
network_driver:
name: Rancher IPsec
default_network:
name: ipsec
host_ports: true
subnets:
# After the configuration option is updated, the default subnet address is updated
- network_address: 10.32.0.0/16
dns:
- 169.254.169.250
dns_search:
- rancher.internal
cni_config:
'10-rancher.conf':
name: rancher-cni-network
type: rancher-bridge
bridge: docker0
# After the configuration option is updated, the default subnet address is updated
bridgeSubnet: 10.32.0.0/16
logToFile: /var/log/rancher-cni.log
isDebugLevel: false
isDefaultGateway: true
hostNat: true
hairpinMode: true
mtu: 1500
linkMTUOverhead: 98
ipam:
type: rancher-cni-ipam
logToFile: /var/log/rancher-cni.log
isDebugLevel: false
routes:
- dst: 169.254.169.250/32


注意:随着Rancher通过升级基础服务来更新子网,以前通过API更新子网的方法将不再适用。



#4、VXLAN 网络模式下,跨主机容器无法通信

Vxlan 通过4789端口实现通信,检查防火墙有没有开放此端口;

执行iptables -t filter -L -n参看IPtable表,查看chain FORWARD 是不是被丢弃,如果是,执行sudo iptables -P FORWARD ACCEPT

三、DNS

#1、如何查看我的DNS是否配置正确?

如果你想查看Rancher DNS配置,点击应用 > 基础服务。点击network-services应用,选择metadata,在metadata中,找到名为network-services-metadata-dns-X的容器,通过UI点击执行命令行后,可以进入该容器的命令行,然后执行如下命令。


cat /etc/rancher-dns/answers.json


#2、在Ubuntu上运行容器时彼此间不能正常通信。

如果你的系统开启了UFW,请关闭UFW或更改/etc/default/ufw中的策略为:


DEFAULT_FORWARD_POLICY="ACCEPT"


四、负载均衡

#1、为什么我的负载均衡一直是Initializing状态?

负载均衡器自动对其启用健康检查。如果负载均衡器处于初始化状态,则很可能主机之间无法进行跨主机通信。

#2、我如何查看负载均衡的配置?

如果要查看负载均衡器的配置,你需要用进入负载均衡器容器内部查找配置文件,你可以在页面选择负载均衡容器的执行命令行


cat /etc/haproxy/haproxy.cfg


该文件将提供负载均衡器的所有配置详细信息。

#3、我在哪能找到HAproxy的日志?

HAProxy的日志可以在负载均衡器容器内找到。负载均衡器容器的docker logs只提供与负载均衡器相关的服务的详细信息,但不提供实际的HAProxy日志记录。


cat /var/log/haproxy


#4、如何自定义负载均衡的配置



如图,在自定义配置中,按照global、defaults、frontend、backend的格式配置。

五、健康检查

#1、为什么健康检查服务一直显示黄色初始化状态?

healthcheck不仅为其他服务提供健康检查,对系统组件(比如调度服务)也提供健康检查服务,healthcheck也对自己进行健康检查。多个healthcheck组件时,它们会相互交叉检查,只有健康检查通过后,容器状态才会变成绿色。而healthcheck一直显示黄色初始化状态,说明一直没有通过健康检查。健康检查都是通过网络访问的,所以一定是网络通信异常导致。

六、调度

为什么节点关机后,应用没有自动调度到其他节点上?Rancher上应用的调度,需要配合健康检查功能。当健康检查检查到应用不健康才会重新调度,如果没有配置健康检查,即使关机,cattle也不会对应用做调度处理。

七、CentOS

#1、为什么容器无法连接到网络?

如果你在主机上运行一个容器(如:docker run -it ubuntu)该容器不能与互联网或其他主机通信,那可能是遇到了网络问题。Centos默认设置/proc/sys/net/ipv4/ip_forward为0,这从底层阻断了Docker所有网络。

解决办法:


vi /usr/lib/sysctl.d/00-system.conf


添加如下代码:


net.ipv4.ip_forward=1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-arptables = 1


重启network服务


systemctl restart network


查看是否修改成功


sysctl net.ipv4.ip_forward


如果返回为net.ipv4.ip_forward = 1则表示成功了

八、京东云

#1、京东云运行rancher server出现以下问题



解决办法:sudo sysctl -w net.ipv4.tcp_mtu_probing=1

推荐阅读:《FAQ宝典之Rancher Server》《FAQ宝典之Rancher Server、K8s、Docker》

原文链接:Rancher Labs

FAQ宝典之Rancher Server、K8s、Docker

Rancher 发表了文章 • 1 个评论 • 1588 次浏览 • 2017-12-13 10:29 • 来自相关话题

Rancher FAQ宝典系列第二弹,Rancher Agent、Kubernetes、Docker相关的常见问题,本文一网打尽。 Rancher Agent常见问题 #1、Rancher Agent无法启动 ...查看全部
Rancher FAQ宝典系列第二弹,Rancher Agent、Kubernetes、Docker相关的常见问题,本文一网打尽。

Rancher Agent常见问题

#1、Rancher Agent无法启动的原因是什么?

1.1、添加 --NAME RANCHER-AGENT(老版本)

如果你从UI中编辑docker run .... rancher/agent...命令并添加--name rancher-agent选项,那么Rancher Agent将启动失败。Rancher Agent在初始运行时会启动3个不同容器,一个是运行状态的,另外两个是停止状态的。Rancher Agent要成功连接到Rancher Server必须要有两个名字分别为rancher-agent和rancher-agent-state的容器,第三个容器是docker自动分配的名称,这个容器会被移除。

1.2、使用一个克隆的虚拟机

如果你使用了克隆其他Agent主机的虚拟机并尝试注册它,它将不能工作。在rancher-agent容器的日志中会产生ERROR: Please re-register this agent.字样的日志。Rancher主机的唯一ID保存在/var/lib/rancher/state,因为新添加和虚拟机和被克隆的主机有相同的唯一ID,所以导致无法注册成功。

解决方法是在克隆的VM上运行以下命令:


rm -rf /var/lib/rancher/state; docker rm -fv rancher-agent; docker rm -fv rancher-agent-state


完成后可重新注册。

#2、我在哪里可以找到Rancher agent容器的详细日志?

从v1.6.0起,在rancher-agent容器上运行docker logs将提供agent相关的所有日志。

#3、主机是如何自动探测IP的?我该怎么去修改主机IP?如果主机IP改变了(因为重启),我该怎么办?

当Agent连接Rancher Server时,它会自动检测Agent的IP。有时,自动探测的IP不是你想要使用的IP,或者选择了docker网桥的IP,如. 172.17.x.x。或者,你有一个已经注册的主机,当主机重启后获得了一个新的IP, 这个IP将会和Rancher UI中的主机IP不匹配。你可以重新配置“CATTLE_AGENT_IP”设置,并将主机IP设置为你想要的。当主机IP地址不正确时,容器将无法访问管理网络。要使主机和所有容器进入管理网络,只需编辑添加自定义主机的命令行,将新的IP指定为环境变量“CATTLE_AGENT_IP”。在主机上运行编辑后的命令。不要停止或删除主机上的现有的Rancher Agent容器!


sudo docker run -d -e CATTLE_AGENT_IP= --privileged \
-v /var/run/docker.sock:/var/run/docker.sock \
rancher/agent:v0.8.2 http://SERVER_IP:8080/v1/scripts/xxxx


#4、错误提示如下:INFO: Attempting to connect to: http://192.168.xx.xx:8080/v1 ERROR: http://192.168.xx.xx:8080/v1 is not accessible (Failed to connect to 192.168.xx.xx port 8080: No route to host)

这个问题主要有以下几种情况:

  • RANCHER SERVER服务器防火墙没有开通8080端口;
  • 云平台安全组没有放行8080端口;
  • Agent 服务器没有开启IP转发规则 [为什么我的容器无法连接到网络?]:{site.baseurl}}/rancher/faqs/ troubleshooting/1为什么我的容器无法连接到网络;
=1为开启,=0为关闭
/etc/sysctl.confnet.ipv4.ip_forward=1net.ipv6.conf.all.forwarding=1
  • 主机hosts(/etc/hosts)文件没有配置;

#5、rancher下创建的服务容器,docker inspect 查看到Entrypoint和CMD后面有/.r/r字符,这个起什么作用?

./r 是基于weave wait编译出来的。CNI网络下会添加/.r/r 这个参数,目的是:当容器启动时,其实网络设备还没设置好,这时候需要container 等待,不能启动真实业务,否则会失败。

#6、添加hosts后 server上没有列出,agent报Host not registered yet. Sleeping 1 second and trying again.” Attempt=0 reportedUuid=752031dd-8c7e-4666-5f93-020d7f4da5d3

检查主机名和hosts配置, hosts中需要配置:

127.0.0.1 localhost
hostip hostname

Kubernetes常见问题

#1、部署Kubernetes时候出现以下有关cgroup的问题


Failed to get system container stats for "/system.slice/kubelet.service":
failed to get cgroup stats for "/system.slice/kubelet.service": failed to
get container info for "/system.slice/kubelet.service": unknown container
"/system.slice/kubelet.service"



Expected state running but got error: Error response from daemon:
oci runtime error: container_linux.go:247: starting container
process caused "process_linux.go:258: applying cgroup configuration
for process caused \"mountpoint for devices not found\""


以上问题为Kubernetes版本与docker版本不兼容导致cgroup功能失效

#2、Kubernetes err: [nodes "iZ2ze3tphuqvc7o5nj38t8Z" not found]”

Rancher-Kubernetes中,节点之间通信需要通过hostname,如果没有内部DNS服务器,那么需要为每台节点配置hosts文件。

配置示例:假如某个节点主机名为node1,ip 地址为192.168.1.100


cat /etc/hosts< 127.0.0.1 localhost
192.168.1.100 node1
EOF


#3、如何验证你的主机注册地址设置是否正确?

如果你正面临Rancher Agent和Rancher Server的连接问题,请检查主机设置。当你第一次尝试在UI中添加主机时,你需要设置主机注册的URL,该URL用于建立从主机到Rancher Server的连接。这个URL必须可以从你的主机访问到。为了验证它,你需要登录到主机并执行curl命令:


curl -i /v1


你应该得到一个json响应。如果开启了认证,响应代码应为401。如果认证未打开,则响应代码应为200。

注意:普通的HTTP请求和websocket连接(ws://)都将被使用。如果此URL指向代理或负载平衡器,请确保它们可以支持Websocket连接。

#4、Kuberbetes UI显示Service unavailable

很多同学正常部署Kuberbetes环境后无法进入Dashboard,基础设施应用栈均无报错。但通过查看 基础架构|容器 发现并没有Dashboard相关的容器.因为Kuberbetes在拉起相关服务(如Dashboard、内置DNS等服务)是通过应用商店里面的YML文件来定义的,YML文件中定义了相关的镜像名和版本。

而Rancher部署的Kuberbetes应用栈属于Kuberbetes的基础框架,相关的镜像通过dockerhub/rancher 仓库拉取。默认Rancher-catalog Kuberbetes YML中服务镜像都是从谷歌仓库拉取,在没有科学上网的情况下,国内环境几乎无法成功拉取镜像。

为了解决这一问题,优化中国区用户的使用体验,在RANCHER v1.6.11之前的版本,我们修改了http://git.oschina.net/rancher/rancher-catalog仓库中的YML文件,将相关的镜像也同步到国内仓库,通过替换默认商店地址来实现加速部署;在RANCHER v1.6.11及之后的版本,不用替换商店catalog地址,直接通过在模板中定义仓库地址和命名空间就行实现加速;在后期的版本种,Kuberbetes需要的镜像都会同步到docker hub中。

安装方法见:《原生加速中国区Kubernetes安装》《Rancher-k8s加速安装文档》

Docker常见问题

#1、镜像下载慢,如何提高下载速度?


touch /etc/docker/daemon.json
cat >> /etc/docker/daemon.json < {
"insecure-registries": ["0.0.0.0/0"],
"registry-mirrors": ["https://7bezldxe.mirror.aliyuncs.com"]
}
EOF
systemctl daemon-reload && systemctl restart docker



PS:0.0.0.0/0 表示信任所有非https地址的镜像仓库,对于内网测试,这样配置很方便。对于线上生产环境,为了安全请不要这样配置


#2、如何配置Docker后端存储驱动?

以overlay为例


touch /etc/docker/daemon.json
cat >> /etc/docker/daemon.json < {
"storage-driver": "overlay"
}
EOF
systemctl daemon-reload && systemctl restart docker


#3、docker info 出现 WARNING


WARNING: No swap limit support
WARNING: No kernel memory limit support
WARNING: No oom kill disable support


编辑/etc/default/grub文件,并设置:`GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"`

接着

SUSE


grub2-mkconfig -o /boot/grub2/grub.cfg


Cetos


Update grub


Ubuntu


update-grub


#4、我怎么通过rancher让docker里的程序代理上网呢?

启动容器的时候,加一下


-e http_proxy= -e https_proxy=




#5、Docker错误:无法删除文件系统

一些基于容器的实用程序(例如Google cAdvisor)会将Docker系统目录(如/ var / lib / docker /)挂载到容器中。例如,cadvisor的文档指示您运行cadvisor容器,如下所示:


$ sudo docker run \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:rw \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--publish=8080:8080 \
--detach=true \
--name=cadvisor \
google/cadvisor:latest


当挂载/var/lib/docker/时,这会有效地将所有其他正在运行的容器的所有资源作为文件系统安装在挂载/var/lib/docker/的容器中。当您尝试删除这些容器中的任何一个时,删除尝试可能会失败,出现如下所示的错误:


Error: Unable to remove filesystem for
74bef250361c7817bee19349c93139621b272bc8f654ae112dd4eb9652af9515:
remove /var/lib/docker/containers/74bef250361c7817bee19349c93139621b272bc8f654ae112dd4eb9652af9515/shm:
Device or resource busy


如果将/var/lib/docker/在/var/lib/docker/中的文件系统句柄上使用statfsor或fstatfs并且不关闭它们的容器,就会发生此问题。

通常,我们会以这种方式建议禁止挂载/var/lib/docker。然而,cAdvisor的核心功能需要这个绑定挂载。

如果您不确定是哪个进程导致错误中提到的路径繁忙并阻止它被删除,则可以使用lsof命令查找其进程。例如,对于上面的错误:


sudo lsof /var/lib/docker/containers/74bef250361c7817bee19349c93139621b272bc8f65


原文来源:Rancher Labs

阿里云经典网络与Rancher VXLAN兼容性问题

Rancher 发表了文章 • 1 个评论 • 1996 次浏览 • 2017-09-12 12:34 • 来自相关话题

近期国内很多用户曝出在阿里云的环境中无法使用Rancher的VXLAN网络,现象是跨主机的容器无法正常通信,healthcheck服务一直无法更新正常状态。经过一系列走访排查,最终定位此现象只发生在阿里云的经典网络环境下。如果你也遭遇了同样的情况,请关注此文。 ...查看全部
近期国内很多用户曝出在阿里云的环境中无法使用Rancher的VXLAN网络,现象是跨主机的容器无法正常通信,healthcheck服务一直无法更新正常状态。经过一系列走访排查,最终定位此现象只发生在阿里云的经典网络环境下。如果你也遭遇了同样的情况,请关注此文。

阿里云经典网络部署最新的stable(v1.6.7)版本并启用VXLAN网络,使用经典网络的内网IP加入两台主机,现象如下:



Rancher的VXLAN网络除了VXLAN本身的机制外,还需要在IPtables中的RAW表中进行数据包标记,然后在Filter表中对标记数据包设置ACCEPT规则,进而实现容器跨主机通信。但是在阿里云经典网络环境中,无论如何配置安全组功能,RAW表中始终无法匹配进入主机栈的数据包。



依据“大胆假设,小心求证”的troubleshooting原则,首先我们验证了使用经典网络的公网IP注册主机,VXLAN并没有问题,这说明存在某种安全规则是作用在经典网络的内网IP的。



其次,我们知道Rancher VXLAN的实现是基于Linux kernel的VXLAN module,IPtables的数据包处理也基本是kernel处理,所以理论上讲肯定系统中存在权限更高的组件截获了VXLAN的数据,因为我们测试了在其他公有云环境并无此问题,考虑阿里云会对经典网络的内网安全做诸多限制,所以怀疑阿里云镜像内做了一些特殊的定制。

以过往使用阿里云的经验,我们对系统中内置的“安全加固”组件疑惑很大,尝试删除这个组件,可以使用这个脚本 http://update.aegis.aliyun.com/download/uninstall.sh ,但重启机器后发现VXLAN网络依然不通。无法确定是否存在删除不彻底的情况,所以重建环境并在创建VM时选择去掉“安全加固”选项。



重新添加主机,发现VXLAN一切恢复正常。



我们也正在尽力与阿里云官方取得联系,确认这种情况是否存在误杀。当前可选择的临时方案除了按照上面的说明删除“安全加固”组件外,还可以在创建VM的时候选择不使用安全加固镜像,这样Rancher VXLAN就可以正常工作。

在这里,非常感谢社区用户的热情发问,没有大家对技术专注的态度和刨根问底的精神,Rancher也无法真正发现问题的根源,Rancher会一如既往地接受用户的问题与需求,改进自身产品,真真正正能够提供一个有生产力的工具。

原文来源:Rancher Labs

9月27日,北京海航万豪酒店,容器技术大会Container Day 2017即将举行。

CloudStack之父、海航科技技术总监、华为PaaS部门部长、恒丰银行科技部总经理、阿里云PaaS工程总监、民生保险CIO······均已加入豪华讲师套餐!

11家已容器落地企业,15位真·云计算大咖,13场纯·技术演讲,结合实战场景,聚焦落地经验。免费参会+超高规格,详细议程及注册链接请戳

DockOne微信分享(一三八):白话Kubernetes网络

FanLin 发表了文章 • 0 个评论 • 5231 次浏览 • 2017-08-22 00:47 • 来自相关话题

【编者的话】容器的网络是在CaaS集群中无法避免的话题,作为当下最主流的一种容器集群解决方案,Kubernetes对网络进行了合理的抽象,并采用了开放的CNI模型。面对各种容器网络实现,他们有什么不同,应该如何选择?本文将带大家回顾Kubernetes各种主流 ...查看全部
【编者的话】容器的网络是在CaaS集群中无法避免的话题,作为当下最主流的一种容器集群解决方案,Kubernetes对网络进行了合理的抽象,并采用了开放的CNI模型。面对各种容器网络实现,他们有什么不同,应该如何选择?本文将带大家回顾Kubernetes各种主流网络方案的发展历程,并透过现象清本质,用形象的例子展示Weave、Flannel、Calico和Romana等网络解决方案背后的原理。

【3 天烧脑式基于Docker的CI/CD实战训练营 | 北京站】本次培训围绕基于Docker的CI/CD实战展开,具体内容包括:持续集成与持续交付(CI/CD)概览;持续集成系统介绍;客户端与服务端的 CI/CD 实践;开发流程中引入 CI、CD;Gitlab 和 CI、CD 工具;Gitlab CI、Drone 的使用以及实践经验分享等。

白话Kubernetes网络.001_.jpeg

这次讲一讲容器集群中的网络。其实不同的容器集群解决方案,在网络方面的核心原理都是相似的,只不过这次我们将以Kubernetes为线索,来窥斑见豹的一睹容器网络的发展过程。
白话Kubernetes网络.002_.jpeg

我是来自ThoughtWorks的林帆,我们从Docker的0.x版本开始就在对容器的应用场景进行探索,积累了一线的容器运用经验。这次分享会用简洁易懂的方式告诉大家我们对容器网络方面的一些知识归纳。
白话Kubernetes网络.003_.jpeg

初入容器集群的人往往会发现,和单节点的容器运用相比,容器的网络和存储是两个让人望而却步的领域。在这些领域里,存在大量的技术名词和术语,就像是一道道拒人于门外的高门槛。
白话Kubernetes网络.004_.jpeg

为了便于理解,我们将这些名称简单的分个类别,从简单到复杂,依次递增。今天的话题会涉及的深度大致在这个大池子的中间,希望大家看完以后会对目标线以上的内容不再陌生,目标线以下的内容我们也会依据需要适当的提及。
白话Kubernetes网络.005_.jpeg

此外,这个话题会按照Kubernetes的网络发现过程作为时间主线,其中重点介绍CNI标准和它的主流实现。
白话Kubernetes网络.006_.jpeg

在早期的Kubernetes中,对网络是没有什么标准的。文档中对网络的描述只有很简单的几句话,其实就是让用户在部署Kubernetes之前,预先准备好容器互联的网络解决方案。Kubernetes只对网络提出设计假设,这三条假设总结起来就是:所有容器都可以和集群里任意其他容器或者主机通信,并且通信双方看到的对方IP地址就是实际的地址(即不经过网络地址转换)。

基于这样的底层网络,Kubernetes设计了Pod - Deployment - Service的经典三层服务访问机制。

既然Kubernetes不提供底层网络实现,在业界就出现了很多企业级的以及开源的第三方解决方案,其中下面这页图中展示了这个时期的主流开源方案。
白话Kubernetes网络.007_.jpeg

我们将这些方案依据配置的复杂度,分为“全自动”和“半自动”两类,就像是汽车中的自动挡和手动挡的差别。

“全自动”的解决方案使用起来简单,适用于标准网络环境的容器跨节点通信。

“半自动”的解决方案实际上是对底层协议和内核模块功能的封装,提供了选择十分丰富的网络连接方法,但对使用者的网络原理知识有一定要求。
白话Kubernetes网络.008_.jpeg

在Kubernetes的1.1版本中,发生了一件很重要的变化,那就是Kubernetes全面采纳CNI网络标准。

CNI诞生于2015年4月,Kubernetes的1.1版本诞生于2015年9月,之间仅隔5个月。在这个时期,Docker也设计了一套网络标准,称为CNM(即Libnetwork)。Kubernetes采用CNI而非CNM,这背后有很长的一段故事,核心的原因就是CNI对开发者的约束更少,更开放,不依赖于Docker工具,而CNM对Docker有非常强的依赖,无法作为通用的容器网络标准。在Kubernetes的官方博客里有一篇博文详细讨论了个中细节,InfoQ上有一篇该博客的翻译,有兴趣的读者不妨一读。
白话Kubernetes网络.009_.jpeg

几乎在Kubernetes宣布采纳CNI以后的1个月,之前提到的“全自动”网络方案就悉数实现了CNI的插件,这也间接说明了CNI的简单。

那么CNI到底有多简单呢?举几个数字。

实现一个CNI插件需要的内容包括一个Json配置文件和一个可执行的文件(脚本或程序),配置文件描述插件的版本、名称、描述等基本信息,可执行文件就是CNI插件本身会在容器需要建立网络和需要销毁容器的时候被调用。

当一个CNI插件被调用时,它能够通过6个环境变量以及1个命令行参数(Json格式文本)来获得需要执行的操作、目标网络Namespace、容器的网卡必要信息,每个CNI插件只需实现两种基本操作:创建网络的ADD操作,和删除网络的DEL操作(以及一个可选的VERSION查看版本操作)。

最新的CNI规范可以通过上图中的链接访问,只有一页网页的内容而已。同时Kuberntes社区也提供了一个利用“docker network”命令实现的简单CNI插件例子,只用了几十行Bash脚本。
白话Kubernetes网络.010_.jpeg

那么面对这么多的社区CNI插件,我们怎样选择呢?

直观的说,既然是网络插件,在功能差不多的情况下,我们当然先关心哪个的速度快。

为此我此前专门做过一次对比测试,不过由于使用了公有云的网络环境(云上环境的不同主机之间相对位置不固定),在汇总数据的时候才发现测试结果偏离理论情况过于明显。

这个数据大家且当娱乐,不过对于同一种插件的不同工作模式(比如Flannel的三种模型)之间,由于是使用的相同的虚拟机测试,还是具有一定可参考性。

先抛开测试结果,从理论上说,这些CNI工具的网络速度应该可以分为3个速度等级。

最快的是Romana、Gateway模式的Flannel、BGP模式的Calico。

次一级的是IPIP模式的Calico、Swarm的Overlay网络、VxLan模式的Flannel、Fastpath模式的Weave。

最慢的是UDP模式的Flannel、Sleeve模式的Weave。
白话Kubernetes网络.012_.jpeg

这里我也提供出测试容器网络速度的具体方法,以便大家重复这个测试。
白话Kubernetes网络.013_.jpeg

要解释这些网络插件和模式速度不同的原因,我们需要先回到这些工具最初要解决的问题上来。那就是跨节点的网络不通。

如果仔细观察,会发现在3种网络速度模式中都有Flannel的身影。因此我们不妨先以Flannel为例来看这些网络工具(和相应的CNI插件)是如何解决网络不通问题的。
白话Kubernetes网络.014_.jpeg

跨节点网络不同有几个方面的原因,首先是容器的地址重复。

由于Docker等容器工具只是利用内核的网络Namespace实现了网络隔离,各个节点上的容器是在所属节点上自动分配IP地址的,从全局来看,这种局部地址就像是不同小区里的门牌号,一旦拿到一个更大的范围上看,就可能是会重复的。
白话Kubernetes网络.015_.jpeg

为了解决这个问题,Flannel设计了一种全局的网络地址分配机制,即使用Etcd来存储网段和节点之间的关系,然后Flannel配置各个节点上的Docker(或其他容器工具),只在分配到当前节点的网段里选择容器IP地址。

这样就确保了IP地址分配的全局唯一性。
白话Kubernetes网络.016_.jpeg

是不是地址不重复网络就可以联通了呢?

这里还有一个问题,是对于不同的主机、以及网络上的路由设备之间,并不知道这些IP容器网段的地址是如何分配的,因此数据包即使被发送到了网络中,也会因为无法进行路由而被丢掉。

虽然地址唯一了,依然无法实现真正的网络通信。
白话Kubernetes网络.017_.jpeg

为此,Flannel采用了几种处理方法(也就是Flannel的几种网络模式)。

早期时候用的比较多的一种方式是Overlay网络。

在这种方式下,所有被发送到网络中的数据包会被添加上额外的包头封装。这些包头里通常包含了主机本身的IP地址,因为只有主机的IP地址是原本就可以在网络里路由传播的。

根据不同的封包方式,Flannel提供了UDP和Vxlan两种传输方法。

UDP封包使用了Flannel自定义的一种包头协议,数据是在Linux的用户态进行封包和解包的,因此当数据进入主机后,需要经历两次内核态到用户态的转换。

VxLAN封包采用的是内置在Linux内核里的标准协议,因此虽然它的封包结构比UDP模式复杂,但由于所有数据装、解包过程均在内核中完成,实际的传输速度要比UDP模式快许多。

但比较不幸的是,在Flannel开始流行的时候,大概2014年,主流的Linux系统还是Ubuntu 14.04或者CentOS 6.x,这些发行版的内核比较低,没有包含VxLAN的内核模块。因此多数人在开始接触Flannel时候,都只能使用它的UDP模式,因此Flanned一不小心落得了一个“速度慢”的名声,特别是在之后的Calico出来以后(其实Flannel的Gateway模式与Calico速度相当,甚至理论上还要快一点点,稍后解释)。

这是第一种解决网络无法路由的方法。
白话Kubernetes网络.018_.jpeg

第二种思路是,既然在无法进行路由是因为网络中的节点之间没有路由信息,但Flannel是知道这个信息的,能不能把这个信息告诉网络上的节点呢?

这就是Flannel的Host-Gateway模式,在这种模式下,Flannel通过在各个节点上的Agent进程,将容器网络的路由信息刷到主机的路由表上,这样一来所有的主机就都有整个容器网络的路由数据了。

Host-Gateway的方式没有引入像Overlay中的额外装包解包操作,完全是普通的网络路由机制,它的效率与虚拟机直接的通信相差无几。

然而,由于Flannel只能够修改各个主机的路由表,一旦主机直接隔了个其他路由设备,比如三层路由器,这个包就会在路由设备上被丢掉。

这样一来,Host-Gateway的模式就只能用于二层直接可达的网络,由于广播风暴的问题,这种网络通常是比较小规模的,但近年来也出现了一些专门的设备能够构建出大规模的二层网络(就是我们经常听到的“大二层”网络)。

那么其他的CNI插件呢?

由于Flannel几乎是最早的跨网络通信解决方案,其他的方案都可以被看做是Fannel的某种改进版。
白话Kubernetes网络.019_.jpeg

比如Weave的工作模式与Flannel是很相似的,它最早只提供了UDP(称为sleeve模式)的网络方式,后来又加上了fastpass方式(基于VxLAN),不过Weave消除了Flannel中用来存储网络地址的额外组件,自己集成了高可用的数据存储功能。
白话Kubernetes网络.020_.jpeg

Calico的设计比较新颖,之前提到Flannel的Host-Gateway模式之所以不能跨二层网络,是因为它只能修改主机的路由,Calico把改路由表的做法换成了标准的BGP路由协议。

相当于在每个节点上模拟出一个额外的路由器,由于采用的是标准协议,Calico模拟路由器的路由表信息就可以被传播到网络的其他路由设备中,这样就实现了在三层网络上的高速跨节点网络。

不过在现实中的网络并不总是支持BGP路由的,因此Calico也设计了一种IPIP模式,使用Overlay的方式来传输数据。IPIP的包头非常小,而且也是内置在内核中的,因此它的速度理论上比VxLAN快一点点,但安全性更差。
白话Kubernetes网络.021_.jpeg

Cannal将Calico和Flannel做了一下组合,同时支持两者的特性。
白话Kubernetes网络.022_.jpeg

Romana只支持与Flannel相同的Host-Gateway模式,但它在网络策略方面做了比较多的增强,通过额外引入的租户概念简化了网络策略所需的IPtables规则数量。
白话Kubernetes网络.023_.jpeg

这是几种主流CNI工具的横向对比。
白话Kubernetes网络.024_.jpeg

在Kubernetes的1.2版本以后开始引入了一个新的工具,叫做 kubernet,它实现了内置的网络地址分配功能。结合一些云平台上的内网路由表功能,就能够直接执行跨网络通信,相当于把跨网络功能内建到Kubernetes里面了。

这是一个从“只做假设”到“设定标准”到“内置实现”的很大的改变。
白话Kubernetes网络.025_.jpeg

在Kubernetes的1.3版本以后,开始加入网络策略相关的支持。并且在1.7版本后结束了Beta阶段,成为正式API的一部分。

值得一说的是,Kubernetes的网络策略采用了比较严格的单向流控制,即假如允许服务A访问服务B,反过来服务B并不一定能访问服务A。这与Docker内置的Network命令实现的隔离有很大不同。
白话Kubernetes网络.026_.jpeg

纵向的对比一下主流的容器集群对今天提到的这些网络特性的支持情况和时间点。
# Q&A
Q:Kubernetes的网络策略采用了比较严格的单向流控制,即假如允许服务A访问服务B,反过来服务B并不一定能访问服务A。为什么要设计成严格单向流呢?

A:主要是安全性的原因,这是一种更精细的权限控制策略,除了方向,Kuberetes还允许对可访问的端口进行控制。



Q:Open vSwitch有测过么?

A:没有测试,Open vSwitch同样可以配置成Overlay网络或者Macvlan网络等不同的通信模式,速度也会落到相应的档位上。那个测试例子只是为了说明网络速度与采用的通信原理有关,同时引出几种主流的通信模式原理,测试数据是不准确的,建议以在自己的实际环境中测试结果为准。



Q:Calico怎么做网段间的隔离?

A:各种网络工具的网络策略基本上都是基于内核的Iptables模块实现的。比如Calico只是根据用户配置,自动管理各个节点上的Iptables规则。其他有些改进的,比如Romana设计了一种基于“租户”的规则管理机制,可以用更少的Iptables规则实现网络隔离。



Q:如果在Kubernetes里面需要做到平行网络,让每一个Pod获取一个业务IP,除了Bridge+Vlan的方式,还有更好的建议么?

A:这次讲的这些CNI插件都会让每一个Pod获得一个独立业务IP。可以根据实际网络情况和对速度的需求选择。



Q:Calico BGP IPIP NAT三种模式分别怎么配置?原理是怎样的?其中IPIP还有两种模式,区别在哪?

A:在Calico的配置中设置`spec.ipip.enabled: ture`就会开启IPIP模式,否则默认是纯BGP模式。IPIP的两种模式其实是指纯IPIP(ipip always模式)或者混合IPIP和BGP(ipip cross-subnet),后者指的是“同子网内路由采用BGP,跨子网路由采用IPIP”,主要用于即想在内网获得高速,又想在跨公网时能保持联通的情况。这种模式需要每个节点启动时用`--ip`参数预先配置节点的子网,并且所有节点版本都在v2.1以上。



Q:能麻烦具体介绍一下kube-proxy这种网络模式的优缺点吗,在测试过程中发现很不稳定,但是又没发现足够的证据。

A:kube-proxy是Kubernetes的一个组件,提供通过Service到Pod的路由,并不是一种网络模式,不同的网络插件都会使用到这个组件。



以上内容根据2017年08月15日晚微信群分享内容整理。分享人林帆,ThoughtWorks DevOps和容器技术咨询师。从事软件开发运维以及社区宣传工作,热衷于对DevOps和容器技术应用的推广,在容器规模化运维方面有较丰富实践经验,著有《CoreOS实践之路》一书。 DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesa,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

容器网络——从CNI到Calico(360搜索)

man4acs 发表了文章 • 0 个评论 • 8344 次浏览 • 2017-08-07 10:51 • 来自相关话题

从容器诞生开始,存储和网络这两个话题就一直为大家津津乐道。我们今天这个环境下讲网络这个问题,其实是因为容器对网络的需求,和传统物理、虚拟环境对网络环境需求是有差别的,主要面临以下两个问题: 过去IaaS层在网络方便做了很多工作,已经形 ...查看全部
从容器诞生开始,存储和网络这两个话题就一直为大家津津乐道。我们今天这个环境下讲网络这个问题,其实是因为容器对网络的需求,和传统物理、虚拟环境对网络环境需求是有差别的,主要面临以下两个问题:

  • 过去IaaS层在网络方便做了很多工作,已经形成了成熟的环境,如果和容器环境适配,两边都需要做很多改造
  • 容器时代提倡微服务,导致容器的粒度之小,离散程度之大,原有IaaS层网络解决方案很难承载如此复杂的需求
我们来看下一些主流的容器网络接入方案:# Host network最简单的网络模型就是让容器共享Host的network namespace,使用宿主机的网络协议栈。这样,不需要额外的配置,容器就可以共享宿主的各种网络资源。# 共享物理网卡这种接入方式主要使用SR-IOV技术,每个容器被分配一个VF,直接通过PCIe网卡与外界通信。SR-IOV 技术是一种基于硬件的虚拟化解决方案,可提高性能和可伸缩性。SR-IOV 标准允许在虚拟机之间高效共享 PCIe设备,并且它是在硬件中实现的,可以获得能够与本机性能媲美的 I/O 性能。启用了 SR-IOV 并且具有适当的硬件和 OS 支持的 PCIe 设备(例如以太网端口)可以显示为多个单独的物理设备,每个都具有自己的 PCIe 配置空间。SR-IOV主要用于虚拟化中,当然也可以用于容器:
1.png
SR-IOV配置(需要网卡支持,线上主流万兆卡Intel 540可以支持128个VF(Virtual Function)):
modprobe ixgbevflspci -Dvmm|grep -B 1 -A 4 Ethernetecho 2 > /sys/bus/pci/devices/0000:82:00.0/sriov_numvfs # check ifconfig -a. You should see a number of new interfaces created, starting with “eth”, e.g. eth4
Intel也给Docker实现了一个SR-IOV network plugin,同样也有相应的CNI(后面会提到)Plugin。SR-IOV的接入方式可以达到物理网卡的性能,但是需要硬件支持,而且VF的数量是有限的。# 共享容器网络多个容器共享同一个netns,只需要第一个容器配置网络。比如Kubernetes Pod就是所有容器共享同一个pause容器的网络。# VSwitch/Bridge容器拥有独立的network namespace,通过veth-pair连接到VSwitch或者Bridge上。容器网络技术日新月异,有些相当复杂,而且提供某种功能的方式也多种多样。这样就给容器runtime与调度系统的实现与各种接入方式的适配带来的很大的困难。为了解决这些问题,Docker与CoreOS相继发布了容器网络标准,便是CNM与CNI,为Linux容器网络提供了统一的接口。先来看下CNM:
2.png
Libnetwork是CNM的原生实现。它为Docker daemon和网络驱动程序之间提供了接口。网络控制器负责将驱动和一个网络进行对接。每个驱动程序负责管理它所拥有的网络以及为该网络提供的各种服务,例如IPAM等等。由多个驱动支撑的多个网络可以同时并存。网络驱动可以按提供方被划分为原生驱动(libnetwork内置的或Docker支持的)或者远程驱动 (第三方插件)。原生驱动包括 none、bridge、overlay 以及 MACvlan。驱动也可以被按照适用范围被划分为本地(单主机)的和全局的 (多主机)。
3.png
  • Sandbox:一个Sandbox对应一个容器的网络栈,能够对该容器的interface、route、dns等参数进行管理。一个Sandbox中可以有多个Endpoint,这些Endpoint可以属于不同的Network。Sandbox的实现可以为linux network namespace、FreeBSD Jail或其他类似的机制。
  • Endpoint: Sandbox通过Endpoint接入Network,一个Endpoint只能属于一个Network。Endpoint的实现可以是veth pair、Open vSwitch internal port或者其他类似的设备。
  • Network:一个Network由一组Endpoint组成,这些Endpoint彼此间可以直接进行通信,不同的Network间Endpoint的通信彼此隔离。Network的实现可以是linux bridge、Open vSwitch等。
我们可以以Docker操作为例,简单看下CNM创建容器的工作流:
  • Create Network(docker network create)
- IpamDriver.RequestPool:创建subnetpool用于分配IP - IpamDriver.RequestAddress:为gateway获取IP - NetworkDriver.CreateNetwork:创建network和subnet
  • Create Container(docker run / docker network connect)
- IpamDriver.RequestAddress:为容器获取IP - NetworkDriver.CreateEndpoint:创建port - NetworkDriver.Join:为容器和port绑定 - NetworkDriver.ProgramExternalConnectivity - NetworkDriver.EndpointOperInfoCNM与libnetwork相对比较复杂,这里不做详细介绍,相关内容可参考libnetwork的Design Doc。再看下CNI:
4.png
其基本思想为:Container Runtime在创建容器时,先创建好network namespace,然后调用CNI插件为这个netns配置网络,其后再启动容器内的进程。CNI插件包括两部分:
  • CNI Plugin负责给容器配置网络,它包括两个基本的接口
- 配置网络:AddNetwork(net NetworkConfig,rt RuntimeConf)(types.Result,error) - 清理网络:DelNetwork(net NetworkConfig, rt RuntimeConf) error
  • IPAM Plugin负责给容器分配IP地址,实现包括host-local和dhcp等
再来看下CNI创建容器的工作流:
  • 容器runtime分配一个网络命名空间以及一个容器ID
  • 连同一些CNI配置参数传给网络驱动
  • 网络驱动会将该容器连接到网络并将分配的IP地址以JSON的格式返回给容器runtime
所有CNI插件均支持通过环境变量和标准输入传入参数:
$ echo '{"cniVersion": "0.3.1","name": "mynet","type": "macvlan","bridge": "cni0","isGateway": true,"ipMasq": true,"ipam": {"type": "host-local","subnet": "10.244.1.0/24","routes": [{ "dst": "0.0.0.0/0" }]}}' | sudo CNI_COMMAND=ADD CNI_NETNS=/var/run/netns/a CNI_PATH=./bin CNI_IFNAME=eth0 CNI_CONTAINERID=a CNI_VERSION=0.3.1 ./bin/bridge$ echo '{"cniVersion": "0.3.1","type":"IGNORED", "name": "a","ipam": {"type": "host-local", "subnet":"10.1.2.3/24"}}' | sudo CNI_COMMAND=ADD CNI_NETNS=/var/run/netns/a CNI_PATH=./bin CNI_IFNAME=a CNI_CONTAINERID=a CNI_VERSION=0.3.1 ./bin/host-local
直观的来看,CNI 的规范比较小巧。它规定了一个容器runtime和网络插件之间的简单的契约(详细内容请参考SPEC)。在斟酌某项技术的时候,我们需要考虑采纳的成本;是否会增加对供应商的依赖。社区的采纳程度和支持程度也是比较重要的考量。插件开发者还需要考虑哪种方式相对比较容易实现。目前,主流容器调度框架(Mesos、Kubernetes)与网络解决方案(Calico、Flannel等)都对CNI有良好的支持,另外其简单的接口使插件的开放成本很低;并且不依赖docker runtime,使容器解决方案有了更多选择(例如Mesos Containerizer)。所以,我们选择了CNI。在对比业内支持CNI接口的主流网络解决方案之前,需要对多主机条件下,容器的组网方案做下分类,来方便大家理解不同解决方案之间的区别:##Flat
  • L2 Flat
- 各个host中容器在虚拟与物理网络形成的VLAN(大二层)中 - 容器可以在任意host间迁移不用改变其IP - 不同租户IP不可Overlap
  • L3 Flat
- 各个host中容器在虚拟与物理网络中可路由,且为32位路由 - 因为是32位路由,所以容器在任意host间迁移不用改变IP - 不同租户IP不可Overlap,容器与物理网络IP也不可Overlap
5.png
##L3 Hierarchy - 各个host中容器在虚拟与物理网络中可路由 - 路由在不同层次上(VM/Host/Leaf/Spine)以聚合路由的形式存在 - 相同CIDR的容器需在物理上被组织在一起 - 容器在host间迁移需要改变IP - 不同租户IP不可Overlap,容器与物理网络IP也不可Overlap
6.png
##Overlay
  • L2 over L3
- 容器可跨L3 Underlay进行L2通信 - 容器可在任意host间迁移而不改变其IP
7.png
  • L3 over L3
- 容器可跨L3 Underlay进行L3通信 - 容器可在任意host间迁移可能需要改变其IP - 不同租户IP可Overlap,容器IP也可与Underlay网络Overlap下面我们来看下社区比较认可的几种容器网络解决方案。# Flannel通过给每台宿主机分配一个子网的方式为容器提供虚拟网络,它基于Linux TUN/TAP,使用UDP封装IP包来创建overlay网络,并借助etcd维护网络的分配情况。控制平面上host本地的flanneld负责从远端的ETCD集群同步本地和其它host上的subnet信息,并为POD分配IP地址。数据平面flannel通过Backend(比如UDP封装)来实现L3 Overlay,既可以选择一般的TUN设备又可以选择VxLAN设备。
8.png
从上图可以看出,Flannel是典型的L3 over L3组网方案。支持的Backend:
  • udp:使用udp封装,默认使用8285端口
  • vxlan:vxlan封装,需要配置VNI,Port(默认8472)和GBP
  • host-gw:直接路由的方式
  • 公有云vpc:aws-vpc、gce、ali-vpc
如上图,可以方便的与Docker集成:
source /run/flannel/subnet.envdocker daemon --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU} &
也提供CNI接口:CNI插件会将flannel网络配置转换为bridge插件配置,并调用bridge插件给容器netns配置网络。比如下面的flannel配置:
 {    "name": "mynet",    "type": "flannel",    "delegate": {        "bridge": "mynet0",        "mtu": 1400    }} 
会被插件转换为:
 {    "name": "mynet",    "type": "bridge",    "mtu": 1472,    "ipMasq": false,    "isGateway": true,    "ipam": {        "type": "host-local",        "subnet": "10.1.17.0/24"    }} 
Flannel便是通过CNI与Mesos、Kubernetes集成。由于历史原因,我们线上Kubernetes集群是通过前一种方式直接与Docker集成的。优点:
  • 配置安装简单,使用方便
  • 与公有云集成方便,VPC方式无Overhead
缺点:
  • Vxlan模式对平滑重启支持不好(重启需要数秒来刷新ARP表,且不可变更配置,例如VNI、iface)
  • 功能相对简单,不支持Network Policy
  • Overlay存在一定Overhead
# Weave不同于其它的multi-host方案,其支持去中心化的控制平面,各个host上的wRouter间通过建立Full Mesh的TCP链接,并通过Gossip来同步控制信息。这种方式省去了集中式的K/V Store,能够在一定程度上减低部署的复杂性。不过,考虑到docker libnetwork是集中式的K/V Store作为控制平面,因此Weave为了集成docker,它也提供了对集中式控制平面的支持,能够作为docker remote driver与libkv通信。数据平面上,Weave通过UDP封装实现L2 Overlay,封装支持两种模式:
  • 运行在user space的sleeve mode:通过pcap设备在Linux bridge上截获数据包并由wRouter完成UDP封装,支持对L2 traffic进行加密,还支持Partial Connection,但是性能损失明显。
9.png
  • 运行在kernal space的 fastpath mode:即通过OVS的odp封装VxLAN并完成转发,wRouter不直接参与转发,而是通过下发odp 流表的方式控制转发,这种方式可以明显地提升吞吐量,但是不支持加密等高级功能。
10.png
- 所有容器都连接到Weave网桥 - weave网桥通过veth pair连到内核的OpenVSwitch模块 - 跨主机容器通过openvswitch vxlan通信 - policy controller通过配置iptables规则为容器设置网络策略关于Service的发布,Weave做的也比较完整。首先,wRouter集成了DNS功能,能够动态地进行服务发现和负载均衡,另外,与libnetwork 的overlay driver类似,weave要求每个容器有两个网卡,一个就连在lb/ovs上处理L2 流量,另一个则连在docker0上处理Service流量,docker0后面仍然是iptables作NAT。同事,提供了一个容器监控和故障排查工具Weave Scope,可以方便的生成整个集群的拓扑并智能分组。优点:去中心化、故障自愈、加密通讯、支持组播缺点:
  • sleeve mode性能损耗巨大
  • full mesh模型限制了集群规模
  • Partial Connection在fastpath未实现
# Contiv思科开源的容器网络方案,是一个用于跨虚拟机、裸机、公有云或私有云的异构容器部署的开源容器网络架构,并与主流容器编排系统集成。Contiv最主要的优势是直接提供了多租户网络,并支持L2(VLAN),L3(BGP),Overlay(VXLAN)以及思科自家的ACI。主要由两部分组件组成:
  • Netmaster
- 对外提供REST API - 学习并分发路由到Netplugin - 管理集群资源(IP、VLAN、VXLAN ID等)
  • Netplugin
- 运行在集群中每个节点上 - 实现了CNI与CNM接口 - 通过REST方式与Netmaster通讯,监听事件,并做相应网络配置 - 数据平面使用OVS实现(插件架构,可替换,例如VPP、BPF)
11.png
优点:
  • 支持多种组网方式,集成现有SDN方案
  • 多租户网络混部在同一台主机上
  • 插件化的设计,可替换的数据平面
  • 即时生效的容器网络Policy/ACL/QoS规则
  • 基于OVS的高性能Load Balancer的支持
  • 清晰的设计,方便二次开发
缺点:
  • 功能丰富带来的副作用便是配置和使用比较复杂
  • 因为发展时间较短,社区和文档都不怎么成熟,也存在一些bug,稳定性有待商榷
  • CNI plugin对Mesos支持不友好(跟Cisco官方沟通后,对Mesos支持仍在POC阶段)
# OpenContrail是Juniper推出的开源网络虚拟化平台,其商业版本为Contrail。OpenContrail主要由控制器和vRouter组成:
  • 控制器提供虚拟网络的配置、控制和分析功能
  • vRouter提供分布式路由,负责虚拟路由器、虚拟网络的建立以及数据转发
vRouter支持三种模式:
  • Kernel vRouter:类似于ovs内核模块
  • DPDK vRouter:类似于ovs-dpdk
  • Netronome Agilio Solution (商业产品):支持DPDK, SR-IOV and Express Virtio (XVIO)
12.png
从上图可以看出,OpenContrail的架构是相当复杂的。相应的,其提供的feature基本覆盖了前所有提到的方案;甚至包括基于Cassandra后端的流量采样与分析平台;由于篇幅所限,这里不做详细介绍,相关内容可参考Arch Doc。计算机科学的先驱David Wheeler曾经说过——“Any problem in computer science can be solved with another level of indirection.”, SDN即是Network的indirection。容器网络解决方案多不胜数,我们在这里就不一一介绍了。但是我们可以看到,每种方案其实都是对network做了不同程度的indirection,但是不要忘了后面还有一句——“except of course for the problem of too many indirections”,所以大家在不同的方向上做出了取舍与权衡。正如前面所提到的,在斟酌某项技术的时候,我们需要考虑采纳成本、对供应商的依赖、社区的支持程度等等。我们正在如此权衡之后,并没选择上面的方案,而是选择了Calico,下面我会详细说明。# CalicoCalico 是一个纯三层的数据中心网络方案(不需要Overlay),并且与OpenStack、Mesos、Kubernetes、AWS、GCE等IaaS和容器平台都有良好的集成。Calico是一个专门做数据中心网络的开源项目。当业界都痴迷于Overlay的时候,Calico实现multi-host容器网络的思路确可以说是返璞归真——pure L3,pure L3是指容器间的组网都是通过IP来完成的。这是因为,Calico认为L3更为健壮,且对于网络人员更为熟悉,而L2网络由于控制平面太弱会导致太多问题,排错起来也更加困难。那么,如果能够利用好L3去设计数据中心的话就完全没有必要用L2。不过对于应用来说,L2无疑是更好的网络,尤其是容器网络对二层的需求则更是强烈。业界普遍给出的答案是L2 over L3,而Calico认为Overlay技术带来的开销(CPU、吞吐量)太大,如果能用L3去模拟L2是最好的,这样既能保证性能、又能让应用满意、还能给网络人员省事,看上去是件一举多得的事。用L3去模拟L2的关键就在于打破传统的Hierarchy L3概念,IP不再以前缀收敛,大家干脆都把32位的主机路由发布到网络上,那么Flat L3的网络对于应用来说即和L2一模一样。这个思路不简单,刨了L2存在必要性的老底儿,实际上如果不用考虑可扩展性、隔离性,IP地址和MAC地址标识endpoint的功能上确实是完全冗余的,即使考虑可扩展性,一个用L3技术形成的大二层和一个用L2技术形成的大二层并没有本质上的差距。而且,L3有成熟的、完善的、被普遍认可接受的控制平面,以及丰富的管理工具,运维起来要容易的多。于是,Calico给出了下面的设计:
13.png
Calico在每一个计算节点利用Linux Kernel实现了一个高效的vRouter来负责数据转发,而每个vRouter通过BGP协议负责把自己上运行的workload的路由信息向整个Calico网络内传播—,路由条目全是/32的v4或者/128的v6。小规模部署可以直接互联,大规模下可通过指定的BGP route reflector来完成。 这样保证最终所有的workload之间的数据流量都是通过IP路由的方式完成互联的。Calico节点组网可以直接利用数据中心的网络结构(无论是L2或者L3),不需要额外的NAT,隧道或者Overlay Network。
14.png
此外,Calico基于iptables还提供了丰富而灵活的网络Policy,保证通过各个节点上的ACLs来提供Workload的多租户隔离、安全组以及其他可达性限制等功能。另外,对CNM与CNI的支持使其可以方便适配绝大多数场景。这里有必要说明下,CNI和CNM并非是完全不可调和的两个模型。二者可以进行转化的,calico项目最初只支持CNI,后面才加入CNM的支持。从模型中来看,CNI中的container应与CNM的sandbox概念一致,CNI中的network与CNM中的network一致。在CNI中,CNM中的endpoint被隐含在了ADD/DELETE的操作中。CNI接口更加简洁,把更多的工作托管给了容器的管理者和网络的管理者。从这个角度来说,CNI的ADD/DELETE接口其实只是实现了docker network connectdocker network disconnect两个命令。类似的,kubernetes/contrib项目提供了一种从CNI向CNM转化的过程,这里就不做详细介绍了。我们详细看下Calico中的各个组件:
  • Felix:Calico Agent,跑在每台需要运行Workload的节点上,主要负责通过iptables来配置ACLs
  • etcd:分布式键值存储,主要负责网络元数据一致性,确保Calico网络状态的准确性
  • confd:根据etcd上状态信息,与本地模板,生成并更新BIRD配置
  • BGP Client(BIRD):主要负责容器的路由信息分发到当前Calico网络,确保Workload间的通信的有效性
  • BGP Route Reflector(BIRD):大规模部署时使用,摒弃所有节点互联的 mesh 模式,通过一个或者多个BGP Route Reflector来完成集中式的路由分发
这个架构,技术成熟、高性能、易维护,看起来是生产级别的容器网络环境最好的选择。但是,也有不如意的地方:
  • 没有了外面的封装,就谈不上VRF,多租户的话地址没法Overlap
  • L2和L3的概念模糊了,那么network级别的安全就难以实现,port级别的安全实现难是因为需要的规则都是1:1的,数量太多
上面并不是什么严重的问题。但是有一点,Calico控制平面的上述设计中,物理网络最好是L2 Fabric,这样vRouter间都是直接可达的,路由不需要把物理设备当做下一跳。如果是L3 Fabric,控制平面的问题就来了:物理设备如果要存32位的路由,路由表将变得巨大无比。因此,为了解决以上问题,Calico不得不采取了妥协,为了支持L3 Fabric,Calico推出了IPinIP的选项,用作cross-subnet下容器间通讯,但是有一定性能损耗。另一种方案是回退到L3 Hierarchy(calico目前支持),如果对容器迁移保持IP不变的需求不大,可以选择这种,这也是我们最后选择的方案。不过,对于使用L2 Fabric、没有多租户需求的企业来说,用calico上生产环境应该最理想选择。Calico最理想的部署方式是基于L2 Fabrics的,官方也有相应说明(Calico over an Ethernet interconnect fabric),这里就不做详细说明了。由于我们数据中心规模比较大,显然L2 Fabrics不是理想的选择。事实也是如此,我们多个数据中心组成的网络是以BGP为控制层面组成的L3 Fabrics。每个数据中心为一个AS。这里不讨论跨数据中心的问题,大家只需知道我们跨数据中心在L3上是互通的便可以。官方给出了3种基于L3 Fabrics的组网建议(详细介绍可点击进去查看):AS per Rack这种模型在每个ToR下加入了RR(Route Reflector),关于RR,前面有提到过,这里有必要解释一下:首先说下BGP的水平分割原则(这里只谈IBGP),从IBGP学习到的路由绝不对再传播给其它的IBGP邻居(可以传给EBGP邻居)。IBGP水平分割主要是为了防止在AS内部产生路由环路。所以,为了AS内路由正确收敛,需要所有节点组成full mesh结构(也就是两两之间建立邻居)。但是,这种架构在大型网络中显然行不通。另一种解决方案便是RR,一种C/S模型。在同AS内,其中一台设备作为RR,其他设备作为Client。Client与RR之间建立IBGP连接。路由反射器和它的客户机组成一个Cluster。这里不详细讨论RR的工作原理。显然,路由反射破坏了水平分割的原则,所以便要许多额外的配置来防止环路,这会给实际部署过程带来很多负担。另外,我们同一数据中心内运行的是IBGP,也就是都在同AS内。这使的配置改造更为复杂,而且,显然不符合AS per Rack。另外两种模型同样要求每个ToR在不同的AS,也面临上述问题。另外,如果不在ToR上做路由聚合,AS per Compute Server会造成Linux服务器上有全网的路由,庞大的路由表也会成为性能的瓶颈。经过与网络部门的认真研讨,我们最终选择了下面的部署模型:
15.png
  • 每个Server选择不同的AS号,且与数据中心AS不同,与ToR建立EBGP邻居
  • Server使用原有网关(默认路由),ToR不向Server宣告任何路由条目
  • Server本地聚合路由到28位,并宣告给ToR
  • 与网络部门制定一定算法(方便自动化),用Server的IP地址计算出AS号

可以看到,上述方案,几乎不用对数据中心现有网络架构做出改变;而且,也大大减少了Server与ToR上路由条目数。

实际部署Calico的Agent时,我们还遇到了一些问题:官方默认只提供基于Docker的部署方式,也就是之前提到的几个组件都部署在一个Docker容器中。calicoctl也是基于Docker容器做部署操作。但是,实际环境中,我们线上的Mesos集群有部分是只是用Mesos Containerizer的,也就是并没有Docker环境;而且,我们认为,Calico Agent加入对Docker daemon的依赖,考虑到稳定性,显然不是一个良好的选择。

所以,我们对Calico组件进行拆解,重新拼装,并去掉我们用不到IPv6模块;最终通过systemd在每台server上运行bird、confd、felix这三个模块,实现了去Docker化的部署(实际上对confd的模板也做了些改造,去掉了IPinIP的支持,并且适配的非Docker环境)。整个过程基于Ansible,实现了一键部署。

关于性能问题,虽然Calico在众多基于软件的容器网络解决方案里是性能最好的,但是也不是完全没有性能损耗。前面说过,Calico实现namespace内外通讯是通过linux内核的veth pair来实现的(就是之前提到的接入方式中的VSwitch/Bridge)。确实增加了一层overhead,但是好在veth pair的实现比较简单,性能损耗几乎可以忽略(无policy条件下)。我们实际测试中,对于echo server(小报文测试),请求延迟会增加0.02到0.04ms;对于bandwidth(大报文测试,万兆环境),很难看到差别。

到了这一步,你可能觉得我们大功告成,实则不然。其实我们还有很多事情可以做,也需要去做。Calico支持丰富的安全策略,但是在server上是用kernel的netfilter实现的(iptables),大量policy下的性能仍有待考察。

业内也有一些其他的实现思路,例如Google大力支持cilium方案,其policy的实现就用了BPF(Berkeley Packet Filter,最早在kernel 3.15中加入,4.8版本以后标为stable)。BPF的基本思路是把用作包处理的代码通过llvm编译成ir,然后插入到正在运行的kernel网络栈中,通过jit方式执行,大幅度提高了处理能力。这里不做详细介绍,相关信息可以看这里。cilium还加入了对XDP的支持(一种类似DPDK的技术,但是目前集成在kernel中),来加速网络栈的处理。这些都不失为未来改造calico的一个方向。

另外一个问题是,calico目前并没有对traffic shaping的支持。试想,当大量容器运行与同一物理机,其进出流量都共享物理网卡,如果不对容器流量进行限制,单个容器过分使用网络资源就会影响其他容器提供服务(磁盘IO也有同样问题,但是不在本文讨论范围)。Calico社区目前也在讨论这个问题,详情可见这个issue,目前还在API制定的阶段。

上述问题,底层实现目前可行选择是linux自带的tc(OVS同样用到了tc)。上层切入点却有两个选择,一是拓展Calico的API,在felix上实现应用tc规则的逻辑;另一种是在CNI plugin上hook,通过相应的调度系统,传参数进来,由plugin来应用tc规则。由于,calico社区已经在讨论这个问题,而且第二种方案实现起来成本也比较低。现阶段,我们只考虑方案二,也做了相应的POC。

实践过程中,由于veth pair两端的流量是相反的(ingress与egress),理论上可以在两端的egress上应用tc规则(tc只支持egress方向的shaping),来实现两个方向上的QoS。但是,我们还是遇到了一些问题,namespace内的虚拟网卡上的tc规则虽然可配置,但是并不生效。而且,这些规则对容器内应用是可见、可修改的,这样做也并不安全。所以,我们用到了ifb内核模块,把物理机上虚拟网卡的ingress流量变成egress,最终在在ifb网卡上应用tc规则,来实现容器egress方向的QoS。关于ifb,功能比较简单,大家可以看下kernel代码中相关的介绍:
/* drivers/net/ifb.c:

The purpose of this driver is to provide a device that allows
for sharing of resources:

1) qdiscs/policies that are per device as opposed to system wide.
ifb allows for a device which can be redirected to thus providing
an impression of sharing.

2) Allows for queueing incoming traffic for shaping instead of
dropping.

The original concept is based on what is known as the IMQ
driver initially written by Martin Devera, later rewritten
by Patrick McHardy and then maintained by Andre Correa.

You need the tc action mirror or redirect to feed this device
packets.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version
2 of the License, or (at your option) any later version.

Authors: Jamal Hadi Salim (2005)

*/

迫于篇幅限制,这次就先到这里吧,后续我会把一些详细实现拿出来给大家分享,欢迎共同交流。

看了上面这么多,有人可能会问,我们做了这么多工作,究竟是为了什么。回过头来看今天,我们理所当然的用着方便的跨数据中心环网、接入负载均衡、共享存储、对象存储,甚至到上层的云平台等等。正是因为有了这些,业务们拿出编译好的代码,快的不到几分钟就可以被线上的用户所使用。

这就是基础设施,这些是这座大楼的地基。正因为如此,基础设施的改造才异常困难。我们需要用合理的抽象来解决顽疾,更需要对上层建筑的兼容。正如我们在网络方面所做的工作,让容器和现有物理设备在三层上的互通,实现了网络上对业务的透明;同时又提供了良好的性能,消除了业务迁移到云平台上的顾虑;在提高资源利用率的混部环境下,同时提供可配置的策略,为服务质量提供了有效的保障。

作者:郝一昕,来自360搜索私有云团队

同程容器云平台网络方案演进

李颖杰 发表了文章 • 0 个评论 • 2650 次浏览 • 2017-07-26 22:53 • 来自相关话题

【编者的话】同程旅游PaaS平台是从2014年开始搭建的,到现在已经持续发展了三个年头。规模从原来的几百个容器到现在上万个容器。在容器调度上从原来的手动操作到现在的自动伸缩与扩容,在宿主机部署密度上从原来的十几个容器到现在上百个容器……我们的PaaS云平台在三 ...查看全部
【编者的话】同程旅游PaaS平台是从2014年开始搭建的,到现在已经持续发展了三个年头。规模从原来的几百个容器到现在上万个容器。在容器调度上从原来的手动操作到现在的自动伸缩与扩容,在宿主机部署密度上从原来的十几个容器到现在上百个容器……我们的PaaS云平台在三年间进行了3次大版本的迭代。本文主要介绍同程旅游PaaS云平台在持续集成和持续部署方面,基于Docker对网络方案的选型及应用,以及随着业务需求的增加而经历的网络方案变更过程。

【3 天烧脑式基于Docker的CI/CD实战训练营 | 北京站】本次培训围绕基于Docker的CI/CD实战展开,具体内容包括:持续集成与持续交付(CI/CD)概览;持续集成系统介绍;客户端与服务端的 CI/CD 实践;开发流程中引入 CI、CD;Gitlab 和 CI、CD 工具;Gitlab CI、Drone 的使用以及实践经验分享等。
#系统的初始形态
PaaS平台最初是基于Swarm搭建的,Swarm是Docker公司推出的一套容器调度平台。它的特点是简单易用,部署方便,学习成本低,因为它所有的命令和Docker命令基本上是一致的。容器有4种网络模式Bridge、Host、Container以及None ,开始我们使用的网络方案是Host模式,这种模式下,容器没有独立的IP网络栈,它共用了宿主机的IP地址。为了防止端口冲突,应用对外暴露服务的时候,需要指定端口,并且这个端口在同一宿主机上唯一(不然会冲突),然后再对接负载均衡器,这样就打通了整个网络链路。整个架构非常简洁,对于当时每天几十个容器以及无状态的应用,是能够完全满足需要的。

网络访问流程如下所示:
001.png

后来随着业务的发展,各种业务也慢慢的容器化,比如说Redis、Hadoop、Database、中间件等等。Host模式越来越显得力不从心,最严重的情况是很多应用没办法往上部署。举个例子来说,像Redis应用,它主要功能是做缓存,在高并发的情况下,一个Redis容器能把网络跑满,如果同一台宿主机上还有其它容器,这就会导致其它容器无法正常对外提供服务。像Database服务,为了做HA,需要容器拥有独立的网络,在迁移的时候保持IP不变。

但在Host模型下,容器网络依赖宿主机网络,容器对外访问需要通过宿主机IP加容器唯一端口,当容器发生迁移的时候,访问容器的方式(IP:Port)也要跟着改变,无法满足用户在平台外部需要直接使用IP访问的需求。为了解决此类问题,急需对容器进行网络隔离,让每个容器拥有独立IP。
#基于Public IP的网络订制
为了满足业务需求,开始研究如何使容器实例以Public IP方式供用户使用。首先什么是Public IP,Public IP就是让容器拥有一个独立的网络协议栈,有一个独立的IP地址。用户可以直接通过这个独立的IP地址访问应用,这样可以方便地解决端口冲突问题。有了这个目标以后,接下来就对目前现有的Docker网络方案进行调研评估。首先简单介绍下现有的容器网络方案,网上也看了很多对比,对于各方案的优缺点这里也做一个简单的总结。
##隧道方案
其典型的代表是:

* Weave,UDP广播,本机建立新的BR,通过PCAP互通。
* Open vSwitch(OVS),基于VxLAN和GRE协议,但是性能方面损失比较严重。
* Flannel,UDP广播,VxLan。

隧道方案在IaaS层的网络中应用也比较多,大家共识是随着节点规模的增长复杂度会提升,而且出了网络问题跟踪起来比较麻烦,大规模集群情况下这是需要考虑的一个点。另外,由于隧道方案性能损失比较严重,所以隧道方案暂时不考虑使用。
##路由方案
其比较典型的代表有:

* Calico,基于BGP协议的路由方案,支持很细致的ACL控制,对混合云亲和度比较高。
* Macvlan,从逻辑和Kernel层来看隔离性和性能最优的方案,基于二层隔离,所以需要二层路由器支持,大多数云服务商不支持,所以混合云上比较难以实现。

路由方案一般是从3层或者2层实现隔离和跨主机容器互通的,出了问题也很容易排查。

在这里我们说一下Calico。

首先它既支持Docker的CNM网络模型也支持像Kubernetes主推的CNI网络模型。既有着不俗的性能表现,提供了很好的隔离性,而且还有不错的ACL控制能力。通过将整个互联网的可扩展IP网络原则压缩到数据中心级别,Calico在每一个计算节点利用Linux Kernel实现了一个高效的vRouter来负责数据转发,而每个vRouter通过BGP协议负责把自己上运行的workload的路由信息像整个Calico网络内传播——小规模部署可以直接互联,大规模下可通过指定的BGP route reflector来完成。这样保证最终所有的workload之间的数据流量都是通过IP路由的方式完成互联的。

此外,Calico基于iptables还提供了丰富而灵活的网络Policy,保证通过各个节点上的ACLs来提供Workload的多租户隔离、安全组以及其他可达性限制等功能。

Calico 架构如下图所示:
002.jpg

对于Calico方案,我们也做了一些测试,首先它的网络转性能非常高,接近原生物理网卡的性能。但Calico依赖BGP协议,需要根据需要,频繁变更物理路由器的配置。对于传统物理网络有一定的侵入性,为了兼容以往的网络架构只能放弃。
##Vlan方案
其比较典型的代表有:

* Contiv netplugin
* Pipework

这里我们着重讲一下Contiv。

Contiv是Cisco开源出来的针对容器的基础架构,主要功能是提供基于Policy的网络和存储管理,是面向微服务的一种新基架,同时它又支持CNM以及CNI网络模型。Contiv能够和主流的容器编排系统整合,包括:Docker Swarm、Kubernetes、Mesos and Nomad。
003.png

如上图所示,Contiv比较“诱人”的一点就是,它的网络管理能力,既有L2(VLAN)、L3(BGP),又有 Overlay(VxLAN),而且还能对接Cisco自家的 SDN 产品 ACI。可以说有了它就可以无视底层的网络基础架构,向上层容器提供一致的虚拟网络了。

最主要的一点是,既满足了业务场景,又兼容了以往的网络架构。在转发性能上,它能达到物理网卡95%的性能。在高并发的场景下,OVS可能会消耗一部分CPU性能。对于这方面后期打算通过DPDK来做改善。另外,Contiv netmaster节点Down了以后不会造成网络中断,可以降低风险。还有一个优点是基于OVS可以灵活地做Policy/ACL/Qos监控等等,最终选择使用Contiv netplugin。

接下来我们说一下Contiv Netplugin在公司的落地情况。

首先根据实际网络访问描述下Contiv在PaaS平台整体部署结构:
004.jpg

目前我们通过Mesos + Marathon实现了容器的动态扩容以及动态负载,能够根据业务负载快速响应,做到自动伸缩,下面我们介绍一下网络模块Contiv。

Contiv主要包含3部分:

  1. netctl客户端主要用来发送命令到Contiv Netmaster;
  2. Netmaster服务端用来管理所有的Netplugin,以及提供IP地址分配IPMI功能;
  3. Netplugin插件跑在每个swarm node节点上,接收Netmaster指令控制OVS实现路由转发功能。

Contiv带来的方便是用户可以根据实例IP直接进行访问,可以借助ovs做很多策略,以及监控等,Contiv Netplugin特性主要有以下几点:

  1. 多租户网络混部在同一台主机上;
  2. 集成现有SDN方案;
  3. 能够和非容器环境兼容协作,不依赖物理网络具体细节;
  4. 即时生效的容器网络Policy/ACL/QoS规则。

可以说Contiv有很多丰富的特性,能够满足大部分业务场景,但有些场景目前Contiv还无法支持需要做二次开发,比如说应用容器IP固定,流量监控等。接下来讲一下我们是如何基于Contiv做IP持久化的。

大家都知道,Docker容器网络模型使用的是CNM(Container Network Model),这的底层是通过Libnetwork实现的,只要符合这个模型的网络接口就能被用于容器之间通信,而通信的过程和细节可以完全由网络接口来实现。
005.jpg


* Sandbox:对应一个容器中的网络环境,包括相应的网卡配置、路由表、DNS配置等。CNM很形象的将它表示为网络的『沙盒』,因为这样的网络环境是随着容器的创建而创建,又随着容器销毁而不复存在的。沙盒的实现可以是Linux Network Namespace、FreeBSD Jail之类的概念,并包含连接多个网络的Endpoint;
* Endpoint:实际上就是一个容器中的虚拟网卡,在容器中会显示为eth0、eth1依次类推。它可以是veth对,或者Open vSwitch的internal port。一个Endpoint只能属于一个沙盒;
* Network:指的是一个能够相互通信的容器网络,加入了同一个网络的容器直接可以直接通过对方的名字相互连接。它的实体本质上是主机上的虚拟网卡或网桥。

在CNM模型下,容器需要先通过IPMI获取IP,然后再创建Endpoint。我们的做法是,在启动容器之前,先调用Contiv rest API获取IP,Contiv Netmaster收到allocate ip的请求以后,将分配的IP保留起来,接下来在创建容器的时候指定所获取的IP,Netmaster收到创建Endpoint的请求将,保留的IP分配给容器,这样就做到了IP持久化。

创建容器的时序图如下:
006.png

#网络监控
在网络流量监控方面,我们通过使用OVS的sFlow来抓取宿主机上所有的网络流量,然后自开发了一个简单的sFlow Collecter,服务器收到sFlow的数据包进行解析,筛选出关键数据,丢到Redis(这里的Redis是做来做缓存的作用)。然后再通过ELK集群定时从Redis拉取数据,进行汇总分析。前端通过调用ELK的API,得到所需要的监控数据。

通过对网络进行改造,目前已经将Redis,大数据,DB等诸多复杂的业务成功的跑在了容器中,切切实实解决了业务的痛点。随着PaaS云平台的演进,由Swarm切换为Mesos + Marathon,后期也会根据需求对Contiv不断优化。

三年多的持续迭代,只为达到更高的要求。
>铭记初心,只为让更多人享受旅游的乐趣。
>
——王文建



原文链接:同程容器云平台网络方案演进&version=12020610&nettype=WIFI&fontScale=100&pass_ticket=FLwEXJsRPG3OGe5piakWkIHrzthK2rlKfn3ITRd1TSLnVhmID7y9j4z8eu7HFxt7)(作者:王文建)

DockOne微信分享(一三三):深入理解Kubernetes网络策略

尼古拉斯 发表了文章 • 0 个评论 • 4326 次浏览 • 2017-07-21 15:45 • 来自相关话题

【编者的话】当我们逐渐向着微服务、云原生迈进的时候,传统静态的、相对简单的网络安全策略开始显得吃力。 Kubernetes 的 Network Policy 特性正是来解决这个问题的。在刚刚出炉不久的1.7版本中,该特性也被扶正成为GA。让我们来一起看看 Ne ...查看全部
【编者的话】当我们逐渐向着微服务、云原生迈进的时候,传统静态的、相对简单的网络安全策略开始显得吃力。 Kubernetes 的 Network Policy 特性正是来解决这个问题的。在刚刚出炉不久的1.7版本中,该特性也被扶正成为GA。让我们来一起看看 Network Policy 是什么,能为我们做什么,以及是如何实现的。

【3 天烧脑式基于Docker的CI/CD实战训练营 | 北京站】本次培训围绕基于Docker的CI/CD实战展开,具体内容包括:持续集成与持续交付(CI/CD)概览;持续集成系统介绍;客户端与服务端的 CI/CD 实践;开发流程中引入 CI、CD;Gitlab 和 CI、CD 工具;Gitlab CI、Drone 的使用以及实践经验分享。

# CNI
Kubernetes 对网络做了较好的抽象。它将对网络的需求交给外部的组件完成,也就是 CNI driver。

Pod 的网络必须满足以下三个需求:

  1. 所有 Pod 之间无需 NAT 即可互通
  2. 主机和 Pod 之间无需 NAT 即可互通
  3. Pod 自省的 IP 地址和之外部看到该 Pod 的地址一致

CNI 对网络的实现做了详细的定义。CNI 的实现可以被分成三种:

  1. 3 层路由实现
  2. Overlay 实现
  3. 2 层交换实现

现在比较常用的 CNI 实现有:Flannel、Calico、Weave。 Flannel 通过 VXLan Overlay 来实现跨主机 Pod 网络, Calico 则完全通过 3 层路由来实现了跨主机的容器网络,Weave也是 Overlay 的实现。
# 什么是Network Policy
随着业务逻辑的复杂化,微服务的流行,越来越多的云服务平台需要大量模块之间的网络调用。

传统的单一外部防火墙,或依照应用分层的防火墙的做法渐渐无法满足需求。在一个大的集群里面,各模块,业务逻辑层,或者各个职能团队之间的网络策略的需求越来越强。

Kubernetes 在 1.3 引入了 Network Policy 这个功能来解决这个问题。这些 Policy 允许用户在同一个 Cluster 内实现网络的隔离。也就是在某些需要的 Pod 之间架起防火墙。可以简单的理解为各个微服务之间的动态防火墙。也有人把这叫做分布式防火墙。

并非所有的网络驱动都支持这个功能。比如大家比较熟悉的,比较流行的 Flannel 就还没有加入对 Network Policy 的支持。Calico 和 Weave 都各自实现了 NPC(network policy controller)。虽然 Flannel 不支持 Network Policy。但是,可以使用 Flannel 提供网络方案,同时使用 Calico 或者Weave 的 NPC 组件来共同完成。Canal 就提供了将 Flannel 和 Calico NPC 组合的方案。
# DEMO
下面我们就以Calico为基础,给大家做一个demo。

这里我已经搭好了一个 Kubernetes 的简单的集群:只有一个 master 和两个 minion。我们先来部署 Calico。这里要注意的是,由于我们要 demo 的是最新的 Kubernetes API,我们必须使用 Kubernetes 1.7 和 Calico 2.3,并且,Calico只能配置成 Kubernetes Datastore 的模式。在这种模式下,Calico 对网络状态的控制是通过 Kubernetes API 来完成的。另外还有一种模式是通过 etcd 集群。那种模式暂时还不支持最新的API。Kubernetes Datastore 这种方式有时也叫做KDD — Kubernetes datastore driver。

在进行 KDD 模式的 Calico 安装时要注意以下这么几点:

  1. IPAM 要使用 host-local
  2. 通过 controller manager 来分配 CIDR

细节请点击:http://docs.projectcalico.org/v2.3/getting-started/kubernetes/installation/hosted/kubernetes-datastore/

配置好 Calico之后,我们来看一个简单的 demo,实际操作一下 Network Policy:

为了简单起见,我们会直接使用 default namespace。如果你在一个现有的环境里面, 可以将以下的命令在一个独立的 namespace 里面运行。

创建 namespace 使用这个命令:
kubectl create ns np-demo

接下来运行一个简单的 nginx deployment 并用80端口暴露服务:
kubectl run nginx --replicas=2 --image=nginx
deployment "nginx" created
kubectl expose deploy nginx --port=80
service "nginx" exposed

现在我们还没有做任何的限制,所以 Kubernetes 缺省情况是所有 Pod 都是开放的。

我们来用一个 BusyBox 的 Pod 验证一下:
kubectl run busy --rm -ti --image busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget -q nginx -O - | head -4

上面的 Wget 命令是在 BusyBox 这个 Pod 里面执行的。`-q` 和 `-O -` 的组合会使这个命令在命令行输出 nginx 的缺省首页,这表明我们的验证是成功的。用 Ctl-D 退出容器。

接下来我们就要加入限制了。我们的做法是先限制对所有 Pod 的访问,然后建立白名单。 kubectl apply下面的 YAML 文件就可以限制所有访问:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: default-deny
spec:
podSelector:

注意我们提供了一个空的 podSelector。

我们再试着用之前的 BusyBox 的方式来访问一下:
kubectl run busy --rm -ti --image busybox /bin/sh
/ # wget -q --timeout=5 nginx -O -


这此我们设置了 5 秒的超时。因为访问被拒接,所以确实会超时:
wget: download timed out 

好,我们的第一个 Network Policy 已经生效了。然而,限制对所有 Pod 的访问显然是没有意义的。接下来我们建立一个白名单 . apply 下面的 YAML 文件:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: access-nginx
spec:
podSelector:
matchLabels:
run: nginx
ingress:
- from:
- podSelector:
matchLabels:
run: access

这个 Network Policy 的意思是:标签 run:access 选中的 Pod 可以访问标签 run:nginx 的 Pod,也就是我们 demo 开始时创建的 Nginx 的 Pod。这些 label 都是 kubectl run 命令自动 添加的。

接下来我们试试看能否成功地访问了:
kubectl run access --rm -ti --image busybox /bin/sh
wget -q nginx -O -

我们依然会看到熟悉的 Nginx 缺省首页。如果我们运行一个不符合上述 selector 的 Pod,就无法访问。这个留给有兴趣的同学自己回去验证。

如果你接触过 1.7 之前的 Network Policy 的话,你可能会发现这里的 API 有些不同。Kubernetes 1.7 已经将 Network Policy 正式提升到 GA。

正式的 API 和之前的 API 区别有:

  1. 不再使用 Annotation 来表达 default-deny 等这样的规则
  2. API version 从 extension/beta1 升级到了 networking.k8s.io/v1

# 实现
Calico 的实现是基于 iptables 的。在每个 chain 的顶端,Calico 都插入了一条定制的 chain,从而使得 packet 优先经过 Calico 定义的规则。我们在其中一个 minion 上面运行 iptables-save -c 就可以检查这些规则。可以看出 kube-proxy 和 Calico 都定义了大量的 iptable 规则。

这里细节很多,我们只需要关注这几点:

Calico 使用 conntrack 来优化。就是说,一旦一个连接已经建立,之后的packet都会直接被允许通过。比如:
-A cali-fw-cali7af3f94d3a1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 
-A cali-fw-cali7af3f94d3a1 -m conntrack --ctstate INVALID -j DROP

名为 cali-pi-xxxx 的规则是负责 Network Policy Ingress 的。我们可以想见,如果我们定义了很多 Policy,一个一个单独定义的规则会导致性能下降。这里 Calico 利用了 iptables 的 ipset 特性。使得一个 rule 可以通过 hash 表来匹配多种地址。
-A cali-pi-_G7e-YAvXRsfDoqGDf36 -m set --match-set cali4-s:2I5R46OBA_TBIUlpH0dCd_n src -j MARK --set-xmark 0x1000000/0x1000000 
-A cali-pi-_G7e-YAvXRsfDoqGDf36 -m mark --mark 0x1000000/0x1000000 -j RETURN

Weave 的实现也类似。底层还是使用了 iptables 和 netfilter。Weave 也创建了自定义的 chain。但由于一个是 Overlay 一个是路由,规则还是有些不同的。

另外一个细微的不同是,Weave使用了 -m state 而不是 -m conntrack。conntrack 是比较新的语法,但实际使用中功能是一样的。下面是几个 Weave 安装的 iptables rules 的例子:
FORWARD chain:
-o weave -j WEAVE-NPC
-o weave -j DROP
WEAVE_NPC chain:
-m state --state RELATED,ESTABLISHED -j ACCEPT
-m state --state NEW -j WEAVE-NPC-DEFAULT
-m state --state NEW -j WEAVE-NPC-INGRESS
-m set --match-set weave-v/q_G.;Q?uK]BuDs2 dst -j ACCEPT
-m set --match-set weave-k?Z;25^M}|1s7P3|H dst -j ACCEPGo

# Q&A
Q:Calico 和 Weave 从 Policy 处理性能来看,两者哪个更优?

A:两者在 iptables 层面上的实现原理是一样的。都用了-m
state 和 ipset 优化,性能差别不大。



Q:Calico 结合 Kubernetes 怎么实现多租户,比如网络隔离之类的?

A:可以考虑用 namespace 来隔离。没有 Network Policy 的情况下当然是互通的。但是 Kubernetes 的 Network Policy 支持 namespaceSelector,可以轻松搞定。



Q:Weave、Calico、Flannel 比较,适用场景和优缺点是什么,Flannel out了么?

A:各有各的市场 :-)。
Flannel 比较简单,资源消耗也会小些。Flannel 不能算 out 了。Cannel 的出现将 Flannel 和 Calico 整合了起来。



Q:NPC 必须用 iptables 实现吗?在某些情况下,Pod 出向流量并不会由主机协议栈,这样 iptables 就用不了,这种情况下 NPC 怎么实现呢 ?

A:Calico、Weave、Romana 的 NPC 都是通过 iptables 实现的。Pod
egress 不通过主机协议栈也会通过 netfilter。



以上内容根据2017年07月20日晚微信群分享内容整理。分享人梁文智:睿云智合研发顾问。 DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesa,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

3 天烧脑式容器存储网络训练营 | 深圳站

李颖杰 发表了文章 • 0 个评论 • 5321 次浏览 • 2017-06-21 18:29 • 来自相关话题

容器进入云计算AI时代,大规模容器集群即将进入千万家企业,业务特征十分复杂,如:容器数量庞大,需要满足快速部署灵活迁移,保证容器间跨物理机间的通信;保证业务、资源与物理位置无关,容器可以任意迁移;承载多种业务,需要保证业务间的安全隔离及访问控制。存储和网络的容 ...查看全部
容器进入云计算AI时代,大规模容器集群即将进入千万家企业,业务特征十分复杂,如:容器数量庞大,需要满足快速部署灵活迁移,保证容器间跨物理机间的通信;保证业务、资源与物理位置无关,容器可以任意迁移;承载多种业务,需要保证业务间的安全隔离及访问控制。存储和网络的容器化技术成为关键点,云计算从业者必须尽快在传统数据中心在使用云化后,着手解决大二层网络中的经典问题如MAC表项不足、ARP风暴、VLAN的4k上限等问题。目前业界主要有两种容器网络模型CNM和CNI来实现容器的网络方案,其中坑多知识点也多,尽快掌握这些技术方案成为不断完善自身业务能力的必须课程。

* 培训时间:7月20日——7月22日
* 课程难度:中高级
* 课程人数:20-40人
* 地点: 广东深圳市南山区粤兴三道9号华中科技大学产学研基地B座二楼T204教室
* 费用:4999元/人
* 报名链接:http://www.bagevent.com/event/649106
* 垂询电话:132 4116 6558
* 微信:liyingjiesa

培训对象:

* 容器开发和运维工程师
* 有志于从事容器技术的在职人员或者学生

技能要求:

* 对容器技术有一定了解
* 工作或者学习中有使用到容器技术

优惠信息:

* 团购3-4人每人优惠300
* 团购5人第6人免费

证书:

培训结束后,将提供『云计算容器(Docker)技术能力』中级测评考试,考试通过后,将获得『云计算容器(Docker)技术能力』中级能力测评认证证书,此认证是由科技部统一印制、统一编号、统一管理的国家级职业技能证书,是反映开源软件开发与应用技能水平的国家级职业资格认证。该证书在全国范围内通用有效,目前也是国内首个『容器技术』认证证书。

培训结束将统一为学员安排考试,考试时长1小时。

内容设置:

Docker文件系统基础

  • Docker分层文件系统
  • image的存储表现
  • Container的存储表现
Cgroup文件系统分析及实战
  • Cgroup及其subsystem介绍
  • Cgroup进行资源限制实战
Docker Plugin是如何设计的Docker storage driver分析及选型
  • AUFS
  • Btrfs
  • Device mapper
  • OverlayFS
  • OverlayFS2
  • ZFS
Docker Volume Plugin的工作原理常见Docker Volume Pulgin
  • Local volume plugin
  • Local Persist Plugin
  • Contiv Volume Plugin
  • Convoy plugin
  • Flocker plugin
  • GlusterFS plugin
  • rbd-docker-plugin
Kubernetes Storage机制
  • Volume类型介绍
  • PV/PVC原理及使用
  • Dynamic provisioning介绍及使用

Kubernetes管理有状态应用案例

经验分享

容器网络实现原理

* 容器实现原理
* Namespace介绍
* Cgroup介绍
* Cgroup手动实现容器网络之实战

容器网络模型: CNI vs CNM

* Docker网络模型CNM
* Kubernetes网络模型CNI

Docker网络实现CNM之Libnetwork

* Docker原生网络Bridge、Overflay、IPVLAN、MacVLAN
* Libnetwork plugin driver

容器网络插件

* CNM libnetwork插件的开发实现
* CNI插件的开发实现
* 常见的network driver

Calico原理及实现

* 什么是Calico
* Calico实现框架
* Calico典型部署

Contiv Netplugin原理及实现、性能

* Netplugin介绍
* Netplugin架构分析
* Netplugin源码实现
* 经验分享

开源企业级镜像仓库Harbor原理及实现

* Harbor介绍及主要特性
* Harbor架构分析
* Harbor高可用实现

讲师

* 王涛,原唯品会资深云计算工程师。西电研究生毕业后,一直从事云计算领域的开发和架构近六年。曾先后在华为和唯品会从事FusionSphere增值服务开发,以及IaaS、PaaS平台的架构开发。专注于研究Docker、Kubernetes、Mesos等容器技术,对Docker和Kubernetes源码有较深入研究和二次开发经验。

* 贺佰元,唯品会资深云计算开发工程师,北邮计算机硕士。研究生期间开始从事虚拟化和云计算的课题研究,曾先后任职于雅虎北研、中国移动,一直负责私有云和公有云的研发和架构工作,包括IaaS\PaaS平台、对象存储、容器云等的开发和架构设计,已有6年多的云计算领域实践经验。对虚拟化及OpenStack、Docker容器技术、Kubernetes和Mesos、分布式存储等有丰富的源码二次开发和架构选型经验。

报名链接:http://www.bagevent.com/event/649106

DockOne微信分享(一九八):容器网络限流实践

范彬 发表了文章 • 0 个评论 • 1162 次浏览 • 2019-01-09 09:51 • 来自相关话题

【编者的话】我们需要为“上云“的应用提供流量带宽保证,使其不受到其他应用或其他用户的应用的影响。我们需要提供租户级别或者应用级别的有效隔离。今天将分享一下我们为了达到这个目标做了哪些实践工作。 # 容器平台做容器网络限流的意义 无论我们 ...查看全部
【编者的话】我们需要为“上云“的应用提供流量带宽保证,使其不受到其他应用或其他用户的应用的影响。我们需要提供租户级别或者应用级别的有效隔离。今天将分享一下我们为了达到这个目标做了哪些实践工作。
# 容器平台做容器网络限流的意义
无论我们的目标是搭建公有云的容器云平台还是为客户提供容器平台的私有部署或解决方案,我们都会面临一个问题:容器网络限流的问题。在我们实验室的环境下,如果没有对容器带宽进行限制,单Pod使用的最大吞吐量将可以独占整个带宽,从而导致其他应用不能被访问。

单用户单Pod在没有做任何网络带宽限制情况下,网络吞吐量测试结果如下:
0.png

我们需要为“上云”的应用提供流量带宽保证,使其不受到其他应用或其他用户的应用的影响。我们需要提供租户级别或者应用级别的有效隔离。今天将分享一下我们为了达到这个目标做了哪些实践工作。

在Kubernetes众多的网络插件中,我们选择使用Open vSwitch容器网络插件。通常情况下,我们根据VNID实现租户间的网络隔离,并且在此基础上我们还可以根据Networkpolicy网络策略提供更细粒度的网络隔离,可以实现Pod之间、跨Namespace的网络访问控制。
1.png

# 使用Open vSwitch容器网络插件如何进行容器网络限流
使用Open vSwitch容器网络插件如何进行容器网络限流呢?Open vSwitch本身不实现QoS,它使用Linux内核自带的traffic-control机制进行流量控制。主要两种实现方式:

* Policing管制:Policing用于控制接口上接收分组(ingress)的速率,是一种简单的QoS的功能,通过简单的丢包机制实现接口速率的限制,它既可以作用于物理接口,也可以作用于虚拟接口。
* Shaping整形:Shaping是作用于接口上的出口流量(egress)策略,可以实现QoS队列,不同队列里面处理不同策略。

2.png

##Policing的实现
Policing在OVS中采用ingress_policing_rate和ingress_policing_burst两个字段完成ingress入口限速功能,该两个字段放在Interface表中。

入口限速直接配置在网络接口上,命令示例如下:
# ovs-vsctl set interface eth1 ingress_policing_rate=1000
# ovs-vsctl set interface eth1 ingress_policing_burst=100


* eth1:加入OVS桥端口的网络接口名称;
* ingress_policing_rate:为接口最大收包速率,单位kbps,超过该速度的报文将被丢弃,默认值为0表示关闭该功能;
* ingress_policing_burst:为最大突发流量大小,单位kb。默认值0表示1000kb,这个参数最小值应不小于接口的MTU,通常设置为ingress_policing_rate的10%更有利于tcp实现全速率;

通过命令ovs-vsctl list interface eth1可以查看配置:
OpenvSwitch-QoS-fig-1.png

##Shaping的实现
Shaping用于实现出口流量的控制,使用了队列Queue,可以缓存和调度数据包发送顺序,比Policing更加精确和有效,在OVS的数据表中主要使用QoS和Queue两张表。

QoS创建命令:
ovs-vsctl set port eth1 qos=@newqos--  
--id=@newqoscreate qos type=linux-htb queues=0=@q0--
--id=@q0create queue other-config:max-rate=100000000

创建Queue:
--id=@q0 create queue other-config:max-rate=100000000

创建q0队列,设置最大速率100M,通过ovs-vsctl查看配置的Queue表内容如下:
OpenvSwitch-QoS-fig-4.png

创建Qos规则:
--id=@newqos create qos type=linux-htb queues=0=@q0

创建QoS规则newqos,类型为linux-htb,并连接key值为0的队列q0,通过ovs-vsctl查看配置的QoS表内容如下:
OpenvSwitch-QoS-fig-5.png

创建接口Qos:
set port eth1 qos=@newqos

设置接口eth1的QoS为newqos,通过ovs-vsctl list port查看配置的port表内容如下:
OpenvSwitch-QoS-fig-6.png

我们采用的技术栈是Golang。我们也可以使用红帽提供的OVS的库github.com/openshift/origin/pkg/util/ovs实现上面Policing和Shaping功能。

代码示意如下:
image.png

image1.png

在Kubernetes上,如果使用Open vSwitch CNI插件,我们可以在创建Pod资源的时候为其配置速率限制。

创建iperf-pod.yaml,并为其配置速率限制:
cat <iperf-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: iperf
annotations:
kubernetes.io/ingress-bandwidth: 3M
kubernetes.io/egress-bandwidth: 3M
spec:
containers:
- name: iperf
image: yadu/hello-openshift-iperf
imagePullPolicy: IfNotPresent
nodeSelector:
zone: default
EOF

流入测试:

Pod容器里启动iperf server:
$ iperf -s -p 12345 -i 1
------------------------------------------------------------
Server listening on TCP port 12345
TCP window size: 85.3 KByte (default)
------------------------------------------------------------

在任意节点向iperf server产生流量:
[root@a-node4 ~]# iperf -c 10.130.2.103 -p 12345 -i 1 -t 10 -w 5m
------------------------------------------------------------
Client connecting to 10.130.2.103, TCP port 12345
TCP window size: 416 KByte (WARNING: requested 4.77 MByte)
------------------------------------------------------------
[ 3] local 10.130.2.1 port 58162 connected with 10.130.2.103 port 12345
[ ID] Interval Transfer Bandwidth
[ 3] 0.0- 1.0 sec 773 KBytes 6.33 Mbits/sec
[ 3] 1.0- 2.0 sec 316 KBytes 2.59 Mbits/sec
[ 3] 2.0- 3.0 sec 314 KBytes 2.57 Mbits/sec
(omitted)

查看Pod里流入的日志:
iperf -s -p 12345 -i 1
------------------------------------------------------------
Server listening on TCP port 12345
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
[ 4] local 10.130.2.103 port 12345 connected with 10.130.2.1 port 58162
[ ID] Interval Transfer Bandwidth
[ 4] 0.0- 1.0 sec 354 KBytes 2.90 Mbits/sec
[ 4] 1.0- 2.0 sec 351 KBytes 2.87 Mbits/sec
[ 4] 2.0- 3.0 sec 349 KBytes 2.86 Mbits/sec
(omitted)

流出测试:

在任意节点上启动iperf server作为测试:
iperf -s -p 12345 -i 1
------------------------------------------------------------
Server listening on TCP port 12345
TCP window size: 85.3 KByte (default)
------------------------------------------------------------

Pod中用iperf client进行测试:
iperf -c 172.18.143.117 -p 12345 -i 1 -t 10 -w 5m
------------------------------------------------------------
Client connecting to 172.18.143.117, TCP port 12345
TCP window size: 416 KByte (WARNING: requested 5.00 MByte)
------------------------------------------------------------
[ 3] local 10.130.2.103 port 44602 connected with 172.18.143.117 port 12345
[ ID] Interval Transfer Bandwidth
[ 3] 0.0- 1.0 sec 1.62 MBytes 13.6 Mbits/sec
[ 3] 1.0- 2.0 sec 384 KBytes 3.15 Mbits/sec
[ 3] 2.0- 3.0 sec 384 KBytes 3.15 Mbits/sec
(omitted)

查看node4上流入的日志:
iperf -s -p 12345 -i 1
------------------------------------------------------------
Server listening on TCP port 12345
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
[ 4] local 172.18.143.117 port 12345 connected with 10.130.2.103 port 44602
[ ID] Interval Transfer Bandwidth
[ 4] 0.0- 1.0 sec 1.28 MBytes 10.7 Mbits/sec
[ 4] 1.0- 2.0 sec 373 KBytes 3.05 Mbits/sec
[ 4] 2.0- 3.0 sec 380 KBytes 3.11 Mbits/sec
[ 4] 3.0- 4.0 sec 339 KBytes 2.77 Mbits/sec
(omitted)

查看tc的配置:
[root@a-node4 ~]# tc -s -d class show dev vethddb66bac
class htb 1:1 parent 1:fffe prio 0 quantum 1450 rate 11600bit ceil 3000Kbit burst 1513b/1 mpu 0b overhead 0b cburst 1513b/1 mpu 0b overhead 0b level 0
Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0
lended: 0 borrowed: 0 giants: 0
tokens: 16314655 ctokens: 63083

class htb 1:fffe root rate 3000Kbit ceil 3000Kbit burst 1449b/1 mpu 0b overhead 0b cburst 1449b/1 mpu 0b overhead 0b level 7
Sent 4187548 bytes 2872 pkt (dropped 0, overlimits 0 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0
lended: 998 borrowed: 0 giants: 0
tokens: 60416 ctokens: 6041

#实现AdmissionWebhook组件:bandwidth-inject-webhook
在公有云平台中,我们可以根据租户等级,为其创建的Pod设置不同级别的限流限制。我们通过自研开发实现了AdmissionWebhook组件:bandwidth-inject-webhook。当创建Pod的配置文件yaml提交给apiserver时,可以为其增加网络限流配置。
image2.png

上面是我们基于Open vSwitch的CNI做的一些研究和开发工作。当然,我们也可以借鉴华为自研的CNI插件,去支持任何网络插件的情景。
image4.png


参考文章:Open vSwitch之QoS的实现:https://www.sdnlab.com/19208.html
#Q&A
Q:网络插件为什么没用Flannel?
A:如果选择flannel cni网络插件,可以采用华为开发的限流CNI插件。

Q:目前Istio也具有限速功能,这与tc限速共存吗?
A:SDN控制器,红帽开源的OpenShift有相应的实现。OVS选择是vxlan方式解决节点间通信。Istio的限流方式暂时我还没有了解。

以上内容根据2019年1月8日晚微信群分享内容整理。分享人范彬,现电信云容器项目研发组长。对技术保有一颗热衷的心。自2016年起开始一直从事容器、微服务等方面的研究和开发工作。熟悉Golang技术栈、Kubernetes分布式系统架构和工作原理。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesd,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

DockOne微信分享(一三八):白话Kubernetes网络

FanLin 发表了文章 • 0 个评论 • 5231 次浏览 • 2017-08-22 00:47 • 来自相关话题

【编者的话】容器的网络是在CaaS集群中无法避免的话题,作为当下最主流的一种容器集群解决方案,Kubernetes对网络进行了合理的抽象,并采用了开放的CNI模型。面对各种容器网络实现,他们有什么不同,应该如何选择?本文将带大家回顾Kubernetes各种主流 ...查看全部
【编者的话】容器的网络是在CaaS集群中无法避免的话题,作为当下最主流的一种容器集群解决方案,Kubernetes对网络进行了合理的抽象,并采用了开放的CNI模型。面对各种容器网络实现,他们有什么不同,应该如何选择?本文将带大家回顾Kubernetes各种主流网络方案的发展历程,并透过现象清本质,用形象的例子展示Weave、Flannel、Calico和Romana等网络解决方案背后的原理。

【3 天烧脑式基于Docker的CI/CD实战训练营 | 北京站】本次培训围绕基于Docker的CI/CD实战展开,具体内容包括:持续集成与持续交付(CI/CD)概览;持续集成系统介绍;客户端与服务端的 CI/CD 实践;开发流程中引入 CI、CD;Gitlab 和 CI、CD 工具;Gitlab CI、Drone 的使用以及实践经验分享等。

白话Kubernetes网络.001_.jpeg

这次讲一讲容器集群中的网络。其实不同的容器集群解决方案,在网络方面的核心原理都是相似的,只不过这次我们将以Kubernetes为线索,来窥斑见豹的一睹容器网络的发展过程。
白话Kubernetes网络.002_.jpeg

我是来自ThoughtWorks的林帆,我们从Docker的0.x版本开始就在对容器的应用场景进行探索,积累了一线的容器运用经验。这次分享会用简洁易懂的方式告诉大家我们对容器网络方面的一些知识归纳。
白话Kubernetes网络.003_.jpeg

初入容器集群的人往往会发现,和单节点的容器运用相比,容器的网络和存储是两个让人望而却步的领域。在这些领域里,存在大量的技术名词和术语,就像是一道道拒人于门外的高门槛。
白话Kubernetes网络.004_.jpeg

为了便于理解,我们将这些名称简单的分个类别,从简单到复杂,依次递增。今天的话题会涉及的深度大致在这个大池子的中间,希望大家看完以后会对目标线以上的内容不再陌生,目标线以下的内容我们也会依据需要适当的提及。
白话Kubernetes网络.005_.jpeg

此外,这个话题会按照Kubernetes的网络发现过程作为时间主线,其中重点介绍CNI标准和它的主流实现。
白话Kubernetes网络.006_.jpeg

在早期的Kubernetes中,对网络是没有什么标准的。文档中对网络的描述只有很简单的几句话,其实就是让用户在部署Kubernetes之前,预先准备好容器互联的网络解决方案。Kubernetes只对网络提出设计假设,这三条假设总结起来就是:所有容器都可以和集群里任意其他容器或者主机通信,并且通信双方看到的对方IP地址就是实际的地址(即不经过网络地址转换)。

基于这样的底层网络,Kubernetes设计了Pod - Deployment - Service的经典三层服务访问机制。

既然Kubernetes不提供底层网络实现,在业界就出现了很多企业级的以及开源的第三方解决方案,其中下面这页图中展示了这个时期的主流开源方案。
白话Kubernetes网络.007_.jpeg

我们将这些方案依据配置的复杂度,分为“全自动”和“半自动”两类,就像是汽车中的自动挡和手动挡的差别。

“全自动”的解决方案使用起来简单,适用于标准网络环境的容器跨节点通信。

“半自动”的解决方案实际上是对底层协议和内核模块功能的封装,提供了选择十分丰富的网络连接方法,但对使用者的网络原理知识有一定要求。
白话Kubernetes网络.008_.jpeg

在Kubernetes的1.1版本中,发生了一件很重要的变化,那就是Kubernetes全面采纳CNI网络标准。

CNI诞生于2015年4月,Kubernetes的1.1版本诞生于2015年9月,之间仅隔5个月。在这个时期,Docker也设计了一套网络标准,称为CNM(即Libnetwork)。Kubernetes采用CNI而非CNM,这背后有很长的一段故事,核心的原因就是CNI对开发者的约束更少,更开放,不依赖于Docker工具,而CNM对Docker有非常强的依赖,无法作为通用的容器网络标准。在Kubernetes的官方博客里有一篇博文详细讨论了个中细节,InfoQ上有一篇该博客的翻译,有兴趣的读者不妨一读。
白话Kubernetes网络.009_.jpeg

几乎在Kubernetes宣布采纳CNI以后的1个月,之前提到的“全自动”网络方案就悉数实现了CNI的插件,这也间接说明了CNI的简单。

那么CNI到底有多简单呢?举几个数字。

实现一个CNI插件需要的内容包括一个Json配置文件和一个可执行的文件(脚本或程序),配置文件描述插件的版本、名称、描述等基本信息,可执行文件就是CNI插件本身会在容器需要建立网络和需要销毁容器的时候被调用。

当一个CNI插件被调用时,它能够通过6个环境变量以及1个命令行参数(Json格式文本)来获得需要执行的操作、目标网络Namespace、容器的网卡必要信息,每个CNI插件只需实现两种基本操作:创建网络的ADD操作,和删除网络的DEL操作(以及一个可选的VERSION查看版本操作)。

最新的CNI规范可以通过上图中的链接访问,只有一页网页的内容而已。同时Kuberntes社区也提供了一个利用“docker network”命令实现的简单CNI插件例子,只用了几十行Bash脚本。
白话Kubernetes网络.010_.jpeg

那么面对这么多的社区CNI插件,我们怎样选择呢?

直观的说,既然是网络插件,在功能差不多的情况下,我们当然先关心哪个的速度快。

为此我此前专门做过一次对比测试,不过由于使用了公有云的网络环境(云上环境的不同主机之间相对位置不固定),在汇总数据的时候才发现测试结果偏离理论情况过于明显。

这个数据大家且当娱乐,不过对于同一种插件的不同工作模式(比如Flannel的三种模型)之间,由于是使用的相同的虚拟机测试,还是具有一定可参考性。

先抛开测试结果,从理论上说,这些CNI工具的网络速度应该可以分为3个速度等级。

最快的是Romana、Gateway模式的Flannel、BGP模式的Calico。

次一级的是IPIP模式的Calico、Swarm的Overlay网络、VxLan模式的Flannel、Fastpath模式的Weave。

最慢的是UDP模式的Flannel、Sleeve模式的Weave。
白话Kubernetes网络.012_.jpeg

这里我也提供出测试容器网络速度的具体方法,以便大家重复这个测试。
白话Kubernetes网络.013_.jpeg

要解释这些网络插件和模式速度不同的原因,我们需要先回到这些工具最初要解决的问题上来。那就是跨节点的网络不通。

如果仔细观察,会发现在3种网络速度模式中都有Flannel的身影。因此我们不妨先以Flannel为例来看这些网络工具(和相应的CNI插件)是如何解决网络不通问题的。
白话Kubernetes网络.014_.jpeg

跨节点网络不同有几个方面的原因,首先是容器的地址重复。

由于Docker等容器工具只是利用内核的网络Namespace实现了网络隔离,各个节点上的容器是在所属节点上自动分配IP地址的,从全局来看,这种局部地址就像是不同小区里的门牌号,一旦拿到一个更大的范围上看,就可能是会重复的。
白话Kubernetes网络.015_.jpeg

为了解决这个问题,Flannel设计了一种全局的网络地址分配机制,即使用Etcd来存储网段和节点之间的关系,然后Flannel配置各个节点上的Docker(或其他容器工具),只在分配到当前节点的网段里选择容器IP地址。

这样就确保了IP地址分配的全局唯一性。
白话Kubernetes网络.016_.jpeg

是不是地址不重复网络就可以联通了呢?

这里还有一个问题,是对于不同的主机、以及网络上的路由设备之间,并不知道这些IP容器网段的地址是如何分配的,因此数据包即使被发送到了网络中,也会因为无法进行路由而被丢掉。

虽然地址唯一了,依然无法实现真正的网络通信。
白话Kubernetes网络.017_.jpeg

为此,Flannel采用了几种处理方法(也就是Flannel的几种网络模式)。

早期时候用的比较多的一种方式是Overlay网络。

在这种方式下,所有被发送到网络中的数据包会被添加上额外的包头封装。这些包头里通常包含了主机本身的IP地址,因为只有主机的IP地址是原本就可以在网络里路由传播的。

根据不同的封包方式,Flannel提供了UDP和Vxlan两种传输方法。

UDP封包使用了Flannel自定义的一种包头协议,数据是在Linux的用户态进行封包和解包的,因此当数据进入主机后,需要经历两次内核态到用户态的转换。

VxLAN封包采用的是内置在Linux内核里的标准协议,因此虽然它的封包结构比UDP模式复杂,但由于所有数据装、解包过程均在内核中完成,实际的传输速度要比UDP模式快许多。

但比较不幸的是,在Flannel开始流行的时候,大概2014年,主流的Linux系统还是Ubuntu 14.04或者CentOS 6.x,这些发行版的内核比较低,没有包含VxLAN的内核模块。因此多数人在开始接触Flannel时候,都只能使用它的UDP模式,因此Flanned一不小心落得了一个“速度慢”的名声,特别是在之后的Calico出来以后(其实Flannel的Gateway模式与Calico速度相当,甚至理论上还要快一点点,稍后解释)。

这是第一种解决网络无法路由的方法。
白话Kubernetes网络.018_.jpeg

第二种思路是,既然在无法进行路由是因为网络中的节点之间没有路由信息,但Flannel是知道这个信息的,能不能把这个信息告诉网络上的节点呢?

这就是Flannel的Host-Gateway模式,在这种模式下,Flannel通过在各个节点上的Agent进程,将容器网络的路由信息刷到主机的路由表上,这样一来所有的主机就都有整个容器网络的路由数据了。

Host-Gateway的方式没有引入像Overlay中的额外装包解包操作,完全是普通的网络路由机制,它的效率与虚拟机直接的通信相差无几。

然而,由于Flannel只能够修改各个主机的路由表,一旦主机直接隔了个其他路由设备,比如三层路由器,这个包就会在路由设备上被丢掉。

这样一来,Host-Gateway的模式就只能用于二层直接可达的网络,由于广播风暴的问题,这种网络通常是比较小规模的,但近年来也出现了一些专门的设备能够构建出大规模的二层网络(就是我们经常听到的“大二层”网络)。

那么其他的CNI插件呢?

由于Flannel几乎是最早的跨网络通信解决方案,其他的方案都可以被看做是Fannel的某种改进版。
白话Kubernetes网络.019_.jpeg

比如Weave的工作模式与Flannel是很相似的,它最早只提供了UDP(称为sleeve模式)的网络方式,后来又加上了fastpass方式(基于VxLAN),不过Weave消除了Flannel中用来存储网络地址的额外组件,自己集成了高可用的数据存储功能。
白话Kubernetes网络.020_.jpeg

Calico的设计比较新颖,之前提到Flannel的Host-Gateway模式之所以不能跨二层网络,是因为它只能修改主机的路由,Calico把改路由表的做法换成了标准的BGP路由协议。

相当于在每个节点上模拟出一个额外的路由器,由于采用的是标准协议,Calico模拟路由器的路由表信息就可以被传播到网络的其他路由设备中,这样就实现了在三层网络上的高速跨节点网络。

不过在现实中的网络并不总是支持BGP路由的,因此Calico也设计了一种IPIP模式,使用Overlay的方式来传输数据。IPIP的包头非常小,而且也是内置在内核中的,因此它的速度理论上比VxLAN快一点点,但安全性更差。
白话Kubernetes网络.021_.jpeg

Cannal将Calico和Flannel做了一下组合,同时支持两者的特性。
白话Kubernetes网络.022_.jpeg

Romana只支持与Flannel相同的Host-Gateway模式,但它在网络策略方面做了比较多的增强,通过额外引入的租户概念简化了网络策略所需的IPtables规则数量。
白话Kubernetes网络.023_.jpeg

这是几种主流CNI工具的横向对比。
白话Kubernetes网络.024_.jpeg

在Kubernetes的1.2版本以后开始引入了一个新的工具,叫做 kubernet,它实现了内置的网络地址分配功能。结合一些云平台上的内网路由表功能,就能够直接执行跨网络通信,相当于把跨网络功能内建到Kubernetes里面了。

这是一个从“只做假设”到“设定标准”到“内置实现”的很大的改变。
白话Kubernetes网络.025_.jpeg

在Kubernetes的1.3版本以后,开始加入网络策略相关的支持。并且在1.7版本后结束了Beta阶段,成为正式API的一部分。

值得一说的是,Kubernetes的网络策略采用了比较严格的单向流控制,即假如允许服务A访问服务B,反过来服务B并不一定能访问服务A。这与Docker内置的Network命令实现的隔离有很大不同。
白话Kubernetes网络.026_.jpeg

纵向的对比一下主流的容器集群对今天提到的这些网络特性的支持情况和时间点。
# Q&A
Q:Kubernetes的网络策略采用了比较严格的单向流控制,即假如允许服务A访问服务B,反过来服务B并不一定能访问服务A。为什么要设计成严格单向流呢?

A:主要是安全性的原因,这是一种更精细的权限控制策略,除了方向,Kuberetes还允许对可访问的端口进行控制。



Q:Open vSwitch有测过么?

A:没有测试,Open vSwitch同样可以配置成Overlay网络或者Macvlan网络等不同的通信模式,速度也会落到相应的档位上。那个测试例子只是为了说明网络速度与采用的通信原理有关,同时引出几种主流的通信模式原理,测试数据是不准确的,建议以在自己的实际环境中测试结果为准。



Q:Calico怎么做网段间的隔离?

A:各种网络工具的网络策略基本上都是基于内核的Iptables模块实现的。比如Calico只是根据用户配置,自动管理各个节点上的Iptables规则。其他有些改进的,比如Romana设计了一种基于“租户”的规则管理机制,可以用更少的Iptables规则实现网络隔离。



Q:如果在Kubernetes里面需要做到平行网络,让每一个Pod获取一个业务IP,除了Bridge+Vlan的方式,还有更好的建议么?

A:这次讲的这些CNI插件都会让每一个Pod获得一个独立业务IP。可以根据实际网络情况和对速度的需求选择。



Q:Calico BGP IPIP NAT三种模式分别怎么配置?原理是怎样的?其中IPIP还有两种模式,区别在哪?

A:在Calico的配置中设置`spec.ipip.enabled: ture`就会开启IPIP模式,否则默认是纯BGP模式。IPIP的两种模式其实是指纯IPIP(ipip always模式)或者混合IPIP和BGP(ipip cross-subnet),后者指的是“同子网内路由采用BGP,跨子网路由采用IPIP”,主要用于即想在内网获得高速,又想在跨公网时能保持联通的情况。这种模式需要每个节点启动时用`--ip`参数预先配置节点的子网,并且所有节点版本都在v2.1以上。



Q:能麻烦具体介绍一下kube-proxy这种网络模式的优缺点吗,在测试过程中发现很不稳定,但是又没发现足够的证据。

A:kube-proxy是Kubernetes的一个组件,提供通过Service到Pod的路由,并不是一种网络模式,不同的网络插件都会使用到这个组件。



以上内容根据2017年08月15日晚微信群分享内容整理。分享人林帆,ThoughtWorks DevOps和容器技术咨询师。从事软件开发运维以及社区宣传工作,热衷于对DevOps和容器技术应用的推广,在容器规模化运维方面有较丰富实践经验,著有《CoreOS实践之路》一书。 DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesa,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

容器网络——从CNI到Calico(360搜索)

man4acs 发表了文章 • 0 个评论 • 8344 次浏览 • 2017-08-07 10:51 • 来自相关话题

从容器诞生开始,存储和网络这两个话题就一直为大家津津乐道。我们今天这个环境下讲网络这个问题,其实是因为容器对网络的需求,和传统物理、虚拟环境对网络环境需求是有差别的,主要面临以下两个问题: 过去IaaS层在网络方便做了很多工作,已经形 ...查看全部
从容器诞生开始,存储和网络这两个话题就一直为大家津津乐道。我们今天这个环境下讲网络这个问题,其实是因为容器对网络的需求,和传统物理、虚拟环境对网络环境需求是有差别的,主要面临以下两个问题:

  • 过去IaaS层在网络方便做了很多工作,已经形成了成熟的环境,如果和容器环境适配,两边都需要做很多改造
  • 容器时代提倡微服务,导致容器的粒度之小,离散程度之大,原有IaaS层网络解决方案很难承载如此复杂的需求
我们来看下一些主流的容器网络接入方案:# Host network最简单的网络模型就是让容器共享Host的network namespace,使用宿主机的网络协议栈。这样,不需要额外的配置,容器就可以共享宿主的各种网络资源。# 共享物理网卡这种接入方式主要使用SR-IOV技术,每个容器被分配一个VF,直接通过PCIe网卡与外界通信。SR-IOV 技术是一种基于硬件的虚拟化解决方案,可提高性能和可伸缩性。SR-IOV 标准允许在虚拟机之间高效共享 PCIe设备,并且它是在硬件中实现的,可以获得能够与本机性能媲美的 I/O 性能。启用了 SR-IOV 并且具有适当的硬件和 OS 支持的 PCIe 设备(例如以太网端口)可以显示为多个单独的物理设备,每个都具有自己的 PCIe 配置空间。SR-IOV主要用于虚拟化中,当然也可以用于容器:
1.png
SR-IOV配置(需要网卡支持,线上主流万兆卡Intel 540可以支持128个VF(Virtual Function)):
modprobe ixgbevflspci -Dvmm|grep -B 1 -A 4 Ethernetecho 2 > /sys/bus/pci/devices/0000:82:00.0/sriov_numvfs # check ifconfig -a. You should see a number of new interfaces created, starting with “eth”, e.g. eth4
Intel也给Docker实现了一个SR-IOV network plugin,同样也有相应的CNI(后面会提到)Plugin。SR-IOV的接入方式可以达到物理网卡的性能,但是需要硬件支持,而且VF的数量是有限的。# 共享容器网络多个容器共享同一个netns,只需要第一个容器配置网络。比如Kubernetes Pod就是所有容器共享同一个pause容器的网络。# VSwitch/Bridge容器拥有独立的network namespace,通过veth-pair连接到VSwitch或者Bridge上。容器网络技术日新月异,有些相当复杂,而且提供某种功能的方式也多种多样。这样就给容器runtime与调度系统的实现与各种接入方式的适配带来的很大的困难。为了解决这些问题,Docker与CoreOS相继发布了容器网络标准,便是CNM与CNI,为Linux容器网络提供了统一的接口。先来看下CNM:
2.png
Libnetwork是CNM的原生实现。它为Docker daemon和网络驱动程序之间提供了接口。网络控制器负责将驱动和一个网络进行对接。每个驱动程序负责管理它所拥有的网络以及为该网络提供的各种服务,例如IPAM等等。由多个驱动支撑的多个网络可以同时并存。网络驱动可以按提供方被划分为原生驱动(libnetwork内置的或Docker支持的)或者远程驱动 (第三方插件)。原生驱动包括 none、bridge、overlay 以及 MACvlan。驱动也可以被按照适用范围被划分为本地(单主机)的和全局的 (多主机)。
3.png
  • Sandbox:一个Sandbox对应一个容器的网络栈,能够对该容器的interface、route、dns等参数进行管理。一个Sandbox中可以有多个Endpoint,这些Endpoint可以属于不同的Network。Sandbox的实现可以为linux network namespace、FreeBSD Jail或其他类似的机制。
  • Endpoint: Sandbox通过Endpoint接入Network,一个Endpoint只能属于一个Network。Endpoint的实现可以是veth pair、Open vSwitch internal port或者其他类似的设备。
  • Network:一个Network由一组Endpoint组成,这些Endpoint彼此间可以直接进行通信,不同的Network间Endpoint的通信彼此隔离。Network的实现可以是linux bridge、Open vSwitch等。
我们可以以Docker操作为例,简单看下CNM创建容器的工作流:
  • Create Network(docker network create)
- IpamDriver.RequestPool:创建subnetpool用于分配IP - IpamDriver.RequestAddress:为gateway获取IP - NetworkDriver.CreateNetwork:创建network和subnet
  • Create Container(docker run / docker network connect)
- IpamDriver.RequestAddress:为容器获取IP - NetworkDriver.CreateEndpoint:创建port - NetworkDriver.Join:为容器和port绑定 - NetworkDriver.ProgramExternalConnectivity - NetworkDriver.EndpointOperInfoCNM与libnetwork相对比较复杂,这里不做详细介绍,相关内容可参考libnetwork的Design Doc。再看下CNI:
4.png
其基本思想为:Container Runtime在创建容器时,先创建好network namespace,然后调用CNI插件为这个netns配置网络,其后再启动容器内的进程。CNI插件包括两部分:
  • CNI Plugin负责给容器配置网络,它包括两个基本的接口
- 配置网络:AddNetwork(net NetworkConfig,rt RuntimeConf)(types.Result,error) - 清理网络:DelNetwork(net NetworkConfig, rt RuntimeConf) error
  • IPAM Plugin负责给容器分配IP地址,实现包括host-local和dhcp等
再来看下CNI创建容器的工作流:
  • 容器runtime分配一个网络命名空间以及一个容器ID
  • 连同一些CNI配置参数传给网络驱动
  • 网络驱动会将该容器连接到网络并将分配的IP地址以JSON的格式返回给容器runtime
所有CNI插件均支持通过环境变量和标准输入传入参数:
$ echo '{"cniVersion": "0.3.1","name": "mynet","type": "macvlan","bridge": "cni0","isGateway": true,"ipMasq": true,"ipam": {"type": "host-local","subnet": "10.244.1.0/24","routes": [{ "dst": "0.0.0.0/0" }]}}' | sudo CNI_COMMAND=ADD CNI_NETNS=/var/run/netns/a CNI_PATH=./bin CNI_IFNAME=eth0 CNI_CONTAINERID=a CNI_VERSION=0.3.1 ./bin/bridge$ echo '{"cniVersion": "0.3.1","type":"IGNORED", "name": "a","ipam": {"type": "host-local", "subnet":"10.1.2.3/24"}}' | sudo CNI_COMMAND=ADD CNI_NETNS=/var/run/netns/a CNI_PATH=./bin CNI_IFNAME=a CNI_CONTAINERID=a CNI_VERSION=0.3.1 ./bin/host-local
直观的来看,CNI 的规范比较小巧。它规定了一个容器runtime和网络插件之间的简单的契约(详细内容请参考SPEC)。在斟酌某项技术的时候,我们需要考虑采纳的成本;是否会增加对供应商的依赖。社区的采纳程度和支持程度也是比较重要的考量。插件开发者还需要考虑哪种方式相对比较容易实现。目前,主流容器调度框架(Mesos、Kubernetes)与网络解决方案(Calico、Flannel等)都对CNI有良好的支持,另外其简单的接口使插件的开放成本很低;并且不依赖docker runtime,使容器解决方案有了更多选择(例如Mesos Containerizer)。所以,我们选择了CNI。在对比业内支持CNI接口的主流网络解决方案之前,需要对多主机条件下,容器的组网方案做下分类,来方便大家理解不同解决方案之间的区别:##Flat
  • L2 Flat
- 各个host中容器在虚拟与物理网络形成的VLAN(大二层)中 - 容器可以在任意host间迁移不用改变其IP - 不同租户IP不可Overlap
  • L3 Flat
- 各个host中容器在虚拟与物理网络中可路由,且为32位路由 - 因为是32位路由,所以容器在任意host间迁移不用改变IP - 不同租户IP不可Overlap,容器与物理网络IP也不可Overlap
5.png
##L3 Hierarchy - 各个host中容器在虚拟与物理网络中可路由 - 路由在不同层次上(VM/Host/Leaf/Spine)以聚合路由的形式存在 - 相同CIDR的容器需在物理上被组织在一起 - 容器在host间迁移需要改变IP - 不同租户IP不可Overlap,容器与物理网络IP也不可Overlap
6.png
##Overlay
  • L2 over L3
- 容器可跨L3 Underlay进行L2通信 - 容器可在任意host间迁移而不改变其IP
7.png
  • L3 over L3
- 容器可跨L3 Underlay进行L3通信 - 容器可在任意host间迁移可能需要改变其IP - 不同租户IP可Overlap,容器IP也可与Underlay网络Overlap下面我们来看下社区比较认可的几种容器网络解决方案。# Flannel通过给每台宿主机分配一个子网的方式为容器提供虚拟网络,它基于Linux TUN/TAP,使用UDP封装IP包来创建overlay网络,并借助etcd维护网络的分配情况。控制平面上host本地的flanneld负责从远端的ETCD集群同步本地和其它host上的subnet信息,并为POD分配IP地址。数据平面flannel通过Backend(比如UDP封装)来实现L3 Overlay,既可以选择一般的TUN设备又可以选择VxLAN设备。
8.png
从上图可以看出,Flannel是典型的L3 over L3组网方案。支持的Backend:
  • udp:使用udp封装,默认使用8285端口
  • vxlan:vxlan封装,需要配置VNI,Port(默认8472)和GBP
  • host-gw:直接路由的方式
  • 公有云vpc:aws-vpc、gce、ali-vpc
如上图,可以方便的与Docker集成:
source /run/flannel/subnet.envdocker daemon --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU} &
也提供CNI接口:CNI插件会将flannel网络配置转换为bridge插件配置,并调用bridge插件给容器netns配置网络。比如下面的flannel配置:
 {    "name": "mynet",    "type": "flannel",    "delegate": {        "bridge": "mynet0",        "mtu": 1400    }} 
会被插件转换为:
 {    "name": "mynet",    "type": "bridge",    "mtu": 1472,    "ipMasq": false,    "isGateway": true,    "ipam": {        "type": "host-local",        "subnet": "10.1.17.0/24"    }} 
Flannel便是通过CNI与Mesos、Kubernetes集成。由于历史原因,我们线上Kubernetes集群是通过前一种方式直接与Docker集成的。优点:
  • 配置安装简单,使用方便
  • 与公有云集成方便,VPC方式无Overhead
缺点:
  • Vxlan模式对平滑重启支持不好(重启需要数秒来刷新ARP表,且不可变更配置,例如VNI、iface)
  • 功能相对简单,不支持Network Policy
  • Overlay存在一定Overhead
# Weave不同于其它的multi-host方案,其支持去中心化的控制平面,各个host上的wRouter间通过建立Full Mesh的TCP链接,并通过Gossip来同步控制信息。这种方式省去了集中式的K/V Store,能够在一定程度上减低部署的复杂性。不过,考虑到docker libnetwork是集中式的K/V Store作为控制平面,因此Weave为了集成docker,它也提供了对集中式控制平面的支持,能够作为docker remote driver与libkv通信。数据平面上,Weave通过UDP封装实现L2 Overlay,封装支持两种模式:
  • 运行在user space的sleeve mode:通过pcap设备在Linux bridge上截获数据包并由wRouter完成UDP封装,支持对L2 traffic进行加密,还支持Partial Connection,但是性能损失明显。
9.png
  • 运行在kernal space的 fastpath mode:即通过OVS的odp封装VxLAN并完成转发,wRouter不直接参与转发,而是通过下发odp 流表的方式控制转发,这种方式可以明显地提升吞吐量,但是不支持加密等高级功能。
10.png
- 所有容器都连接到Weave网桥 - weave网桥通过veth pair连到内核的OpenVSwitch模块 - 跨主机容器通过openvswitch vxlan通信 - policy controller通过配置iptables规则为容器设置网络策略关于Service的发布,Weave做的也比较完整。首先,wRouter集成了DNS功能,能够动态地进行服务发现和负载均衡,另外,与libnetwork 的overlay driver类似,weave要求每个容器有两个网卡,一个就连在lb/ovs上处理L2 流量,另一个则连在docker0上处理Service流量,docker0后面仍然是iptables作NAT。同事,提供了一个容器监控和故障排查工具Weave Scope,可以方便的生成整个集群的拓扑并智能分组。优点:去中心化、故障自愈、加密通讯、支持组播缺点:
  • sleeve mode性能损耗巨大
  • full mesh模型限制了集群规模
  • Partial Connection在fastpath未实现
# Contiv思科开源的容器网络方案,是一个用于跨虚拟机、裸机、公有云或私有云的异构容器部署的开源容器网络架构,并与主流容器编排系统集成。Contiv最主要的优势是直接提供了多租户网络,并支持L2(VLAN),L3(BGP),Overlay(VXLAN)以及思科自家的ACI。主要由两部分组件组成:
  • Netmaster
- 对外提供REST API - 学习并分发路由到Netplugin - 管理集群资源(IP、VLAN、VXLAN ID等)
  • Netplugin
- 运行在集群中每个节点上 - 实现了CNI与CNM接口 - 通过REST方式与Netmaster通讯,监听事件,并做相应网络配置 - 数据平面使用OVS实现(插件架构,可替换,例如VPP、BPF)
11.png
优点:
  • 支持多种组网方式,集成现有SDN方案
  • 多租户网络混部在同一台主机上
  • 插件化的设计,可替换的数据平面
  • 即时生效的容器网络Policy/ACL/QoS规则
  • 基于OVS的高性能Load Balancer的支持
  • 清晰的设计,方便二次开发
缺点:
  • 功能丰富带来的副作用便是配置和使用比较复杂
  • 因为发展时间较短,社区和文档都不怎么成熟,也存在一些bug,稳定性有待商榷
  • CNI plugin对Mesos支持不友好(跟Cisco官方沟通后,对Mesos支持仍在POC阶段)
# OpenContrail是Juniper推出的开源网络虚拟化平台,其商业版本为Contrail。OpenContrail主要由控制器和vRouter组成:
  • 控制器提供虚拟网络的配置、控制和分析功能
  • vRouter提供分布式路由,负责虚拟路由器、虚拟网络的建立以及数据转发
vRouter支持三种模式:
  • Kernel vRouter:类似于ovs内核模块
  • DPDK vRouter:类似于ovs-dpdk
  • Netronome Agilio Solution (商业产品):支持DPDK, SR-IOV and Express Virtio (XVIO)
12.png
从上图可以看出,OpenContrail的架构是相当复杂的。相应的,其提供的feature基本覆盖了前所有提到的方案;甚至包括基于Cassandra后端的流量采样与分析平台;由于篇幅所限,这里不做详细介绍,相关内容可参考Arch Doc。计算机科学的先驱David Wheeler曾经说过——“Any problem in computer science can be solved with another level of indirection.”, SDN即是Network的indirection。容器网络解决方案多不胜数,我们在这里就不一一介绍了。但是我们可以看到,每种方案其实都是对network做了不同程度的indirection,但是不要忘了后面还有一句——“except of course for the problem of too many indirections”,所以大家在不同的方向上做出了取舍与权衡。正如前面所提到的,在斟酌某项技术的时候,我们需要考虑采纳成本、对供应商的依赖、社区的支持程度等等。我们正在如此权衡之后,并没选择上面的方案,而是选择了Calico,下面我会详细说明。# CalicoCalico 是一个纯三层的数据中心网络方案(不需要Overlay),并且与OpenStack、Mesos、Kubernetes、AWS、GCE等IaaS和容器平台都有良好的集成。Calico是一个专门做数据中心网络的开源项目。当业界都痴迷于Overlay的时候,Calico实现multi-host容器网络的思路确可以说是返璞归真——pure L3,pure L3是指容器间的组网都是通过IP来完成的。这是因为,Calico认为L3更为健壮,且对于网络人员更为熟悉,而L2网络由于控制平面太弱会导致太多问题,排错起来也更加困难。那么,如果能够利用好L3去设计数据中心的话就完全没有必要用L2。不过对于应用来说,L2无疑是更好的网络,尤其是容器网络对二层的需求则更是强烈。业界普遍给出的答案是L2 over L3,而Calico认为Overlay技术带来的开销(CPU、吞吐量)太大,如果能用L3去模拟L2是最好的,这样既能保证性能、又能让应用满意、还能给网络人员省事,看上去是件一举多得的事。用L3去模拟L2的关键就在于打破传统的Hierarchy L3概念,IP不再以前缀收敛,大家干脆都把32位的主机路由发布到网络上,那么Flat L3的网络对于应用来说即和L2一模一样。这个思路不简单,刨了L2存在必要性的老底儿,实际上如果不用考虑可扩展性、隔离性,IP地址和MAC地址标识endpoint的功能上确实是完全冗余的,即使考虑可扩展性,一个用L3技术形成的大二层和一个用L2技术形成的大二层并没有本质上的差距。而且,L3有成熟的、完善的、被普遍认可接受的控制平面,以及丰富的管理工具,运维起来要容易的多。于是,Calico给出了下面的设计:
13.png
Calico在每一个计算节点利用Linux Kernel实现了一个高效的vRouter来负责数据转发,而每个vRouter通过BGP协议负责把自己上运行的workload的路由信息向整个Calico网络内传播—,路由条目全是/32的v4或者/128的v6。小规模部署可以直接互联,大规模下可通过指定的BGP route reflector来完成。 这样保证最终所有的workload之间的数据流量都是通过IP路由的方式完成互联的。Calico节点组网可以直接利用数据中心的网络结构(无论是L2或者L3),不需要额外的NAT,隧道或者Overlay Network。
14.png
此外,Calico基于iptables还提供了丰富而灵活的网络Policy,保证通过各个节点上的ACLs来提供Workload的多租户隔离、安全组以及其他可达性限制等功能。另外,对CNM与CNI的支持使其可以方便适配绝大多数场景。这里有必要说明下,CNI和CNM并非是完全不可调和的两个模型。二者可以进行转化的,calico项目最初只支持CNI,后面才加入CNM的支持。从模型中来看,CNI中的container应与CNM的sandbox概念一致,CNI中的network与CNM中的network一致。在CNI中,CNM中的endpoint被隐含在了ADD/DELETE的操作中。CNI接口更加简洁,把更多的工作托管给了容器的管理者和网络的管理者。从这个角度来说,CNI的ADD/DELETE接口其实只是实现了docker network connectdocker network disconnect两个命令。类似的,kubernetes/contrib项目提供了一种从CNI向CNM转化的过程,这里就不做详细介绍了。我们详细看下Calico中的各个组件:
  • Felix:Calico Agent,跑在每台需要运行Workload的节点上,主要负责通过iptables来配置ACLs
  • etcd:分布式键值存储,主要负责网络元数据一致性,确保Calico网络状态的准确性
  • confd:根据etcd上状态信息,与本地模板,生成并更新BIRD配置
  • BGP Client(BIRD):主要负责容器的路由信息分发到当前Calico网络,确保Workload间的通信的有效性
  • BGP Route Reflector(BIRD):大规模部署时使用,摒弃所有节点互联的 mesh 模式,通过一个或者多个BGP Route Reflector来完成集中式的路由分发
这个架构,技术成熟、高性能、易维护,看起来是生产级别的容器网络环境最好的选择。但是,也有不如意的地方:
  • 没有了外面的封装,就谈不上VRF,多租户的话地址没法Overlap
  • L2和L3的概念模糊了,那么network级别的安全就难以实现,port级别的安全实现难是因为需要的规则都是1:1的,数量太多
上面并不是什么严重的问题。但是有一点,Calico控制平面的上述设计中,物理网络最好是L2 Fabric,这样vRouter间都是直接可达的,路由不需要把物理设备当做下一跳。如果是L3 Fabric,控制平面的问题就来了:物理设备如果要存32位的路由,路由表将变得巨大无比。因此,为了解决以上问题,Calico不得不采取了妥协,为了支持L3 Fabric,Calico推出了IPinIP的选项,用作cross-subnet下容器间通讯,但是有一定性能损耗。另一种方案是回退到L3 Hierarchy(calico目前支持),如果对容器迁移保持IP不变的需求不大,可以选择这种,这也是我们最后选择的方案。不过,对于使用L2 Fabric、没有多租户需求的企业来说,用calico上生产环境应该最理想选择。Calico最理想的部署方式是基于L2 Fabrics的,官方也有相应说明(Calico over an Ethernet interconnect fabric),这里就不做详细说明了。由于我们数据中心规模比较大,显然L2 Fabrics不是理想的选择。事实也是如此,我们多个数据中心组成的网络是以BGP为控制层面组成的L3 Fabrics。每个数据中心为一个AS。这里不讨论跨数据中心的问题,大家只需知道我们跨数据中心在L3上是互通的便可以。官方给出了3种基于L3 Fabrics的组网建议(详细介绍可点击进去查看):AS per Rack这种模型在每个ToR下加入了RR(Route Reflector),关于RR,前面有提到过,这里有必要解释一下:首先说下BGP的水平分割原则(这里只谈IBGP),从IBGP学习到的路由绝不对再传播给其它的IBGP邻居(可以传给EBGP邻居)。IBGP水平分割主要是为了防止在AS内部产生路由环路。所以,为了AS内路由正确收敛,需要所有节点组成full mesh结构(也就是两两之间建立邻居)。但是,这种架构在大型网络中显然行不通。另一种解决方案便是RR,一种C/S模型。在同AS内,其中一台设备作为RR,其他设备作为Client。Client与RR之间建立IBGP连接。路由反射器和它的客户机组成一个Cluster。这里不详细讨论RR的工作原理。显然,路由反射破坏了水平分割的原则,所以便要许多额外的配置来防止环路,这会给实际部署过程带来很多负担。另外,我们同一数据中心内运行的是IBGP,也就是都在同AS内。这使的配置改造更为复杂,而且,显然不符合AS per Rack。另外两种模型同样要求每个ToR在不同的AS,也面临上述问题。另外,如果不在ToR上做路由聚合,AS per Compute Server会造成Linux服务器上有全网的路由,庞大的路由表也会成为性能的瓶颈。经过与网络部门的认真研讨,我们最终选择了下面的部署模型:
15.png
  • 每个Server选择不同的AS号,且与数据中心AS不同,与ToR建立EBGP邻居
  • Server使用原有网关(默认路由),ToR不向Server宣告任何路由条目
  • Server本地聚合路由到28位,并宣告给ToR
  • 与网络部门制定一定算法(方便自动化),用Server的IP地址计算出AS号

可以看到,上述方案,几乎不用对数据中心现有网络架构做出改变;而且,也大大减少了Server与ToR上路由条目数。

实际部署Calico的Agent时,我们还遇到了一些问题:官方默认只提供基于Docker的部署方式,也就是之前提到的几个组件都部署在一个Docker容器中。calicoctl也是基于Docker容器做部署操作。但是,实际环境中,我们线上的Mesos集群有部分是只是用Mesos Containerizer的,也就是并没有Docker环境;而且,我们认为,Calico Agent加入对Docker daemon的依赖,考虑到稳定性,显然不是一个良好的选择。

所以,我们对Calico组件进行拆解,重新拼装,并去掉我们用不到IPv6模块;最终通过systemd在每台server上运行bird、confd、felix这三个模块,实现了去Docker化的部署(实际上对confd的模板也做了些改造,去掉了IPinIP的支持,并且适配的非Docker环境)。整个过程基于Ansible,实现了一键部署。

关于性能问题,虽然Calico在众多基于软件的容器网络解决方案里是性能最好的,但是也不是完全没有性能损耗。前面说过,Calico实现namespace内外通讯是通过linux内核的veth pair来实现的(就是之前提到的接入方式中的VSwitch/Bridge)。确实增加了一层overhead,但是好在veth pair的实现比较简单,性能损耗几乎可以忽略(无policy条件下)。我们实际测试中,对于echo server(小报文测试),请求延迟会增加0.02到0.04ms;对于bandwidth(大报文测试,万兆环境),很难看到差别。

到了这一步,你可能觉得我们大功告成,实则不然。其实我们还有很多事情可以做,也需要去做。Calico支持丰富的安全策略,但是在server上是用kernel的netfilter实现的(iptables),大量policy下的性能仍有待考察。

业内也有一些其他的实现思路,例如Google大力支持cilium方案,其policy的实现就用了BPF(Berkeley Packet Filter,最早在kernel 3.15中加入,4.8版本以后标为stable)。BPF的基本思路是把用作包处理的代码通过llvm编译成ir,然后插入到正在运行的kernel网络栈中,通过jit方式执行,大幅度提高了处理能力。这里不做详细介绍,相关信息可以看这里。cilium还加入了对XDP的支持(一种类似DPDK的技术,但是目前集成在kernel中),来加速网络栈的处理。这些都不失为未来改造calico的一个方向。

另外一个问题是,calico目前并没有对traffic shaping的支持。试想,当大量容器运行与同一物理机,其进出流量都共享物理网卡,如果不对容器流量进行限制,单个容器过分使用网络资源就会影响其他容器提供服务(磁盘IO也有同样问题,但是不在本文讨论范围)。Calico社区目前也在讨论这个问题,详情可见这个issue,目前还在API制定的阶段。

上述问题,底层实现目前可行选择是linux自带的tc(OVS同样用到了tc)。上层切入点却有两个选择,一是拓展Calico的API,在felix上实现应用tc规则的逻辑;另一种是在CNI plugin上hook,通过相应的调度系统,传参数进来,由plugin来应用tc规则。由于,calico社区已经在讨论这个问题,而且第二种方案实现起来成本也比较低。现阶段,我们只考虑方案二,也做了相应的POC。

实践过程中,由于veth pair两端的流量是相反的(ingress与egress),理论上可以在两端的egress上应用tc规则(tc只支持egress方向的shaping),来实现两个方向上的QoS。但是,我们还是遇到了一些问题,namespace内的虚拟网卡上的tc规则虽然可配置,但是并不生效。而且,这些规则对容器内应用是可见、可修改的,这样做也并不安全。所以,我们用到了ifb内核模块,把物理机上虚拟网卡的ingress流量变成egress,最终在在ifb网卡上应用tc规则,来实现容器egress方向的QoS。关于ifb,功能比较简单,大家可以看下kernel代码中相关的介绍:
/* drivers/net/ifb.c:

The purpose of this driver is to provide a device that allows
for sharing of resources:

1) qdiscs/policies that are per device as opposed to system wide.
ifb allows for a device which can be redirected to thus providing
an impression of sharing.

2) Allows for queueing incoming traffic for shaping instead of
dropping.

The original concept is based on what is known as the IMQ
driver initially written by Martin Devera, later rewritten
by Patrick McHardy and then maintained by Andre Correa.

You need the tc action mirror or redirect to feed this device
packets.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version
2 of the License, or (at your option) any later version.

Authors: Jamal Hadi Salim (2005)

*/

迫于篇幅限制,这次就先到这里吧,后续我会把一些详细实现拿出来给大家分享,欢迎共同交流。

看了上面这么多,有人可能会问,我们做了这么多工作,究竟是为了什么。回过头来看今天,我们理所当然的用着方便的跨数据中心环网、接入负载均衡、共享存储、对象存储,甚至到上层的云平台等等。正是因为有了这些,业务们拿出编译好的代码,快的不到几分钟就可以被线上的用户所使用。

这就是基础设施,这些是这座大楼的地基。正因为如此,基础设施的改造才异常困难。我们需要用合理的抽象来解决顽疾,更需要对上层建筑的兼容。正如我们在网络方面所做的工作,让容器和现有物理设备在三层上的互通,实现了网络上对业务的透明;同时又提供了良好的性能,消除了业务迁移到云平台上的顾虑;在提高资源利用率的混部环境下,同时提供可配置的策略,为服务质量提供了有效的保障。

作者:郝一昕,来自360搜索私有云团队

同程容器云平台网络方案演进

李颖杰 发表了文章 • 0 个评论 • 2650 次浏览 • 2017-07-26 22:53 • 来自相关话题

【编者的话】同程旅游PaaS平台是从2014年开始搭建的,到现在已经持续发展了三个年头。规模从原来的几百个容器到现在上万个容器。在容器调度上从原来的手动操作到现在的自动伸缩与扩容,在宿主机部署密度上从原来的十几个容器到现在上百个容器……我们的PaaS云平台在三 ...查看全部
【编者的话】同程旅游PaaS平台是从2014年开始搭建的,到现在已经持续发展了三个年头。规模从原来的几百个容器到现在上万个容器。在容器调度上从原来的手动操作到现在的自动伸缩与扩容,在宿主机部署密度上从原来的十几个容器到现在上百个容器……我们的PaaS云平台在三年间进行了3次大版本的迭代。本文主要介绍同程旅游PaaS云平台在持续集成和持续部署方面,基于Docker对网络方案的选型及应用,以及随着业务需求的增加而经历的网络方案变更过程。

【3 天烧脑式基于Docker的CI/CD实战训练营 | 北京站】本次培训围绕基于Docker的CI/CD实战展开,具体内容包括:持续集成与持续交付(CI/CD)概览;持续集成系统介绍;客户端与服务端的 CI/CD 实践;开发流程中引入 CI、CD;Gitlab 和 CI、CD 工具;Gitlab CI、Drone 的使用以及实践经验分享等。
#系统的初始形态
PaaS平台最初是基于Swarm搭建的,Swarm是Docker公司推出的一套容器调度平台。它的特点是简单易用,部署方便,学习成本低,因为它所有的命令和Docker命令基本上是一致的。容器有4种网络模式Bridge、Host、Container以及None ,开始我们使用的网络方案是Host模式,这种模式下,容器没有独立的IP网络栈,它共用了宿主机的IP地址。为了防止端口冲突,应用对外暴露服务的时候,需要指定端口,并且这个端口在同一宿主机上唯一(不然会冲突),然后再对接负载均衡器,这样就打通了整个网络链路。整个架构非常简洁,对于当时每天几十个容器以及无状态的应用,是能够完全满足需要的。

网络访问流程如下所示:
001.png

后来随着业务的发展,各种业务也慢慢的容器化,比如说Redis、Hadoop、Database、中间件等等。Host模式越来越显得力不从心,最严重的情况是很多应用没办法往上部署。举个例子来说,像Redis应用,它主要功能是做缓存,在高并发的情况下,一个Redis容器能把网络跑满,如果同一台宿主机上还有其它容器,这就会导致其它容器无法正常对外提供服务。像Database服务,为了做HA,需要容器拥有独立的网络,在迁移的时候保持IP不变。

但在Host模型下,容器网络依赖宿主机网络,容器对外访问需要通过宿主机IP加容器唯一端口,当容器发生迁移的时候,访问容器的方式(IP:Port)也要跟着改变,无法满足用户在平台外部需要直接使用IP访问的需求。为了解决此类问题,急需对容器进行网络隔离,让每个容器拥有独立IP。
#基于Public IP的网络订制
为了满足业务需求,开始研究如何使容器实例以Public IP方式供用户使用。首先什么是Public IP,Public IP就是让容器拥有一个独立的网络协议栈,有一个独立的IP地址。用户可以直接通过这个独立的IP地址访问应用,这样可以方便地解决端口冲突问题。有了这个目标以后,接下来就对目前现有的Docker网络方案进行调研评估。首先简单介绍下现有的容器网络方案,网上也看了很多对比,对于各方案的优缺点这里也做一个简单的总结。
##隧道方案
其典型的代表是:

* Weave,UDP广播,本机建立新的BR,通过PCAP互通。
* Open vSwitch(OVS),基于VxLAN和GRE协议,但是性能方面损失比较严重。
* Flannel,UDP广播,VxLan。

隧道方案在IaaS层的网络中应用也比较多,大家共识是随着节点规模的增长复杂度会提升,而且出了网络问题跟踪起来比较麻烦,大规模集群情况下这是需要考虑的一个点。另外,由于隧道方案性能损失比较严重,所以隧道方案暂时不考虑使用。
##路由方案
其比较典型的代表有:

* Calico,基于BGP协议的路由方案,支持很细致的ACL控制,对混合云亲和度比较高。
* Macvlan,从逻辑和Kernel层来看隔离性和性能最优的方案,基于二层隔离,所以需要二层路由器支持,大多数云服务商不支持,所以混合云上比较难以实现。

路由方案一般是从3层或者2层实现隔离和跨主机容器互通的,出了问题也很容易排查。

在这里我们说一下Calico。

首先它既支持Docker的CNM网络模型也支持像Kubernetes主推的CNI网络模型。既有着不俗的性能表现,提供了很好的隔离性,而且还有不错的ACL控制能力。通过将整个互联网的可扩展IP网络原则压缩到数据中心级别,Calico在每一个计算节点利用Linux Kernel实现了一个高效的vRouter来负责数据转发,而每个vRouter通过BGP协议负责把自己上运行的workload的路由信息像整个Calico网络内传播——小规模部署可以直接互联,大规模下可通过指定的BGP route reflector来完成。这样保证最终所有的workload之间的数据流量都是通过IP路由的方式完成互联的。

此外,Calico基于iptables还提供了丰富而灵活的网络Policy,保证通过各个节点上的ACLs来提供Workload的多租户隔离、安全组以及其他可达性限制等功能。

Calico 架构如下图所示:
002.jpg

对于Calico方案,我们也做了一些测试,首先它的网络转性能非常高,接近原生物理网卡的性能。但Calico依赖BGP协议,需要根据需要,频繁变更物理路由器的配置。对于传统物理网络有一定的侵入性,为了兼容以往的网络架构只能放弃。
##Vlan方案
其比较典型的代表有:

* Contiv netplugin
* Pipework

这里我们着重讲一下Contiv。

Contiv是Cisco开源出来的针对容器的基础架构,主要功能是提供基于Policy的网络和存储管理,是面向微服务的一种新基架,同时它又支持CNM以及CNI网络模型。Contiv能够和主流的容器编排系统整合,包括:Docker Swarm、Kubernetes、Mesos and Nomad。
003.png

如上图所示,Contiv比较“诱人”的一点就是,它的网络管理能力,既有L2(VLAN)、L3(BGP),又有 Overlay(VxLAN),而且还能对接Cisco自家的 SDN 产品 ACI。可以说有了它就可以无视底层的网络基础架构,向上层容器提供一致的虚拟网络了。

最主要的一点是,既满足了业务场景,又兼容了以往的网络架构。在转发性能上,它能达到物理网卡95%的性能。在高并发的场景下,OVS可能会消耗一部分CPU性能。对于这方面后期打算通过DPDK来做改善。另外,Contiv netmaster节点Down了以后不会造成网络中断,可以降低风险。还有一个优点是基于OVS可以灵活地做Policy/ACL/Qos监控等等,最终选择使用Contiv netplugin。

接下来我们说一下Contiv Netplugin在公司的落地情况。

首先根据实际网络访问描述下Contiv在PaaS平台整体部署结构:
004.jpg

目前我们通过Mesos + Marathon实现了容器的动态扩容以及动态负载,能够根据业务负载快速响应,做到自动伸缩,下面我们介绍一下网络模块Contiv。

Contiv主要包含3部分:

  1. netctl客户端主要用来发送命令到Contiv Netmaster;
  2. Netmaster服务端用来管理所有的Netplugin,以及提供IP地址分配IPMI功能;
  3. Netplugin插件跑在每个swarm node节点上,接收Netmaster指令控制OVS实现路由转发功能。

Contiv带来的方便是用户可以根据实例IP直接进行访问,可以借助ovs做很多策略,以及监控等,Contiv Netplugin特性主要有以下几点:

  1. 多租户网络混部在同一台主机上;
  2. 集成现有SDN方案;
  3. 能够和非容器环境兼容协作,不依赖物理网络具体细节;
  4. 即时生效的容器网络Policy/ACL/QoS规则。

可以说Contiv有很多丰富的特性,能够满足大部分业务场景,但有些场景目前Contiv还无法支持需要做二次开发,比如说应用容器IP固定,流量监控等。接下来讲一下我们是如何基于Contiv做IP持久化的。

大家都知道,Docker容器网络模型使用的是CNM(Container Network Model),这的底层是通过Libnetwork实现的,只要符合这个模型的网络接口就能被用于容器之间通信,而通信的过程和细节可以完全由网络接口来实现。
005.jpg


* Sandbox:对应一个容器中的网络环境,包括相应的网卡配置、路由表、DNS配置等。CNM很形象的将它表示为网络的『沙盒』,因为这样的网络环境是随着容器的创建而创建,又随着容器销毁而不复存在的。沙盒的实现可以是Linux Network Namespace、FreeBSD Jail之类的概念,并包含连接多个网络的Endpoint;
* Endpoint:实际上就是一个容器中的虚拟网卡,在容器中会显示为eth0、eth1依次类推。它可以是veth对,或者Open vSwitch的internal port。一个Endpoint只能属于一个沙盒;
* Network:指的是一个能够相互通信的容器网络,加入了同一个网络的容器直接可以直接通过对方的名字相互连接。它的实体本质上是主机上的虚拟网卡或网桥。

在CNM模型下,容器需要先通过IPMI获取IP,然后再创建Endpoint。我们的做法是,在启动容器之前,先调用Contiv rest API获取IP,Contiv Netmaster收到allocate ip的请求以后,将分配的IP保留起来,接下来在创建容器的时候指定所获取的IP,Netmaster收到创建Endpoint的请求将,保留的IP分配给容器,这样就做到了IP持久化。

创建容器的时序图如下:
006.png

#网络监控
在网络流量监控方面,我们通过使用OVS的sFlow来抓取宿主机上所有的网络流量,然后自开发了一个简单的sFlow Collecter,服务器收到sFlow的数据包进行解析,筛选出关键数据,丢到Redis(这里的Redis是做来做缓存的作用)。然后再通过ELK集群定时从Redis拉取数据,进行汇总分析。前端通过调用ELK的API,得到所需要的监控数据。

通过对网络进行改造,目前已经将Redis,大数据,DB等诸多复杂的业务成功的跑在了容器中,切切实实解决了业务的痛点。随着PaaS云平台的演进,由Swarm切换为Mesos + Marathon,后期也会根据需求对Contiv不断优化。

三年多的持续迭代,只为达到更高的要求。
>铭记初心,只为让更多人享受旅游的乐趣。
>
——王文建



原文链接:同程容器云平台网络方案演进&version=12020610&nettype=WIFI&fontScale=100&pass_ticket=FLwEXJsRPG3OGe5piakWkIHrzthK2rlKfn3ITRd1TSLnVhmID7y9j4z8eu7HFxt7)(作者:王文建)

DockOne微信分享(一三三):深入理解Kubernetes网络策略

尼古拉斯 发表了文章 • 0 个评论 • 4326 次浏览 • 2017-07-21 15:45 • 来自相关话题

【编者的话】当我们逐渐向着微服务、云原生迈进的时候,传统静态的、相对简单的网络安全策略开始显得吃力。 Kubernetes 的 Network Policy 特性正是来解决这个问题的。在刚刚出炉不久的1.7版本中,该特性也被扶正成为GA。让我们来一起看看 Ne ...查看全部
【编者的话】当我们逐渐向着微服务、云原生迈进的时候,传统静态的、相对简单的网络安全策略开始显得吃力。 Kubernetes 的 Network Policy 特性正是来解决这个问题的。在刚刚出炉不久的1.7版本中,该特性也被扶正成为GA。让我们来一起看看 Network Policy 是什么,能为我们做什么,以及是如何实现的。

【3 天烧脑式基于Docker的CI/CD实战训练营 | 北京站】本次培训围绕基于Docker的CI/CD实战展开,具体内容包括:持续集成与持续交付(CI/CD)概览;持续集成系统介绍;客户端与服务端的 CI/CD 实践;开发流程中引入 CI、CD;Gitlab 和 CI、CD 工具;Gitlab CI、Drone 的使用以及实践经验分享。

# CNI
Kubernetes 对网络做了较好的抽象。它将对网络的需求交给外部的组件完成,也就是 CNI driver。

Pod 的网络必须满足以下三个需求:

  1. 所有 Pod 之间无需 NAT 即可互通
  2. 主机和 Pod 之间无需 NAT 即可互通
  3. Pod 自省的 IP 地址和之外部看到该 Pod 的地址一致

CNI 对网络的实现做了详细的定义。CNI 的实现可以被分成三种:

  1. 3 层路由实现
  2. Overlay 实现
  3. 2 层交换实现

现在比较常用的 CNI 实现有:Flannel、Calico、Weave。 Flannel 通过 VXLan Overlay 来实现跨主机 Pod 网络, Calico 则完全通过 3 层路由来实现了跨主机的容器网络,Weave也是 Overlay 的实现。
# 什么是Network Policy
随着业务逻辑的复杂化,微服务的流行,越来越多的云服务平台需要大量模块之间的网络调用。

传统的单一外部防火墙,或依照应用分层的防火墙的做法渐渐无法满足需求。在一个大的集群里面,各模块,业务逻辑层,或者各个职能团队之间的网络策略的需求越来越强。

Kubernetes 在 1.3 引入了 Network Policy 这个功能来解决这个问题。这些 Policy 允许用户在同一个 Cluster 内实现网络的隔离。也就是在某些需要的 Pod 之间架起防火墙。可以简单的理解为各个微服务之间的动态防火墙。也有人把这叫做分布式防火墙。

并非所有的网络驱动都支持这个功能。比如大家比较熟悉的,比较流行的 Flannel 就还没有加入对 Network Policy 的支持。Calico 和 Weave 都各自实现了 NPC(network policy controller)。虽然 Flannel 不支持 Network Policy。但是,可以使用 Flannel 提供网络方案,同时使用 Calico 或者Weave 的 NPC 组件来共同完成。Canal 就提供了将 Flannel 和 Calico NPC 组合的方案。
# DEMO
下面我们就以Calico为基础,给大家做一个demo。

这里我已经搭好了一个 Kubernetes 的简单的集群:只有一个 master 和两个 minion。我们先来部署 Calico。这里要注意的是,由于我们要 demo 的是最新的 Kubernetes API,我们必须使用 Kubernetes 1.7 和 Calico 2.3,并且,Calico只能配置成 Kubernetes Datastore 的模式。在这种模式下,Calico 对网络状态的控制是通过 Kubernetes API 来完成的。另外还有一种模式是通过 etcd 集群。那种模式暂时还不支持最新的API。Kubernetes Datastore 这种方式有时也叫做KDD — Kubernetes datastore driver。

在进行 KDD 模式的 Calico 安装时要注意以下这么几点:

  1. IPAM 要使用 host-local
  2. 通过 controller manager 来分配 CIDR

细节请点击:http://docs.projectcalico.org/v2.3/getting-started/kubernetes/installation/hosted/kubernetes-datastore/

配置好 Calico之后,我们来看一个简单的 demo,实际操作一下 Network Policy:

为了简单起见,我们会直接使用 default namespace。如果你在一个现有的环境里面, 可以将以下的命令在一个独立的 namespace 里面运行。

创建 namespace 使用这个命令:
kubectl create ns np-demo

接下来运行一个简单的 nginx deployment 并用80端口暴露服务:
kubectl run nginx --replicas=2 --image=nginx
deployment "nginx" created
kubectl expose deploy nginx --port=80
service "nginx" exposed

现在我们还没有做任何的限制,所以 Kubernetes 缺省情况是所有 Pod 都是开放的。

我们来用一个 BusyBox 的 Pod 验证一下:
kubectl run busy --rm -ti --image busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget -q nginx -O - | head -4

上面的 Wget 命令是在 BusyBox 这个 Pod 里面执行的。`-q` 和 `-O -` 的组合会使这个命令在命令行输出 nginx 的缺省首页,这表明我们的验证是成功的。用 Ctl-D 退出容器。

接下来我们就要加入限制了。我们的做法是先限制对所有 Pod 的访问,然后建立白名单。 kubectl apply下面的 YAML 文件就可以限制所有访问:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: default-deny
spec:
podSelector:

注意我们提供了一个空的 podSelector。

我们再试着用之前的 BusyBox 的方式来访问一下:
kubectl run busy --rm -ti --image busybox /bin/sh
/ # wget -q --timeout=5 nginx -O -


这此我们设置了 5 秒的超时。因为访问被拒接,所以确实会超时:
wget: download timed out 

好,我们的第一个 Network Policy 已经生效了。然而,限制对所有 Pod 的访问显然是没有意义的。接下来我们建立一个白名单 . apply 下面的 YAML 文件:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: access-nginx
spec:
podSelector:
matchLabels:
run: nginx
ingress:
- from:
- podSelector:
matchLabels:
run: access

这个 Network Policy 的意思是:标签 run:access 选中的 Pod 可以访问标签 run:nginx 的 Pod,也就是我们 demo 开始时创建的 Nginx 的 Pod。这些 label 都是 kubectl run 命令自动 添加的。

接下来我们试试看能否成功地访问了:
kubectl run access --rm -ti --image busybox /bin/sh
wget -q nginx -O -

我们依然会看到熟悉的 Nginx 缺省首页。如果我们运行一个不符合上述 selector 的 Pod,就无法访问。这个留给有兴趣的同学自己回去验证。

如果你接触过 1.7 之前的 Network Policy 的话,你可能会发现这里的 API 有些不同。Kubernetes 1.7 已经将 Network Policy 正式提升到 GA。

正式的 API 和之前的 API 区别有:

  1. 不再使用 Annotation 来表达 default-deny 等这样的规则
  2. API version 从 extension/beta1 升级到了 networking.k8s.io/v1

# 实现
Calico 的实现是基于 iptables 的。在每个 chain 的顶端,Calico 都插入了一条定制的 chain,从而使得 packet 优先经过 Calico 定义的规则。我们在其中一个 minion 上面运行 iptables-save -c 就可以检查这些规则。可以看出 kube-proxy 和 Calico 都定义了大量的 iptable 规则。

这里细节很多,我们只需要关注这几点:

Calico 使用 conntrack 来优化。就是说,一旦一个连接已经建立,之后的packet都会直接被允许通过。比如:
-A cali-fw-cali7af3f94d3a1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 
-A cali-fw-cali7af3f94d3a1 -m conntrack --ctstate INVALID -j DROP

名为 cali-pi-xxxx 的规则是负责 Network Policy Ingress 的。我们可以想见,如果我们定义了很多 Policy,一个一个单独定义的规则会导致性能下降。这里 Calico 利用了 iptables 的 ipset 特性。使得一个 rule 可以通过 hash 表来匹配多种地址。
-A cali-pi-_G7e-YAvXRsfDoqGDf36 -m set --match-set cali4-s:2I5R46OBA_TBIUlpH0dCd_n src -j MARK --set-xmark 0x1000000/0x1000000 
-A cali-pi-_G7e-YAvXRsfDoqGDf36 -m mark --mark 0x1000000/0x1000000 -j RETURN

Weave 的实现也类似。底层还是使用了 iptables 和 netfilter。Weave 也创建了自定义的 chain。但由于一个是 Overlay 一个是路由,规则还是有些不同的。

另外一个细微的不同是,Weave使用了 -m state 而不是 -m conntrack。conntrack 是比较新的语法,但实际使用中功能是一样的。下面是几个 Weave 安装的 iptables rules 的例子:
FORWARD chain:
-o weave -j WEAVE-NPC
-o weave -j DROP
WEAVE_NPC chain:
-m state --state RELATED,ESTABLISHED -j ACCEPT
-m state --state NEW -j WEAVE-NPC-DEFAULT
-m state --state NEW -j WEAVE-NPC-INGRESS
-m set --match-set weave-v/q_G.;Q?uK]BuDs2 dst -j ACCEPT
-m set --match-set weave-k?Z;25^M}|1s7P3|H dst -j ACCEPGo

# Q&A
Q:Calico 和 Weave 从 Policy 处理性能来看,两者哪个更优?

A:两者在 iptables 层面上的实现原理是一样的。都用了-m
state 和 ipset 优化,性能差别不大。



Q:Calico 结合 Kubernetes 怎么实现多租户,比如网络隔离之类的?

A:可以考虑用 namespace 来隔离。没有 Network Policy 的情况下当然是互通的。但是 Kubernetes 的 Network Policy 支持 namespaceSelector,可以轻松搞定。



Q:Weave、Calico、Flannel 比较,适用场景和优缺点是什么,Flannel out了么?

A:各有各的市场 :-)。
Flannel 比较简单,资源消耗也会小些。Flannel 不能算 out 了。Cannel 的出现将 Flannel 和 Calico 整合了起来。



Q:NPC 必须用 iptables 实现吗?在某些情况下,Pod 出向流量并不会由主机协议栈,这样 iptables 就用不了,这种情况下 NPC 怎么实现呢 ?

A:Calico、Weave、Romana 的 NPC 都是通过 iptables 实现的。Pod
egress 不通过主机协议栈也会通过 netfilter。



以上内容根据2017年07月20日晚微信群分享内容整理。分享人梁文智:睿云智合研发顾问。 DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesa,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

3 天烧脑式容器存储网络训练营 | 深圳站

李颖杰 发表了文章 • 0 个评论 • 5321 次浏览 • 2017-06-21 18:29 • 来自相关话题

容器进入云计算AI时代,大规模容器集群即将进入千万家企业,业务特征十分复杂,如:容器数量庞大,需要满足快速部署灵活迁移,保证容器间跨物理机间的通信;保证业务、资源与物理位置无关,容器可以任意迁移;承载多种业务,需要保证业务间的安全隔离及访问控制。存储和网络的容 ...查看全部
容器进入云计算AI时代,大规模容器集群即将进入千万家企业,业务特征十分复杂,如:容器数量庞大,需要满足快速部署灵活迁移,保证容器间跨物理机间的通信;保证业务、资源与物理位置无关,容器可以任意迁移;承载多种业务,需要保证业务间的安全隔离及访问控制。存储和网络的容器化技术成为关键点,云计算从业者必须尽快在传统数据中心在使用云化后,着手解决大二层网络中的经典问题如MAC表项不足、ARP风暴、VLAN的4k上限等问题。目前业界主要有两种容器网络模型CNM和CNI来实现容器的网络方案,其中坑多知识点也多,尽快掌握这些技术方案成为不断完善自身业务能力的必须课程。

* 培训时间:7月20日——7月22日
* 课程难度:中高级
* 课程人数:20-40人
* 地点: 广东深圳市南山区粤兴三道9号华中科技大学产学研基地B座二楼T204教室
* 费用:4999元/人
* 报名链接:http://www.bagevent.com/event/649106
* 垂询电话:132 4116 6558
* 微信:liyingjiesa

培训对象:

* 容器开发和运维工程师
* 有志于从事容器技术的在职人员或者学生

技能要求:

* 对容器技术有一定了解
* 工作或者学习中有使用到容器技术

优惠信息:

* 团购3-4人每人优惠300
* 团购5人第6人免费

证书:

培训结束后,将提供『云计算容器(Docker)技术能力』中级测评考试,考试通过后,将获得『云计算容器(Docker)技术能力』中级能力测评认证证书,此认证是由科技部统一印制、统一编号、统一管理的国家级职业技能证书,是反映开源软件开发与应用技能水平的国家级职业资格认证。该证书在全国范围内通用有效,目前也是国内首个『容器技术』认证证书。

培训结束将统一为学员安排考试,考试时长1小时。

内容设置:

Docker文件系统基础

  • Docker分层文件系统
  • image的存储表现
  • Container的存储表现
Cgroup文件系统分析及实战
  • Cgroup及其subsystem介绍
  • Cgroup进行资源限制实战
Docker Plugin是如何设计的Docker storage driver分析及选型
  • AUFS
  • Btrfs
  • Device mapper
  • OverlayFS
  • OverlayFS2
  • ZFS
Docker Volume Plugin的工作原理常见Docker Volume Pulgin
  • Local volume plugin
  • Local Persist Plugin
  • Contiv Volume Plugin
  • Convoy plugin
  • Flocker plugin
  • GlusterFS plugin
  • rbd-docker-plugin
Kubernetes Storage机制
  • Volume类型介绍
  • PV/PVC原理及使用
  • Dynamic provisioning介绍及使用

Kubernetes管理有状态应用案例

经验分享

容器网络实现原理

* 容器实现原理
* Namespace介绍
* Cgroup介绍
* Cgroup手动实现容器网络之实战

容器网络模型: CNI vs CNM

* Docker网络模型CNM
* Kubernetes网络模型CNI

Docker网络实现CNM之Libnetwork

* Docker原生网络Bridge、Overflay、IPVLAN、MacVLAN
* Libnetwork plugin driver

容器网络插件

* CNM libnetwork插件的开发实现
* CNI插件的开发实现
* 常见的network driver

Calico原理及实现

* 什么是Calico
* Calico实现框架
* Calico典型部署

Contiv Netplugin原理及实现、性能

* Netplugin介绍
* Netplugin架构分析
* Netplugin源码实现
* 经验分享

开源企业级镜像仓库Harbor原理及实现

* Harbor介绍及主要特性
* Harbor架构分析
* Harbor高可用实现

讲师

* 王涛,原唯品会资深云计算工程师。西电研究生毕业后,一直从事云计算领域的开发和架构近六年。曾先后在华为和唯品会从事FusionSphere增值服务开发,以及IaaS、PaaS平台的架构开发。专注于研究Docker、Kubernetes、Mesos等容器技术,对Docker和Kubernetes源码有较深入研究和二次开发经验。

* 贺佰元,唯品会资深云计算开发工程师,北邮计算机硕士。研究生期间开始从事虚拟化和云计算的课题研究,曾先后任职于雅虎北研、中国移动,一直负责私有云和公有云的研发和架构工作,包括IaaS\PaaS平台、对象存储、容器云等的开发和架构设计,已有6年多的云计算领域实践经验。对虚拟化及OpenStack、Docker容器技术、Kubernetes和Mesos、分布式存储等有丰富的源码二次开发和架构选型经验。

报名链接:http://www.bagevent.com/event/649106

容器网络概述

edge_dawn 发表了文章 • 2 个评论 • 4207 次浏览 • 2017-02-12 22:51 • 来自相关话题

【编者的话】本文介绍容器网络,对容器网络的实践。 我在博客中经常讨论关于容器的事情,是因为我在工作中一直在关注着它们。 对于这些新奇容器的东西,最难理解的实际是关于容器的网络问题。 ...查看全部
【编者的话】本文介绍容器网络,对容器网络的实践。

我在博客中经常讨论关于容器的事情,是因为我在工作中一直在关注着它们。

对于这些新奇容器的东西,最难理解的实际是关于容器的网络问题。

虽然有很多不同的方式来解决容器网络互连问题,并且介绍这方面的文档也很多,但是有些用起来很糟糕。我对这些非常的困惑,因此我试图在这篇博客当中用非专业术语的方式来理清这个问题。
(我不喜欢夸夸其谈,但是我对于容器网络文档当前状态真的很沮丧。)

# 到底容器网络是什么呢?
当我们在容器中运行程序时,你将有两个主要的操作:

  • 在主机网络命名空间上运行该程序。这是正常的容器网络方式——如果你在`8282`端口上运行的程序,那么他将在本地计算机的`8282`端口上运行。这很正常。
  • 在容器自身的网络命名空间上运行该程序。
如果你将程序运行在其自身所在容器网络命名空间上(假如是在`9382`端口),那么在其他计算机上的其它程序将要通过网络连接来与此程序通信。起初我想:“这能复杂到哪去,将两个程序连接在一起很简单,不是吗?”就像说这个问题只有一种解决方式吗?而事实上对于容器中的程序网络互联问题有着成百上千的解决办法。接下来让我们去看看都有哪些方式。# 每个容器都有个IP如果你经常关注容器,你应该听说过Kubernetes 。Kubernetes 是一个可以使得你的容器可以自行决定其应该在哪一台机器上运行的系统(当然还有其它功能)。Kubernetes 的核心需求之一(当你刚刚开始用它的时候)就是每个容器要分配IP地址,于是在集群当中的其它应用程序可以通过容器对应的IP地址与之通信。这也就意味着在一台计算机上,你可能会拥有成百上千的容器以及对应的成百上千个IP地址(而不是一个IP地址和一堆端口)。当我第一次听到“每个容器都有一个IP地址”的概念,我很困惑和担心。这个怎么可能行得通?!我的计算机也仅仅只有一个IP地址!这个听起来像是难以理解的魔法一样。事实证明,幸运的是,与大多数计算机的东西类似,这是完全可以理解的。“每一个容器具有一个IP地址“这个问题正是我写这篇博客想要说清楚的问题。虽然有很多解决容器网络的方法,但是从现在开始这里只解释上述的这一种方式。而且我讲的是针对AWS来解决容器网络问题。如果你有自己的物理数据中心,那么将有更多的选择。# 我们的目标你有一台计算机(AWS instance),这个计算机有一个IP地址(比如172.9.9.9)。你想要你的容器也有一个IP地址(比如10.4.4.4)。我们将要学习在172.9.9.9这台计算机上如果将一个数据包发送给10.4.4.4。在AWS上是非常容易实现的—AWS上具有这项功能叫做 “VPC Route Tables”,你可以直接的告诉它“请为10.4.4.*发送数据包到172.9.9.9”,这样AWS将为你完成这件事。但是这个规则的限制是最多只能有50个,如果你想要的容器集群数目超过50个实例,那么你需要回到对容器网络困惑的原点。# 一些网络基础:IP地址、MAC地址、本地网络为了更好的理解怎样在一台物理机上拥有成百个IP地址,我们需要懂得一些计算机网络的基本概念。我将说一些你理所应当懂得的东西:* 在计算机网络当中,程序是通过发送数据包来进行互相交互通信的* 每一个数据包(大部分的)都有一个IP地址包含在内* 在Linux中,内核来完成大部分的网络协议工作 一点有关子网概念:子网10.4.4.0/24指的是“从10.4.4.0到10.4.4.255的每一个IP”。我有的时候会写成10.4.4.来代替。接下来我会尽全力去解释。## 网络数据包的组成一个网络数据包有很多个部分组成(经常被称为“layers”)。网络数据包的种类也有很多种,但是让我们只谈最常见的HTTP请求(像`GET /`)。组成部分有:1. 数据包将被发送到的MAC地址(“Layer 2”)2. 源IP地址和目标IP地址(“Layer 3”)3. 端口和其它的TCP/UDP信息(“Layer 4”)4. HTTP数据包的具体数据内容像`GET /` (“Layer 7”)##本地网络 VS 远端网络当你直接将一个数据包发给一台计算机(在同一个本地网络当中),过程如下。数据包被MAC地址标记,我的MAC地址是`3c:97:ae:44:b3:7f`;我通过运行`ifconfig`命令:
bork@kiwi~> ifconfigenp0s25   Link encap:Ethernet  HWaddr 3c:97:ae:44:b3:7f 
如果发送一个数据包给我,任意的一台本地计算机都可以将 `3c:97:ae:44:b3:7f`写在数据包上,然后将它发送到我这里。在AWS上,“本地网络”意味着“可用区域”。如果两个实例在同一个AWS的可用区域中,它们只需写上目标的MAC地址,然后数据包会被传送到止指定的目标计算机,无所谓数据包上写的哪个IP地址。OK,那么如果我的计算机和目标计算机不在同一个本地网络/可用区域中呢?然后呢?然后中间路由器就会查看数据包上的IP地址,然后将它送达指定的地址。路由器的工作原理还有很多内容,但是现在我们没有时间去探讨。幸运的是,在AWS上你通常没有办法去配置路由信息,因此也就无所谓它是如何工作的!发送一个数据包到可用区域外的实例,你需要将该实例所在的物理机的IP地址写在数据包上。否则数据包无法找到目标实例。如果你管理自己的数据中心,你可以很轻松的去设置自己的路由信息。因此,针对AWS我们可以学到的如下:
  • 如果你和目标主机在同一个可用区域里,你仅仅发送数据包携带随便任何IP地址都可以,只要MAC地址是正确的就可以。
  • 如果你和目标主机不不同的AZ里,那么发送数据包到那台计算机,你就必须要将目标实例所在的IP地址写在数据包上。
# 路由表你可能想问:“Julia,但是我如何控制要发送到的MAC地址的数据包呢。我从来没有做过这个,这非常令人困惑”。当你发送一个数据包到本地网络的一台计算机,地址为`172.23.2.1`,你的操作系统(我们希望你的操作系统是Linux)通过它维护的一个表来查看该IP所对应的MAC地址(这个表叫做ARP table)。将这个MAC地址放在数据包上,然后发送出去。那么,如果我有一个地址为`10.4.4.4`的容器的数据包,但是我想将它发送到`172.23.2.1`?这个其实也是非常简单的。你仅仅是在另外一个表上插入一个条目而已。这些都是表能做的事情。这是推荐你可以手动执行的命令:
sudo ip route add 10.4.4.0/24 via 172.23.1.1 dev eth0
`ip route add`是你所在的计算机(IP:172.23.1.1)的路由表当中加一个条目。这个路由表表示:“Linux,当你看到从`10.4.4.*`来的数据包,就将它发送到MAC地址为`172.23.2.1`的目标主机,可以吗?”# 我可以赋予容器IP地址是时候来庆祝我们的第一波胜利!我们现在知道所有的基本工具以及一种主要的方式来路由容器IP地址。步骤如下:1. 为你的每一个计算机选择一个不同的子网(比如`10.4.4.0/24`,也表示为`10.4.4.*`)。这个子网将会让你可以在一台机器上有256个容器。2. 在每一台计算机上,增加路由到其它的每一台计算机。于是你可以为`10.4.1.0/24`,`10.4.2.0/24`,`10.4.3.0/24`等等增加一个路由。3. 你已经完成了,数据包`10.4.4.4`现在将会路由到正确的计算机。这里还存在一个问题就是如果数据包到达目标计算机,它们将会做些什么呢,稍后我会介绍一下。于是我们用来处理容器网络的第一个工具就是路由表。# 如果两台计算机不在同一个可用区域呢?我们早些时候说过路由表这个方式仅仅作用在计算机直连网络中。那么如果两台计算机在远端网络(在不同的本地网络)我们就需要做一些更加复杂的事情了。我们想要发送数据包到一个容器,该容器IP地址为`10.4.4.4`,该容器所在的计算机地址为`172.9.9.9`。因为目标计算机是远端网络,那么我们不得不将IP地址`172.9.9.9`写入该数据包。那么现在问题来了,我们应该在哪里放`10.4.4.4`这个地址呢?## 封装所有的数据包都不会丢失,我们可以做一个叫“封装”的东西。这就是你拿到一个网络数据包,然后将它放在另外一个网络数据包里面。因此代替原有的数据包:
IP: 10.4.4.4TCP stuffHTTP stuff
我们将会发送如下数据包:
IP: 172.9.9.9(extra wrapper stuff)IP: 10.4.4.4TCP stuffHTTP stuff
这里至少有两种不同的方式来做封装:分别为“`ip-in-ip`”封装和 “`vxlan`”封装。Vxlan 封装是将你的整个数据包(包含MAC地址) 外包已成`UDP`数据。就像这样:
MAC address: 11:11:11:11:11:11IP: 172.9.9.9UDP port 8472 (the "vxlan port")MAC address: ab:cd:ef:12:34:56IP: 10.4.4.4TCP port 80HTTP stuff
ip-in-ip 封装仅仅是在就的IP头上打上一个额外的IP头。这就意味着,你不需要将目标MAC地址保持在你想发给的数据包上,但是我不确定你是否会关心这一点。
MAC:  11:11:11:11:11:11IP: 172.9.9.9IP: 10.4.4.4TCP stuffHTTP stuff
##如何设置封装像之前那样,你可以会想“我如何通过我的内核去对我的数据包做这样一个奇怪的封装“?这个证实确实并没有那么困难。基本上你所需要做的就是设置一个新的网络接口来配置封装。在我自己的电脑上,我可以这样做:参考这里
sudo ip tunnel add mytun mode ipip remote 172.9.9.9 local 10.4.4.4 ttl 255sudo ifconfig mytun 10.42.1.1
紧接着你要设置一个路由表,但是你要告诉Linux将你的数据包路由到你所配置的封装网络接口上。这里我们可以像这样做:
sudo route add -net 10.42.2.0/24 dev mytunsudo route list 
我给你这些命令是因为我认为你可以使用`create / inspect`这些 tunnels(`ip route list`,`ip tunnel`,`ifconfig`)——我已经遇到过一些错误,但是这是关于它是如何工作的。# 路由是如何分布的?我们已经谈论了将路由添加到路由表的过程(`10.4.4.4`被添加到`172.9.9.9`),但是我没有解释路由器具体如何从路由表当中获取信息的。理论上我们是希望他们能自动去识别。每一个容器网络的东西都是通过在每一个box里面运行一个守护进程来负责添加路由信息到路由表。这里有两种主要方式:1. 这些路由器在一个etcd集群当中,每一个程序通过etcd集群来确认配置哪一个路由2. 通过BGP路由协议来互相的通信,然后在每一个box里面用一个守护进程(`BIRD`)来监听`BGP`消息# 当数据包到达的你的box时会发生什么? 在正在运行Docker中,一个数据包从IP地址为`10.4.4.4`的容器过来,那么这个数据包最终到达你的程序是终态是什么样的呢?我现在来解释桥接网络。这个地方我有一点模糊,所以可能会出现错误。我现在的理解是这样的:
  • 在你的计算机上的每一个数据包都是通过一个实际的接口传送出去的(比如`eth0`)
  • Docker会为每一个单一的容器创建(虚拟)网络接口,这些接口具有IP地址类似`10.4.4.4`
  • 这些虚拟网络接口都被桥接到你的真实的物理网络接口上。这就是说这些数据包被复制(?)到这些网络接口所对应真实网卡上,然后在网络上被传送出去
这看起来非常重要,但是我还没有完全理解。# 最终:这些容器的网络如何工作的现在我们有已经介绍了容器网络的基本概念。## FlannelFlannel支持几种不同方式的网络:
  • vxlan(封装所有的数据包)
  • host-gw(仅仅是设置路由表,没有封装)
这个守护进程通过etcd集群来设置路由信息。##CalicoCalico支持两种不同的网络方式:
  • ip-in-ip:封装
  • “普通“模式(仅仅是设置路由表,没有封装)

这里守护进程是通过使用使用其它主机的`BGP`信息来设置路由表。Calico具有etcd集群但它并不用于分发路由。

Calico最令人兴奋的是可以不使用封装。如果你观察的够仔细你会发现Flannel也有一个选择是不需要使用封装。如果你是在AWS上,这两种你看不出哪个更好,它们有共同的限制:他们都是工作在具有相同的可用区域的实例之间。

这些关于容器网络的问题大部分都是设置路由以及tunnels等等一些事情,但是我觉得弄明白这些场景中到底做了什么是非常重要的,这样你才可以在出问题的时候调试和解决问题。

# 这是软件定义网络吗?
我不知道什么是软件定义网络。这有助于你做与众不同的网络,而且它都是软件,也许这就是所谓的软件定义网络吧?

# 总结
我已经陈述完了。希望这些能对您有一定作用,这个证明了容器网络并不是很烂,而且我们花费了一些时间在`ip`命令。`ifconfig`和`tcpdump`,这些可以帮助我们理解基本的Kubernetes部署。你不需要成为一个专家级的网络工程师。我的同事Doug帮助我理解了很多问题。

原文链接: A container networking overview(翻译:edge_dawn 审校: 田浩浩)

容器网络插件 Calico 与 Contiv Netplugin深入比较

yekaifeng 发表了文章 • 5 个评论 • 10868 次浏览 • 2016-12-21 09:20 • 来自相关话题

# 前言 业界有很多容器网络实现,为什么选它们俩进行比较?我的标准是一容器一 IP,高效转发,隔离, 已有网络基础设施的兼容程度高,丰富的特性。所以,Overlay,Flannel 之类的没考虑,Linux Bridge 虽然简单,功能上无法应对复 ...查看全部
# 前言
业界有很多容器网络实现,为什么选它们俩进行比较?我的标准是一容器一 IP,高效转发,隔离, 已有网络基础设施的兼容程度高,丰富的特性。所以,Overlay,Flannel 之类的没考虑,Linux Bridge 虽然简单,功能上无法应对复杂需求。筛选下来,只有它们比较值得去研究比较一下。当然,Docker 原生的 MAC VLAN 也不错,但我更倾向使用网络插件,因为可以独立升级。

接下来会简单介绍一下这两个网络插件,并从网络模型,实现机制,转发效率,软件成熟程度等方面进行比较。
# Calico简介
Calico 是一个多主机路由软件,还包含一个分布式防火墙。 Calico 是专门为容器和虚拟机尤其是 Docker 和 OpenStack 环境设计的。 Tigera 公司赞助,用 Python 语言开发。看起来, Calico 有望成为这样一种解决方案:用户能够在生产环境部署容器,同时保证严格的安全。

Calico 为每个容器或者虚拟机分配一个独立的 IP 地址,然后在每台物理主机上定义包含这些 IP 地址的 iptables 规则,实现了防火墙功能。 Calico 在每个物理节点上跑一个高效的vRouter, 由它对外广播本机各容器的路由信息。它基于BGP协议,不仅适用于小规模部署,在route reflector的帮助下,更能应用于大型DataCenter。包的转发用是的Linux内核的转发功能,高效而简单。只要编排框架支持为每个服务分配一个 IP 地址,就可以集成使用 Calico 。借数人云老肖一个图:
B79FB9E4-8AB0-42FD-B36E-AB36CFE33710.png

从本质上讲,Calico巧妙地把容器们的访问信息,包装在路由信息里,把L3作为容器访问的隔离方式,并使用 Linux 转发内核,很好地作出隔离与性能间的权衡。不象 Vxlan,Weave,为了隔离损失了性能, 也不象 host 模式,为了性能而损失了隔离性。在大型 IDC 的部署中,Calico 官方的部署模式建议为『AS Per Rack model』,即每个机架一个自治域,自治域间通过L2全连接或者L3树形连接。只要 IDC 接受内部跑 BGP,这种网络结构的扩展能力还是比较强的。
4F8739CA-9702-4EA5-B706-A24A2F3F44B5.png

二层核心交换部署

7B576B07-0D48-466F-B6A0-3421D8FA1E0A.png

三层核心交换部署
# Contiv Netplugin 简介
Contiv Netplugin 是来自思科的解决方案。编程语言为 Go。它基于 OpenvSwitch,以插件化的形式支持容器访问网络,支持 VLAN,Vxlan,多租户,主机访问控制策略等。作为思科整体支持容器基础设施contiv项目的网络部分,最大的亮点在于容器被赋予了 SDN 能力,实现对容器更细粒度,更丰富的访问控制功能。另外,对 Docker CNM 网络模型的支持,并内置了 IPAM 接口,不仅仅提供了一容器一 IP,而且容器的网络信息被记录的容器配置中,伴随着容器的整个生命周期,减低因为状态不同步造成网络信息丢失的风险。有别于 CNI,这种内聚化的设计有利于减少对第三方模块的依赖。随着项目的发展,除了 Docker,还提供了对 Kubernetes 以及 Mesos 的支持,即 CNI 接口。
9260E9B7-43C0-48B8-B5C7-CF8B952959D2.png


  • Netmaster 后台进程负责记录所有节点状态,保存网络信息,分配 IP 地址
  • Netplugin 后台进程作为每个宿主机上的 Agent 与 Docker 及 OVS 通信,处理来自 Docker 的请求,管理 OVS。Docker 方面接口为 remote driver,包括一系列 Docker 定义的 JSON-RPC(POST) 消息。OVS 方面接口为 remote ovsdb,也是 JSON-RPC 消息。以上消息都在 localhost 上处理。
  • 集群管理依赖 etcd/serf
580469BC-468C-49C8-B29E-8B88143AFE0A.png
# 分析比较
chart1.png
chart2.png
我们逐个点来聊聊:两者都支持 CNI 和 CNM 网络模型。Calico是先有CNI,再有CNM。Netplugin先有CNM,再支持CNI。因为Mesos的关系,Calico比较偏向CNI阵型。至于哪种网络模型更好,CNI最简单,为了通用性而对功能与配置方式有所牺牲。CNM也不复杂,设计更优雅, 容器网络相关信息持久在容器内部,与Docker的交互更紧密点。如果计划用Docker作为 Containerizer的话,建议用CNM。计划支持Docker外多种Containerizer的话,用CNI。Netplugin支持CNI的方式比较特别,有一个cniplugin binary脚本执行后并不是直接跑脚本配置网络,而是http去请求内部cniserver,这个跟兼容已有contiv model有关。从实现机制来看,Calico 的本质是基于BGP的三层交换,加上iptable的访问控制,从而支持各种profile rule。Netplugin 的话以OpenvSwitch为基石,不仅支持VLAN bridge二层协议, 也支持三层的BGP协议(vrouter)。访问控制基于OpenFlow Table,属于SDN应用于容器网络的典范。Calico运用了传统Linux已有的各种模块来搭建自己的产品,掌握起来起容易,而且文档方面比较丰富,前提是需要客户接受这种创新性的BGP协议使用方式。Netplugin更符合近传统的网络框架,引入 OVS的确会提高复杂度,然而它能提供更丰富的功能,特别有利于针对sdn的二次开发。况且业界已经有大规模使用OVS的样例,如JD,相信稳定性不是问题。另外,vxlan也为公有云的发展方向提供有力支持。VLAN技术已经被广泛使用的情况下,Netplugin + VLAN更能被IDC接受,跟已有基础设施兼容性会更好。也许更多的是考验OVS的稳定性以及性能吧。包转效率一直是大家比较网络解决方案的重要指标。测试使用了iperf 工具,在千兆网卡上跑,tcp,从测试结果来看。两者的包转发效率都在80%以上,Calico带宽更稳定,可以保持在95%以上。Calico随着宿主机容器增加(30个以上),转发效率会下降。
071238CA-1542-4FCE-BDE3-FA674F176A03.png
高级网络控制方面,Calico基于iptable可以做到对IP类型,协议,端口,方向,等控制,没有限流功能。基于OVS的Netplugin更丰富,能支持各种可编程网络功能,不仅有多种访问控制,包分级,而且能让容器加入不同的enpoint group,实现多级别的限速。另外,它还内置了面向服务的负载均衡功能。限速对于大型的应用集群来说,是一个必要的功能,能够帮助我们更好的规划使用网络资源,避免应用突发流量所造成的不必要资源竞争状态。只有Netplugin能满足这个需求, 用Calico的话只有自己基于TC开发了。在Calico测试中发现,每个容器会对应四条iptable规则,两条flex-from/to, 两条容器的CHAIN, 随着容器数量的增加(30个),过多的规则对包转发的效率存在比较大的影响。Calico没有多租户的概念,所有容器节点都要求可被路由,IP地址不能重复。 Netplugin基于VXLAN可创建互相隔离的网络空间,不需要担心IP网段overlap的问题,并具有为提供公有云服务的能力。Calico使用Python编程语言相对GO来说,不需要编译,语法没有那么严格,开发门槛更低一些,调度也更容易。 然而GO语言已经是大部分云计算软件的选择,内置并发支持,拥有不错的性能。各有优势吧。对于不同类型调度器的支持,calico 针对不同调度器创建相应project跟踪,如libnetwork-plugin,calico-kubernetes,calico-mesos,或者CNI接口统一用calico-cni。 而且这些插件都可以容器化的形式跑。针对三大调度系统,Netplugin也有三类内部插件, 对应对不同调度系统。比如k8splugin,它会用一个CNIServer来把CNI的请求转成Netplugin内部定义的一系列通用REST接口, 这样就可以用一套内部接口来满足多种调度类型。另外,可惜是这些服务都没有容器化,应该是考虑到跑systemd更稳定吧。代码数量级方面比较相近,30K LOC以下, 改动不大的情况下一到两人的团队就能维护。软件成熟度方面明显Calico更好,GitHub 500 +星,v1.6版本已发布。相比Netplugin 只有 170 +星, 开发版v0.1-11-30-2016.20-08-20.UTC, 正式版仍未出来。Calico有三大模块,包括felix(更新配置路由表,iptable),bird(BGP广播路由信息),conf(监听etcd,动态生成BIRD配置文件)。因为是容器化部署,软件升级很容易,只需要新起一个容器替换旧的就可以了。Netplugin也是三大模块Netplugin(接管容器网络服务,转发IP资源请求),netmaster(管理全局IP资源池), ovsdb(OVS 操作go 库,被Netplugin调用)。它也能独立升级,不需要重启Docker。所以模块数量,维护难度,耦合程度来说,两者比较接近。对于一定规模的idc来说,VLAN肯定是必备功能,BGP也不会陌生。网络基础部门接受VLAN一定没问题,而BGP话还是要看部门的技术熟悉程度和意愿。协议本身很简单,毕竟这是该协议的新玩法,如果跟公司已有的网络框架规划不符,推行起来有一定困难。扩展性方面VLAN应该算是驾轻就熟,但是要小心避免大二层网络规模过大出现的arp风暴与cam表爆仓的问题,要么用三层隔离,要么用arp proxy。BGP的扩展性比VLAN更好, 新AS可以横向自由扩展而流量无需要经过已有的子页交换机,而且该协议本来就是为了解决城域交换的问题,大规模支持不成问题。要考虑的地方是,旧有的子页交换机未必支持BGP, 有可能要换硬件。在IP池管理方面,Calico无IP分配中心,资源信息保存在etcd,由Agent分别去etcd拿。使用过程为预先创建subnet pool,起容器的时候分别为宿主机分配一个30个地址的段(/27),同一主机里的后继容器都在这个段拿。这是为了路由聚合,避免过多的路由信息,然而有可能造成地址资源的浪费。如果主机不超过30个容器,没被使用的IP并不能分给别的机器。如果主机超过30个容器,会新开一个段,地址浪费也许更严重。Netplugin用netmaster作为IP分配中心,资源信息也在etcd,Agent找netmaster要IP,IP从subnet里拿按顺序分配。理论上这样资源使用更充分,却存在潜在瓶颈, 要限制处理好并发拿IP的数量。# 总结:各有优势## Calico的优势
  • 网络拓扑直观易懂,平行式扩展,可扩展性强
  • 容器间网络三层隔离,无需要担心arp风暴
  • 基于iptable/linux kernel包转发效率高,损耗低
  • 更容易的编程语言(Python)
  • 社区活跃,正式版本较成熟
## Netplugin的优势
  • 较早支持CNM模型。与已有的网络基础设施兼容性较高,改造影响小。基于VLAN的平行扩展与现有网络结构地位对等
  • SDN能力,能够对容器的网络访问做更精细的控制
  • 多租户支持,具备未来向混合云/公有云迁移的潜力
  • 代码规模不大,逻辑结构清晰,并发好,VLAN在公司内部有开发部署运维实践经验,稳定性经过生产环境验证
  • 京东基于相同的技术栈(OVS + VLAN)已支持10w+ 容器的运行。

从纯技术角度来说,两种都是非常优秀的方案,它们综合技术指标都非常接近,各有千秋。相信两种方案都具备支持大规模容器网络的能力。公司需要根据部署现状,团队开发运维能力,以及未来的技术发展路线,来选取合适的解决方案吧。

Docker DevOps答疑:关于数据容器和网络

Leo_li 发表了文章 • 0 个评论 • 2847 次浏览 • 2016-07-17 10:51 • 来自相关话题

【编者的话】本文是Matt整理的DevOps vc见面会中一些互动问答,阅读本文Docker爱好者可以快速了解新特性和新趋势。 Matt Saunders是Contino的首席DevOps咨询顾问,也是资深工程师中的一员,他的从业背景 ...查看全部
【编者的话】本文是Matt整理的DevOps vc见面会中一些互动问答,阅读本文Docker爱好者可以快速了解新特性和新趋势。

Matt Saunders是Contino的首席DevOps咨询顾问,也是资深工程师中的一员,他的从业背景囊括了企业和创业公司。Matt同时也是London DevOps meet-up联合组织者——这是一个会员超过3000且每月组织见面会的组织。

关于数据容器,Docker对未来是如何考虑的,以及它将如何回应数据容器在数据复制系统中并不可取的诟病?

目前Docker建议将持久化数据保存在一个命名的volume中,当前和未来的创新都将围绕着如何使其更加稳定和容错而展开。我相信大多数针对数据容器的批评都集中在他们不能在主机之间即时迁移,这也就意味着通过Docker创建的数据容器所存储的数据只存在于一台主机上。从Docker 1.9开始,诸如FlockerConvoyGlusterFS等插件已经允许通过集群文件存储来可靠地托管Docker volumes。

对于Docker的网络模型目前在开发中有什么创新点?就是哪些在所有改进需求中有时候会被单独提出来。

Docker 1.12对此作了很多的改进,包括通过大量的工作把整个应用程序栈与专用的网络以无缝的方式结合在一起。Docker网络模块也从插件中受益,开启了使用第三方网络插件的可能性。Docker 1.12也提升了网络安全性;允许构建横跨多个Docker主机的网络栈从而为使用软件定义网络的应用程序提供隔离性。在Docker 1.12中负载均衡的性能显著改善;这实际上是即将发布的新版中的一个特色。

随着近期推出的Docer安全扫描,你是否已经发现了一些对企业云计算用户的影响?Docker在安全方面的立场是什么?

企业用户中最大的关注点之一恰恰是Docker最大优势的另一面。在构建的过程中用一个容器镜像来锁定所有应用程序的依赖库实现了在不同环境中按需移动容器的灵活性,但是同时也就付出了透明性方面的代价。

Docker安全扫描(Docker Security Sacnning)通过在Docker Hub上对容器镜像的内容进行评估来应对已知的漏洞从而规避这个问题,而且在Docker Hub上使用私有repos的企业云用户也从这项技术中获益。我们期待这个功能未来也可以用于Docker数据中心(Docker Data Centre)用户——由于多数对安全有顾虑的企业用户在他们的私有云中运行Docker Trusted Registry而不需要使用Docker Hub。

对于Docker而言安全的优先级是第一位的——过去一年所发布的版本或者去年主导的Docker Content Trust的发布都表明在这个方面已经取得了令人瞩目的改进。这使得基于Docker的装机量与现有的安全策略能够以一种无缝的方式实现更好地配合。

同其他新兴技术一样,IT团队是如何看待其投资回报率的?

容器技术的投资回报可以用多种方式进行评测——最容易的一种是能够消除或者最小化虚拟化层并停止在太多备用容量上的浪费所带来的收益。Docker的其它收益可以评测软件交付速度的提升,因为容器使得代码能够更快地测试和投入生产,从而提升了敏捷性和软件交付的速度。

您是否注意到哪些行业更愿意拥抱容器?

容器技术对于Web应用运行良好,所以在线商务运营引领着前进的方向。但这不意味着把其它行业排除在外——任何对高效交付软件感兴趣的人都可以拥抱容器。

公司在使用容器的初期最常犯的错误是什么?

很多公司经常试图在容器中再应用它们的虚拟化手段,它虽然也应用了容器技术的一些优势但是并不能充分发挥所有的优势。这将导致容器技术太过臃肿而且会错过大多数技术优势。

Docker在什么时候不是正确的选择?

目前Linux之外的栈对Docker的支持都还很有限。

Windows对Docker的支持还处于早期阶段但是今年就应该会有重大的进展。此外,对于不愿意拥抱由这项革命性技术而带来的变革的组织而言,Docker并不是一个正确的选择——构建软件容器的模型与人们以前所习惯使用的有着巨大的不同而这也是组织所要面对的巨大挑战。

原文链接:Docker DevOps on data containers and networking(翻译:李毅 审校:田浩浩

Docker网络和服务发现

binsummer 发表了文章 • 0 个评论 • 17966 次浏览 • 2016-07-10 21:12 • 来自相关话题

【编者的话】 本文是《Docker网络和服务发现》一书的全文,作者是Michael Hausenblas。本文介绍了Docker世界中的网络和服务发现的工作原理,并提供了一系列解决方案。 # 前言 当你开始使用Docker构建应用的时候 ...查看全部
【编者的话】 本文是《Docker网络和服务发现》一书的全文,作者是Michael Hausenblas。本文介绍了Docker世界中的网络和服务发现的工作原理,并提供了一系列解决方案。
# 前言
当你开始使用Docker构建应用的时候,对于Docker的能力和它带来的机会,你会感到很兴奋。它可以同时在开发环境和生产环境中运行,只需要将一切打包进一个Docker镜像中,然后通过Docker Hub分发镜像,这是很直接了当的。你会发现以下过程很令人满意:你可以快速地将现有的应用(如Python应用)移植到Docker中,将该容器与另一个数据库容器(如PostgreSQL)连接。但是,你不会想手动启动一个Docker容器,也不会想自己去实现一个系统来监控运行中的容器和重启未运行的容器。

此时,你会意识到两个相互关联的挑战:网络和服务发现。不幸的是,说得好听一点,这两个领域都是新兴的课题;说得难听一点,在这两个领域里,还有很多不确定的内容,也缺乏最佳实践。幸运的是,在海量的博客和文章中,分散着各种各样的“秘方”。
# 本书
因此,我对自己说:如果有人写本书,可以介绍这些主题,并提供一些基本的指导,对于每项技术给读者指引正确的方向,那该多好啊。

那个“人”注定是我, 在本书里,我将介绍Docker容器网络和服务发现领域中的挑战和现有的解决方案。 我想让大家了解以下三点:

* 服务发现和容器编排就像一枚硬币的两面。
* 对于Docker网络,如果没有正确的理解和完善的策略,那就糟糕了。
* 网络和服务发现领域还很年轻。你会发现,刚开始你还在学习一套技术,过一段时间,就会“换挡”,尝试另一套技术。不要紧张,这是很正常的。在我看来,在形成标准和市场稳定之前,还会有两三年时间。

编排和调度

严格来讲,编排是比调度更广泛的一个概念:编排包含了调度,同时也包含其他内容。例如,容器的故障重启(可能是由于容器本身不健康,也可能是宿主机出了故障)。而调度仅仅是指,决定哪个容器运行在哪个宿主机上的过程。在本书中,我会无差别地使用这两个术语。

我这么做的原因是:第一,在IETF RFC和NIST标准中并没有对这两个概念的官方定义;第二,在不同公司的市场宣传中,往往会故意混淆它们,因此我希望你能对此有所准备。然而,Joe Beda(前Google和Kubernetes的策划者)对于该问题发表了一篇相当不错的文章: What Makes a Container Cluster?,你可以更深入地了解一下。
#你
我希望,本书的读者是:

* 开发者们,正在使用Docker;
* 网络Ops,正在为热情的开发者所带来的冲击做准备;
* (企业)软件架构师,正在将现有负载迁移到Docker,或者使用Docker开始一项新项目;
* 最后但同样重要的是,我相信,分布式应用的开发者、SRE和后端工程师们也能从其中获取一些价值。

需要注意的是,本书不是一本动手实践(hands-on)的书籍(除了第二章的Docker网络部分),更像是一本指导。当你计划实施一个基于Docker的部署时,你可以参考本书来做出一个明智合理的决定。阅读本书的另一种方式是,添加大量注释和书签(a heavily annotated bookmark collection)。
#我
我在一个很酷的创业公司Mesosphere, Inc.(Apache Mesos背后的商业公司)工作,主要的工作内容是帮助DevOps充分利用Mesos。虽然我有偏见地认为Mesos是目前进行大规模集群调度的最佳选择,但是我仍然会尽我最大的努力来确保这种偏爱不会影响对于各项技术的介绍。
# 致谢
向Mesosphere同事们James DeFelice和Stefan Schimanski(来自Kubernetes组)致谢,他们很耐心地回答了我关于Kubernetes网络的问题。向我的Mesosphere同事们Sebastien Pahl和Tim Fall(原Docker同事)致谢,我非常感谢你们关于Docker网络的建议。也很感谢另一个Mesos同事Mohit Soni,在百忙之中他提供了很多反馈。

进一步地, 我要感谢Medallia的Thorvald Natvig,他的讲话Velocity NYC 2015促使我深入地思考了网络这一领域,他也很友善地和我讨论Medallia生产环境中使用Docker/Mesos/Aurora的经验和教训。

很感谢Adrian Mouat(容器解决方案)和Diogo Mónica(Docker, Inc.)通过Twitter回答问题,尤其是在普通人睡觉的时候,花了数小时回答了我的问题。

我也很感谢来自Chris Swan的反馈,他提供了明确可操作的评论。通过解决他的问题,我相信本书变得更有针对性了。

在本书的写作过程中,来自Google的Mandy Waite提供了很多有用的反馈,特别是Kubernetes,我很感谢这一点。我也很感激Tim Hockin(Google)的支持,他帮助我澄清了很多关于Docker网络特性和Kubernetes的疑惑。

感谢Matthias Bauer对于本书的草稿提出的宝贵意见。

非常感谢我的O’Reilly编辑Brian Anderson。从我们讨论草稿开始,你一直都非常支持我,很高效,也很有趣。非常荣幸和您一起工作。

最后重要的一点是,对于我的家庭要致以最深刻的谢意:我的“阳光”Saphira,我的“运动女孩”Ranya,我的儿子和“Minecraft大师”Iannis,以及一直支持我的妻子Anneliese。如果没有你们的支持,我是不可能完成本书的。
# 动机
2012年2月,Randy Bias发表了一篇谈话,名为开放和可扩展云架构,提出了pets和cattle两种文化基因的碰撞。

* 基础设施的pets方法(pets approach to infrastructure),每台机器或虚拟机被当做一个个体,会分配一个名字,各个应用被静态地部署在各个机器上。例如: `db-prod-2`是生产环境中的一台数据库服务器。应用是手动部署的,当一台机器出故障时,你需要修复它,并把应用手动部署到另一台机器上。在非云原生应用时代(non-cloud-native era),这种方法通常占据着主导地位。
* 基础设施的cattle方法(cattle approach to infrastructure),所有的机器都是无名的、完全类似的(modulo hardware upgrades),它们只有编号,没有名字。应用是自动部署到机器群中的任意一台。当其中一台机器发生故障时,你不需要立刻处理它,只要在方便的时候更换故障机器(或者它的一部分,如一块损坏的HDD)。

尽管这些文化基因(meme)最初是针对虚拟机的,但是我们这里会将cattle方法套用在容器的基础架构上。
# Go Cattle!
在基础设施中,使用cattle方法的一大好处就是,你可以在商用硬件上进行水平扩展。

这样一来,你就可以有很大的弹性来实施混合云。只要你愿意,一部分可以部署在premise环境中,一部分部署在公有云上,也可以部署在不同的云提供商的IaaS架构上。

更重要的是,从一名运维者的角度上来看,cattle方法可以保证一个相当好的睡眠质量。因为你再也不会像pets方法中那样,凌晨3点被叫起来去更换一块坏了的HDD或者将应用重新部署到另一台服务器上。

然而,cattle方法也带来了一些挑战,主要包括以下两个方面:
##社交挑战(Social challenges)
我敢说,大部分挑战会来自于社交方面:我应该怎么说服我的老板呢?我怎么让CTO买我的账呢?我的同事们会反对这种新的做法吗?这是不是意味着我们只需要更少的人来维护基础架构?现在,对于这个问题,我还不能提供一个完整有效的解决方案。你可以买一本《凤凰项目》,从中你可能可以找到答案。
##技术挑战(Technical challenges)
这个方面主要包括:机器的准备机制(provisioning mechanism)如何选择(例如,使用Ansible来部署Mesos Agents);在容器之间、在容器和外界之间如何通信;如何保证容器的自动部署并能被寻址(consequently findable)。
# Docker网络和服务发现栈
我们在图1-1中描述了整个技术栈,包括以下内容:
##底层的网络层(The low-level networking layer)
这一层包括一系列网络工具: `iptables`、路由、IPVLAN和Linux命名空间。你通常不需要知道其中的细节,除非你是在网络组,但是你需要意识到这一点。关于这一课题的更多信息,可以参考Docker网络基础
##Docker网络层
这一层封装了底层的网络层,提供各种抽象模型,例如单主机桥网络模式、多主机的每个容器一个IP地址的解决方案。在第2章和第3章中有相关介绍。
##服务发现层/容器编排层
这里,我们将容器调度定义为通过底层提供的基本原语(primitives)决定将容器放在哪里。第4章提到了服务发现的必要背景,第5章从容器编排的角度讲解了网络和服务发现。

软件定义网络(SDN)

SDN真的是一个市场术语(umbrella term或者marketing term),它可以提供VM带来的网络优势,就像裸机服务器(bare-metal servers)一样。网络管理团队会变得更加敏捷,对商业需求的变化反应更加迅速。另一种看法是:SDN是一种使用软件来定义网络的配置方式,可能是通过API构建、通过NFV构建,或者由Docker网络来提供SDN。

如果你是一名开发者或架构师,我建议你看一下Cisco对于该课题的观点和SDxCentral的文章What’s Software-Defined Networking (SDN)?
01.png

图 1-1

如果你在网络运维组的话,你可能已经准备好进入下一章了。然而,如果你是架构师或者开发者的话,对于网络知识可能有点生疏了,我建议你读一下Linux Network Administrators Guide来复习一下相关知识。
#我需要All-In吗?
在各种会议和用户组中,我经常遇到一些人,他们对于容器领域的机会非常兴奋,同时他们也担心在从容器中受益之前需要投入多少。以下的表格是对于我了解的各种部署的非正式的总结(按照阶段不同排序)。
02.png

需要注意的是,不是所有的例子都使用Docker容器(显而易见的是,Google并不使用Docker容器)。其中,某些正在着手使用Docker,例如,在ad-hoc阶段;某些正在转向full-down阶段,例如Uber,请看ContainerSched 2015 London中的演讲。最后重要的一点是,这些阶段与部署的大小是没有必然关系的。例如,Gutefrage.de只有六台裸机服务器,仍然使用Apache Mesos来管理它们。

在继续之前,还有最后一点:到目前为止,你可能已经注意到了我们处理的是分布式系统。由于我们总是希望将容器部署到一个集群中,我强烈建议你读一下分布式计算的谬论,以防你不熟悉这一主题。

现在言归正传,让我们进入Docker网络这一主题。
# Docker网络基础
在我们进入网络细节之前,我们先来看一看在单主机上发生了什么。Docker容器需要运行在一台宿主机上,可以是一台物理机(on-premise数据中心中的裸机服务器),也可以是on-prem或云上的一台虚拟机。就像图2-1中描述的那样,宿主机上运行了Docker的daemon进程和客户端,一方面可以与Docker registry交互,另一方面可以启动、关闭和审查容器。
03.png

图 2-1
宿主机和容器的关系是1:N,这以为这一台宿主机上可以运行多个容器。例如,从Facebook的报告来看,取决于机器的能力,每台宿主机上平均可以运行10到40个容器。另一个数据是:在Mesosphere,我们发现,在裸机服务器上的各种负载测试中,每台宿主机上不超过250个容器是可能的。

无论你是在单主机上进行部署,还是在集群上部署,你总得和网络打交道:

* 对于大多数单主机部署来说,问题归结于是使用共享卷进行数据交换,还是使用网络(基于HTTP或者其他的)进行数据交换。尽管Docker数据卷很容易使用,它也引入了紧耦合,这意味着很难将单主机部署转化为多主机部署。自然地,共享卷的优势是速度。
* 在多主机部署中,你需要考虑两个方面:单主机上的容器之间如何通信和多主机之间的通信路径是怎样的。性能考量和安全方面都有可能影响你的设计决定。多主机部署通常是很有必要的,原因是单主机的能力有限(请看前面关于宿主机上容器的平均数量和最大数量的讨论),也可能是因为需要部署分布式系统,例如Apache Spark、HDFS和Cassandra。

分布式系统和数据本地化(Distributed Systems and Data Locality)

使用分布式系统(计算或存储)的基本想法是想从并行处理中获利,通常伴随着数据本地化。数据本地化,我指的是将代码转移到数据所在地的原则,而不是传统的、其他的方式。考虑下以下的场景:如果你的数据集是TB级的,而代码是MB级的,那么在集群中移动代码比传输TB级数据更高效。除了可以并行处理数据之外,分布式系统还可以提供容错性,因为系统中的一部分可以相对独立地工作。

本章主要讨论单主机中的网络,在第3章中,我们将介绍多主机场景。

简单地说,Docker网络是原生的容器SDN解决方案。总而言之,Docker网络有四种模式:桥模式,主机模式,容器模式和无网络模式。我们会详细地讨论单主机上的各种网络模式,在本章的最后,我们还会讨论一些常规主题,比如安全。
# bridge模式网络
在该模式(见图2-2)中,Docker守护进程创建了一个虚拟以太网桥`docker0`,附加在其上的任何网卡之间都能自动转发数据包。默认情况下,守护进程会创建一对对等接口,将其中一个接口设置为容器的`eth0`接口,另一个接口放置在宿主机的命名空间中,从而将宿主机上的所有容器都连接到这个内部网络上。同时,守护进程还会从网桥的私有地址空间中分配一个IP地址和子网给该容器。

例2-1
$ docker run -d -P --net=bridge nginx:1.9.1
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED
STATUS PORTS NAMES
17d447b7425d nginx:1.9.1 nginx -g 19 seconds ago
Up 18 seconds 0.0.0.0:49153->443/tcp,
0.0.0.0:49154->80/tcp trusting_feynman


注意:
因为bridge模式是Docker的默认设置,所以你也可以使用`docker run -d -P nginx:1.9.1`。如果你没有使用`-P`(发布该容器暴露的所有端口)或者`-p host_port:container_port`(发布某个特定端口),IP数据包就不能从宿主机之外路由到容器中。



04.png

图 2-2

小技巧:
在生产环境中,我建议使用Docker的host模式(将会在下一小节Host模式网路中讨论),并辅以第3章中的某个SDN解决方案。进一步地,为了控制容器间的网络通信,你可以使用flags参数:`--iptables`和`-icc`。

#Host模式网络
该模式将禁用Docker容器的网络隔离。因为容器共享了宿主机的网络命名空间,直接暴露在公共网络中。因此,你需要通过端口映射(port mapping)来进行协调。

例2-2
$ docker run -d --net=host ubuntu:14.04 tail -f /dev/null
$ ip addr | grep -A 2 eth0:
2: eth0: mtu 9001 qdisc mq state UP group default qlen 1000
link/ether 06:58:2b:07:d5:f3 brd ff:ff:ff:ff:ff:ff
inet [b]10.0.7.197[/b]/22 brd 10.0.7.255 scope global dynamic eth0[/quote]

$ docker ps
CONTAINER ID IMAGE COMMAND CREATED
STATUS PORTS NAMES
b44d7d5d3903 ubuntu:14.04 tail -f 2 seconds ago
Up 2 seconds jovial_blackwell
$ docker exec -it b44d7d5d3903 ip addr
2: eth0: mtu 9001 qdisc mq state UP group default qlen 1000
link/ether 06:58:2b:07:d5:f3 brd ff:ff:ff:ff:ff:ff
inet [b]10.0.7.197[/b]/22 brd 10.0.7.255 scope global dynamic eth0

我们可以从例2-2中看到:容器和宿主机具有相同的IP地址`10.0.7.197`。

在图2-3中,我们可以看到:当使用host模式网络时,容器实际上继承了宿主机的IP地址。该模式比bridge模式更快(因为没有路由开销),但是它将容器直接暴露在公共网络中,是有安全隐患的。
05.png

图 2-3
#Container模式网络
该模式会重用另一个容器的网络命名空间。通常来说,当你想要自定义网络栈时,该模式是很有用的。实际上,该模式也是Kubernetes使用的网络模式,你可以在这里了解更多内容。

例2-3
$ docker run -d -P --net=bridge nginx:1.9.1
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS
PORTS NAMES
eb19088be8a0 nginx:1.9.1 nginx -g 3 minutes ago Up 3 minutes
0.0.0.0:32769->80/tcp,
0.0.0.0:32768->443/tcp admiring_engelbart
$ docker exec -it admiring_engelbart ip addr
8: eth0@if9: mtu 9001 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
inet [b]172.17.0.3[/b]/16 scope global eth0

$ docker run -it --net=container:admiring_engelbart ubuntu:14.04 ip addr
...
8: eth0@if9: mtu 9001 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
inet [b]172.17.0.3[/b]/16 scope global eth0

结果(例2-3)显示:第二个容器使用了`--net=container`参数,因此和第一个容器`admiring_engelbart`具有相同的IP地址`172.17.0.3`。
#None模式网络
该模式将容器放置在它自己的网络栈中,但是并不进行任何配置。实际上,该模式关闭了容器的网络功能,在以下两种情况下是有用的:容器并不需要网络(例如只需要写磁盘卷的批处理任务);你希望自定义网络,在第3章中有很多选项使用了该模式。

例2-4
$ docker run -d -P --net=none nginx:1.9.1
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED
STATUS PORTS NAMES
d8c26d68037c nginx:1.9.1 nginx -g 2 minutes ago
Up 2 minutes grave_perlman
$ docker inspect d8c26d68037c | grep IPAddress
"IPAddress": "",
"SecondaryIPAddresses": null,

在例2-4中可以看到,恰如我们所料,网络没有任何配置。

你可以在Docker官方文档中读到更多关于Docker网络的配置。

[quote] 注意:
本书中的所有Docker命令都是在CoreOS环境中执行的,Docker客户端和服务端的版本都是1.7.1。



# 更多话题
在本章中,我们了解了Docker单主机网络的四种基本模式。现在我们讨论下你应该了解的其他主题(这与多主机部署也是相关的):
##分配IP地址
频繁大量的创建和销毁容器时,手动分配IP地址是不能接受的。bridge模式可以在一定程度上解决这个问题。为了防止本地网络上的ARP冲突,Docker Daemon会根据分配的IP地址生成一个随机地MAC地址。在下一章中,我们会再次讨论分配地址的挑战。
##分配端口
你会发现有两大阵营:固定端口分配(fixed-port-allocation)和动态端口分配(dynamically-port-allocation)。每个服务或者应用可以有各自的分配方法,也可以是作为全局的策略,但是你必须做出自己的判断和决定。请记住,bridge模式中,Docker会自动分配UDP或TCP端口,并使其可路由。
##网络安全
Docker可以开启容器间通信(意味着默认配置`--icc=true`),也就是说,宿主机上的所有容器可以不受任何限制地相互通信,这可能导致拒绝服务攻击。进一步地,Docker可以通过`--ip_forward`和`--iptables`两个选项控制容器间、容器和外部世界的通信。你应该了解这些选项的默认值,并让网络组根据公司策略设置Docker进程。可以读一下StackEngine的Boyd Hemphill写的文章Docker security analysis

另一个网络安全方面是线上加密(on-the-wire encryption),通常是指RFC 5246中定义的TLS/SSL。注意,在写本书时,这一方面还很少被讨论,实际上,只有两个系统(下一章会详细讨论)提供了这个特性:Weave使用NACl,OpenVPN是基于TLS的。根据我从Docker的安全负责人Diogo Mónica那里了解的情况,v1.9之后可能加入线上加密功能。

最后,可以读一下Adrian Mouat的Using Docker,其中详细地介绍了网络安全方面。

小技巧: 自动Docker安全检查 为了对部署在生产环境中的Docker容器进行安全检查,我强烈建议使用The Docker Bench for Security



现在,我们对单主机场景有了一个基本的了解,让我们继续看一下更有效的案例:多主机网络环境。
#Docker多主机网络
只要是在单主机上使用Docker的话,那么上一章中介绍的技术就足够了。然而,如果一台宿主机的能力不足以应付工作负载,要么买一个更高配置的宿主机(垂直扩展),要么你添加更多同类型的机器(水平扩展)。

对于后者,你会搭建一个集群。那么,就出现了一系列问题:不同宿主机上的容器之间如何相互通信?如何控制容器间、容器和外部世界之间的通信?怎么保存状态,如IP地址分配、集群内保持一致性等?如何与现有的网络基础架构结合?安全策略呢?

为了解决这些问题,在本章中,我们会讨论多主机网络的各种技术。

注意:
对于本章中介绍的各种选项,请记住Docker信奉的是“batteries included but replaceable”,也就是说,总会有一个默认功能(如网络、服务发现),但是你可以使用其他方案来替代。



# Overlay
2015年3月,Docker, Inc.收购了软件定义网络(SDN)的创业公司SocketPlane,并更名为Docker Overlay驱动,作为多主机网络的默认配置(在Docker 1.9以后)。Overlay驱动通过点对点(peer-to-peer)通信扩展了通常的bridge模式,并使用一个可插拔的key-value数据库后端(如Consul、etcd和ZooKeeper)来分发集群状态。
# Flannel
CoreOS Flannel是一个虚拟网络,分配给每个宿主机一个子网。集群中的每个容器(或者说是Kubernetes中的pod)都有一个唯一的、可路由的IP地址,并且支持以下一系列后端:VXLAN、AWS VPC和默认的2层UDP overlay网络。flannel的优势是它降低了端口映射的复杂性。例如,Red Hat的Atomic项目使用的就是flannel
# Weave
Weaveworks Weave创建了一个虚拟网络,用来连接部署在多主机上的Docker容器。应用使用网络的方式就像是容器直接插入到同一个网络交换机上,不需要配置端口映射和连接。Weave网络上的应用容器提供的服务可以直接在公共网络上访问,无论这些容器在哪里运行。同样的,无论位置在哪,现有的内部系统都是暴露给应用容器的。Weave可以穿越防火墙,在部分连接的网络中运行。流量可以加密,允许主机跨越非授信网络进行连接。你可以从Alvaro Saurin的文章Automating Weave Deployment on Docker Hosts with Weave Discovery中学习到Weave的更多特性。
# Project Calico
Metaswitch的Calico项目使用标准IP路由,严格的说是RFC 1105中定义的边界网关协议(Border Gateway Protocol,简称BGP),并能使用网络工具提供3层解决方案。相反,大多数其他的网络解决方案(包括Weave)是通过封装2层流量到更高层来构建一个overlay网络。主操作模式不需要任何封装,是为可以控制物理网络结构的组织的数据中心设计的。
# Open vSwitch
Open vSwitch是一个多层虚拟交换机,通过可编程扩展来实现网络自动化,支持标准管理接口和协议,如NetFlow、IPFIX、LACP和802.1ag。除此之外,它还支持在多个物理服务器上分发,和VMware的vNetwork distributed vSwitch、Cisco的Nexus 1000V类似。
# Pipework
Pipework由著名的Docker工程师Jérôme Petazzoni创建,称为Linux容器的软件定义网络。它允许你使用cgroups和namespace在任意复杂的场景中连接容器,并与LXC容器或者Docker兼容。由于Docker, Inc.收购了SocketPlane并引入了Overlay Driver,我们必须看一下这些技术如何融合。
# OpenVPN
OpenVPN,另一个有商业版本的开源项目,运行你创建使用TLS的虚拟私有网络(virtual private networks,简称VPN)。这些VPN也可以安全地跨越公共网络连接容器。如果你想尝试一下基于Docker的配置,我建议看一下DigitalOcean很赞的教程How To Run OpenVPN in a Docker Container on Ubuntu 14.04
# 未来的Docker网络
在最近发布的Docker v1.9中,引入了一个新的命令`docker network`。容器可以动态地连接到其他网络上,每个网络都可以由不同的网络驱动来支持。默认的多主机网络驱动是Overlay

为了了解更多实践经验,我建议看一下以下博客:

* Aleksandr Tarasov的Splendors and Miseries of Docker Network
* Calico项目的Docker libnetwork Is Almost Here, and Calico Is Ready!
* Weave Works的Life and Docker Networking – One Year On

# 更多话题
在本章中,我们讨论了多主机网络中的各种解决方案。这一小节会简要介绍一下其他需要了解的话题:
##IPVLAN
Linux内核v3.19引入了每个容器一个IP地址的特性,它分配给主机上的每个容器一个唯一的、可路由的IP地址。实际上,IPVLAN使用一个网卡接口,创建了多个虚拟的网卡接口,并分配了不同的MAC地址。这个相对较新的特性是由Google的Mahesh Bandewar贡献的,与macvlan驱动类似,但是更加灵活,因为它可以同时使用在L2和L3上。如果你的Linux发行版已经使用了高于3.19的内核,那么你很幸运;否则,你就无法享受这个新功能。
##IP地址管理(IPAM)
多主机网络中,最大的挑战之一就是集群中容器的IP地址分配
##编排工具兼容性
本章中讨论的大多数多主机网络解决方案都是封装了Docker API,并配置网络。也就是说,在你选择其中一个之前,你需要检查与容器编排工具的可兼容性。更多主题,请看第5章。
##IPv4 vs. IPv6
到目前为止,大多数Docker部署使用的是标准IPv4,但是IPv6正在迎头赶上。Docker从v1.5(2015年2月发布)开始支持IPv6。IPv4的持续减少将会导致越来越多的IPv6部署,也可以摆脱NATs。然而,什么时候转变完成还不清楚。

现在,你已经对底层网络和Docker网络的解决方案有了充分理解,让我们进入下一个内容:服务发现。
# 容器和服务发现
管理基础架构的cattle方法的最大挑战就是服务发现。服务发现和容器调度是一枚硬币的两面。如果你使用cattle方法的话,那么你会把所有机器看做相同的,你不会手动分配某台机器给某个应用。相反,你会使用调度软件来管理容器的生命周期。

那么,问题就来了:如何决定容器被调度到哪台宿主机上?答对了,这就是服务发现。我们会在第5章详细讨论硬币的另一面:容器编排。
# 挑战
服务发现已经出现了一段时间了,被认为是zeroconf的一部分。

zeroconf

zeroconf的想法是自动化创建和管理计算机网络,自动分配网络地址,自动分发和解析主机名,自动管理网络服务。

对于Docker容器来说,这个挑战归结于稳定地维护运行中容器和位置(location)的映射关系。位置这里指的是IP地址(启动容器的宿主机地址)和可被访问的端口。这个映射必须及时完成,并在集群中准确地重启容器。容器的服务发现解决方案必须支持以下两个操作:
##注册(Register)
建立`container->location`的映射。因为只有容器调度器才知道容器运行在哪,我们可以把该映射当做容器位置的“绝对真理”(the absolute source of truth)。
##查询(Lookup)
其他服务或应用可以查询我们存储的映射关系,属性包括信息的实时性和查询延迟。

让我们看一下在选择过程中相对独立的几点考虑:

* 除了简单地向一个特定方向发送请求之外,怎么从搜索路径中排除不健康的宿主机和挂掉的容器?你已经猜到了,这是和负载均衡高度相关的主题,因为这是很重要的,所以本章的最后一小节将讨论这一主题。
* 有人认为这是实现细节,也有人认为需要考虑CAP三要素。在选择服务发现工具时,需要考虑选择强一致性(strong consistency)还是高可用性(high availability)。至少你要意识到这一点。
* 可扩展性也会影响你的选择。当然,如果你只有少量的节点需要管理,那么上面讨论的解决方案就够用了。然而,如果你的集群有100多个节点,甚至1000个节点,那么在选择某一项特定技术之前,你必须做一些负载测试。

CAP理论
1998年,Eric Brewer提出了分布式系统的CAP理论。CAP代表了一致性(consistency)、可用性(availability)和分区容错性(partition tolerance):



一致性
> 分布式系统的所有节点同时看到相同的数据。
> 可用性
> 保证每个请求都能得到响应,无论该响应是成功还是失败。
> 分区容错性
> 无论哪块分区由于网络故障而失效,分布式系统都可以继续运行。
> CAP理论在分布式系统的实践中已经讨论多次了。你会听到人们主要讨论强一致性 vs 最终一致性,我建议读一下Martin Kleppmann的论文A Critique of the CAP Theorem。该论文提出了一种不同的、更实际的思考CAP的方法,特别是一致性。



如果你想了解该领域更多的需求和根本的挑战,可以读一下Jeff Lindsay的Understanding Modern Service Discovery with Docker和Shopify的Simon Eskildsen在DockerCon分享的内容
# 技术
该小节介绍了各种技术和它们的优缺点,并提供了网上的更多资源(如果你想获得这些技术的实践经验,你可以看看Adrian Mouat的书Using Docker)。
## ZooKeeper
Apache ZooKeeper是ASF的顶级项目,基于JVM的集中式配置管理工具,提供了与Google的Chubby相兼容的功能。ZooKeeper(ZK)将数据载荷组织成文件系统,成为`znodes`的层级结构。在集群中,选举出一个leader节点,客户端能够连接到服务器中的任意一个来获取数据。一个ZK集群中需要2n+1个节点。最常见的配置是3、5、7个节点。

ZooKeeper是经战场证明的、成熟的、可扩展的解决方案,但是也有一下缺点。有些人认为ZK集群的安装和管理不是一个令人愉快的体验。我碰到的大多数ZK问题都是因为某个服务(我想到了Apache Storm)错误地使用了它。它们可能在znodes里放入了太多数据,更糟糕的是,他们的读写率很不健康(unhealthy read-write ratio),特别是写得太快。如果你打算使用ZK的话,至少考虑使用高层接口。例如,Apache Curator封装了ZK,提供了大量的方法;Netflix的Exhibitor可以管理和监控一个ZK集群。

从图4-1可以看出,你可以看到两个组件:`R/W`(作为注册监控器(registration watcher),你需要自己提供)和NGINX(被`R/W`控制)。当一个容器被调度到一个节点上时,它会在ZK中注册,使用一个路径为/$nodeID/$containerID的`znode`,IP地址作为数据载荷。`R/W`监控`znodes`节点的变化,然后相应地配置NGINX。这种方法对于HAProxy和其他负载均衡器也同样有效。
06.png

图 4-1
## etcd
etcd是由CoreOS团队使用Go语言编写的。它是一个轻量级的、分布式键值对数据库,使用Raft算法实现一致性(带有leader选举的leader-follower模型),在集群中使用复制日志(replicated log)向followers分发lead收到的写请求。从某种意义上说,在概念上,etcd和ZK是相当类似的。虽然负载数据是任意的,但是etcd的HTTP API是基于JSON的。就像ZK一样,你可以观察到etcd保存的值的变化。etcd的一个非常有用的特性是键的TTL,是服务发现的重要的一个结构单元。和ZK一样,一个etcd集群至少需要2n+1个节点。

etcd的安全模型支持基于TLS/SSL和客户端证书加密的线上加密(on-the-wire encryption),加密可以发生在客户端和集群之间,也可以在etcd节点之间。

在图4-2中,你可以看到etcd服务发现的搭建和ZK是相当类似的。主要区别在于etcd使用confd来配置NGINX,而不是使用自己编写的脚本。和ZK一样,这种搭建方法也适用于HAProxy或者其他负载均衡器。
07.png

图 4-2
### Consul
Consul是HashiCorp的产品,也是用Go语言写的,功能有服务注册、服务发现和健康检查,可以使用HTTP API或者DNS来查询服务。Consul支持多数据中心的部署。

Consul的其中一个特性是一个分布式键值对数据库,与etcd相似。它也是用Raft一致性算法(同样需要2n+1个节点),但是部署方式是不同的。Consul有agent的概念,有两种运行方式:服务器模式(提供键值对数据库和DNS)和客户端模式(注册服务和健康检查),使用serf实现了成员和节点发现。

使用Consul,你有四种方式来实现服务发现(从最可取到最不可取):

* 使用服务定义配置文件(service definition config file),由Consul agent解释。
* 使用traefik等工具,其中有Consul后端(backend)
* 编写你自己的进程通过HTTP API注册服务。
* 让服务自己使用HTTP API来注册服务。

想要学习Consul来做服务发现吗?请阅读这两篇文章:Consul Service Discovery with DockerDocker DNS & Service Discovery with Consul and Registrator
# 纯基于DNS的解决方案
在互联网中,DNS经受了数十年的战场验证,是很健壮的。DNS系统的最终一致性、特定的客户端强制性地(aggressively)缓存DNS查询结果、对于`SRV`记录的依赖这些因素使你明白这是正确的选择。

本小节之所以叫做“纯基于DNS的解决方案”的原因是,技术上讲Consul也是用了DNS服务器,但这只是Consul做服务发现的其中一个选项。以下是著名的、常用的、纯粹的基于DNS的服务发现解决方案:
##Mesos-DNS
该解决方案是专门用于Apache Mesos的服务发现的。使用Go编写,Mesos-DNS下拉任意任务的有效的Mesos Master进程,并通过DNS或HTTP API暴露IP:PORT信息。对于其他主机名或服务的DNS请求,Mesos-DNS可以使用一个外部的域名服务器或者你的现有DNS服务器来转发Mesos任务的请求到Mesos-DNS。
##SkyDNS
使用etcd,你可以将你的服务通告给SkyDNS,SkyDNS在etcd中保存了服务定义,并更新DNS记录。你的客户端应用发送DNS请求来发现服务。因此,在功能层面,SkyDNS与Consul是相当类似的,只是没有健康检查。
##WeaveDNS
WeaveDNS由Weave 0.9引入,作为Weave网络的服务发现解决方案,允许容器按照主机名找到其他容器的IP地址。在Weave 1.1中,引入了所谓的Gossip DNS,通过缓存和超时功能使得查询更加快速。在最新的实现中,注册是广播到所有参与的实例上,在内存中保存所有条目,并在本地处理查询。
## Airbnb的SmartStack和Netflix的Eureka
在本小节中,我们将会看一下两个定做的系统,它们是用来解决特定的需求。这并不意味着你不能或者不应该使用它们,你只是需要意识到它们。

Airbnb的SmartStack是一个自动的服务发现和注册框架,透明地处理创建、删除、故障和维护工作。在容器运行的同一个宿主机上,SmartStack使用了两个分离的服务:Nerve(写到ZK)用于服务注册,Synapse(动态配置HAProxy)用于查询。这是一个针对非容器环境的完善的解决方案,随着实践推移,你会看到对于Docker,SmartStack也是有用的。

Netflix的Eureka则不同,它运行在AWS环境中(Netflix全部运行在AWS上)。Eureka是一个基于REST的服务,用于定位服务以便负载均衡和中间件层服务器的故障迁移;Eureka还有一个基于Java的客户端组件,可以直接与服务交互。这个客户端有一个内置的负载均衡器,可以做基本的round-robin的负载均衡。在Netflix,Eureka用于做red/black部署、Cassandra和memcached部署、承载应用中关于服务的元数据。

Eureka集群在参与的节点之间异步地复制服务注册信息;与ZK、etcd、Consul不同,Eureka相对于强一致性更倾向于服务可用性,让客户端自行处理过时的读请求,优点是在网络分区上更有弹性。你也知道的:网络是不可靠的
# 负载均衡
服务发现的一个方面是负载均衡,有的时候负载均衡被认为是正交的,有的时候负载均衡被认为是服务发现的一部分。它可以在很多容器之间分散负载(入站服务请求)。在容器和微服务的语境下,负载均衡同时具有以下功能:

* 最大化吞吐量,最小化响应时间
* 防止热点(hotspotting),例如单一容器过载
* 可以处理过度激进的DNS缓存(overly aggressive DNS caching)

以下列举了一些有名的Docker中的负载均衡解决方案:
* NGINX
* HAProxy
* Bamboo
* Kube-Proxy
* vulcand
* Magnetic.io的vamp-router
* moxy
* HAProxy-SRV
* Marathon的servicerouter.py
* traefik

如果你想了解更多关于负载均衡的信息,请查看Mesos meetup视频和nginx.conf 2014上关于NGINX和Consul的负载均衡的演讲
# 更多话题
在本章的最后,我列举了服务发现解决方案的一览表。我并不想评出一个优胜者,因为我相信这取决于你的用例和需求。因此,把下表当做一个快速定位和小结:
08.png

最后请注意:服务发现领域在不断变化中,每周都会出现新工具。例如,Uber最近开源了它的内部解决方案Hyperbahn,一个路由器的overlay网络,用来支持TChannel RPC协议。因为容器服务发现在不断发展,因此你可能要重新评估最初的选择,直到稳定下来为止。
# 容器和编排
就像上一章中介绍的那样,使用cattle方法来管理基础架构,你不必手动为特定应用分配特定机器。相反,你应该使用调度器来管理容器的生命周期。尽管调度是一个重要的活动,但是它其实只是另一个更广阔的概念——编排的一部分。

从图5-1,可以看到编排包括健康检查(health checks)、组织原语(organizational primitives,如Kubernetes中的labels、Marathon中的groups)、自动扩展(autoscaling)、升级/回滚策略、服务发现。有时候base provisioning也被认为是编排的一部分,但是这已经超出了本书的讨论范围,例如安装Mesos Agent或Kubernetes Kubelet。

服务发现和调度是同一枚硬币的两面。决定一个特定的容器运行在集群的哪个节点的实体,称之为调度器。它向其他系统提供了`containers->locations`的映射关系,可以以各种方式暴露这些信息,例如像etcd那样的分布式键值对数据库、像Mesos-DNS那样的DNS。
09.png

图 5-1

本章将从容器编排解决方案的角度讨论服务发现和网络。背后的动机很简单:假设你使用了某个平台,如Kubernetes;然后,你主要的关注点是平台如何处理服务发现和网络。

注意:
接下来,我会讨论满足以下两个条件的容器编排系统:开源的和相当大的社区。
你可以看一下以下几个不同的解决方案:Fackebook的Bistro或者托管的解决方案,如Amazon EC2的容器服务ECS。
另外,你如果想多了解一下分布式系统调度这个主题,我推荐阅读Google关于BorgOmega的研究论文。



在我们深入探讨容器编排系统之前,让我们先看一下编排的核心组件——调度器到底是做什么的。
# 调度器到底是做什么的?
分布式系统调度器根据用户请求将应用分发到一个或多个可用的机器上。例如,用户可能请求运行应用的100个实例(或者Kubernetes中的replica)。

在Docker中,这意味着:(a)相应的Docker镜像存在宿主机上;(b)调度器告诉本地的Docker Daemon基于该镜像开启一个容器。

在图5-2中,你可以看到,对于集群中运行的应用,用户请求了三个实例。调度器根据它对于集群状态的了解,决定将应用部署在哪里。比如,机器的使用情况、成功启动应用所必须的资源、约束条件(该应用只能运行在使用SSD的机器)等。进一步地,服务质量也是考量因素之一。
10.png

图 5-2

通过John Wilkes的Cluster Management at Google了解更多内容。

警告:
对于调度容器的限制条件的语义,你要有概念。例如,有一次我做了一个Marathon的demo,没有按照预期工作,原因是我没有考虑布局的限制条件:我使用了唯一的主机名和一个特定的角色这一对组合。它不能扩展,原因是集群中只有一个节点符合条件。同样的问题也可能发生在Kubernetes的label上。



# Vanilla Docker and Docker Swarm
创造性地,Docker提供了一种基本的服务发现机制:Docker连接(links)。默认情况下,所有容器都可以相互通信,如果它们知道对方的IP地址。连接允许用户任何容器发现彼此的IP地址,并暴露端口给同一宿主机上的其他容器。Docker提供了一个方便的命令行选项`--link`,可以自动实现这一点。

但是,容器之间的硬连接(hard-wiring of links)并不有趣,也不具扩展性。事实上,这种方法并不算好。长久来说,这个特性会被弃用。

让我们看一下更好的解决方案(如果你仍然想要或者必须使用连接的话):ambassador模式
# Ambassadors
如图5-3所示,这个模式背后的想法是使用一个代理容器来代替真正的容器,并转发流量。它带来的好处是:ambassador模式允许你在开发阶段和生产阶段使用不同的网络架构。网络运维人员可以在运行时重写应用,而不需要更改应用代码。

简单来说,ambassador模式的缺点是它不能有效地扩展。ambassador模式可以用在小规模的、手动的部署中,但是当你使用真正的容器编排工具(如Kubernetes或Apache Mesos)时,应该避免使用ambassador模式。
11.png

图 5-3

注意:
如果你想要了解如何在Docker中部署ambassador模式,我再次建议你参考Adrian Mouat的书Using Docker。事实上,在图5-3中,我使用的就是他的amouat/ambassador镜像



# Docker Swarm
除了容器的静态链接(static linking),Docker有一个原生的集群工具Docker Swarm。Docker Swarm基于Docker API构建,并通过以下方式工作:有一个Swarm manager负载调度,在每一个宿主机上运行了一个agent,负责本地资源管理(如图5-4所示)。

Swarm中有趣的地方在于,调度器是插件式的(plug-able),所以你可以使用除了内置以外的其他调度器,如Apache Mesos。在写本书的过程中,Swarm发布了1.0版本,并完成了GA(General Availability);新的特性(如高可用性)正在进行开发中。
12.png

图 5-4
## 网络
在本书的第2章和第3章中,我们介绍了Docker中的单宿主机和多宿主机中的网络。
## 服务发现
Docker Swarm支持不同的后端:etcd、Consul和Zookeeper。你也可以使用静态文件来捕捉集群状态。最近,一个基于DNS的服务发现工具wagl被引入到了Swarm中。

如果你想更多了解Docker Swarm,可以读一下Rajdeep Dua的幻灯片
# Kubernetes
Kubernetes(请看图5-5)是一个opinionated的开源框架,弹性地管理容器化的应用。简单来说,它吸取了Google超过十年的运行容器负载的经验,我们会简要地介绍一下。进一步地,你总是可以选择其他开源或闭源的方法来替换Kubernetes的默认实现,比如DNS或监控。
13.png

图 5-5

以下讨论假设你已经熟悉Kubernetes和它的技术。如果你还不熟悉Kubernetes的话,我建议看一下Kelsey HighTower的Kubernetes Up and Running

Kubernetes中,调度单元是一个pod,这是a tightly coupled set of containers that is always collocated。pod运行实例的数目是由Replication Controller定义和指定的。pods和services的逻辑组织是由labels定义的。

在每个Kubernetes节点上,运行着一个称为Kubelet的agent,负责控制Docker daemon,向Master汇报节点状态,设置节点资源。Master节点提供API(例如,图5-6中的web UI),收集集群现在的状态,并存储在etcd中,将pods调度到节点上。
14.png

图 5-6
## 网络
在Kubernetes中,每个pod都有一个可路由的IP,不需要NAT,集群节点上的pods之间也可以相互通信。pod中的所有容器共享一个端口命名空间(port namespace)和同一个notion localhost,因此没有必要做端口代理(port brokering)。这是Kubernetes的基本要求,可以通过network overlay来实现。

在pod中,存在一个所谓的infrastructure容器,kubelet实例化的第一个容器,它会获得pod的IP,并设置网络命名空间。pod中的所有其他容器会加入到infra容器的网络和IPC命名空间。infra容器的网络启用了bridge模式(请参考第九页的bridge模式网络),pod中的所有其他容器使用container模式(请参考第11页的container模式网络)来共享它的命名空间。infra容器中的初始进程实际上什么也没做,因为它的目的只是提供命名空间的载体。关于端口转发的最近的work around可能在infra容器中启动额外的进程。如果infra容器死亡的话,那么Kubelet会杀死pod中所有的进程,然后重新启动进程。

进一步地,Kubernetes的命名空间会启动所有control points。其中一个网络命名空间的例子是,Calico项目使用命名空间来强化coarse-grained网络策略(policy)
## 服务发现
在Kubernetes的世界里,有一个服务发现的canonical抽象,这是service primitive。尽管pods随时可能启动和销毁因为他们可能失败(或者pods运行的宿主机失败),服务是长时间运行的:它们提供集群层面的服务发现和某种级别的负载均衡。它们提供了一个稳定的IP地址和持久化名字,compensating for the shortlivedness of all equally labelled pods。Kubernetes提供了两种发现机制:通过环境变量(限制于一个特定节点上)和DNS(集群层面上的)。
# Apache Mesos
Apache Mesos (图5-7)是一个通用的集群资源管理器,抽象了集群中的各项资源(CPU、RAM等),通过这种方式,集群对于开发者来说就像一个巨大的计算机。

在某种程度上,Mesos可以看作是分布式操作系统的内核。因此,它从未单独使用,总是和其他框架一起工作,例如Marathon(用于long-running任务,如web服务器)、Chronos(用于批量任务)或者大数据框架(如Apache Spark或Apache Cassandra)。
15.png

图 5-7

Mesos同时支持容器化负载(Docker容器)和普通的可执行文件(包括bash脚本、Python脚本、基于JVM的应用、一个纯粹的老的Linux二进制格式),也支持无状态和有状态的服务。

接下来,我假设你已经熟悉了Mesos和它的相关技术。如果你不熟悉Mesos,我建议你阅读David Greenberg的书《Building Applications on Mesos》,该书介绍了Mesos,特别是对于分布式应用的开发者。

如图5-8所示,你可以看到Marathon的UI,使用Apache Mesos来启动和管理长期运行的服务和应用。
16.png

图 5-8
## 网络
网络特性和能力主要取决于Mesos使用的容器方案:

* 对于Mesos containerizer来说,有一些要求,如Linux内核版本要大于3.16,并安装`libnl`。开启网络隔离功能之后,你可以构建一个Mesos Agent。启动之后,你可以看到以下输出:
mesos-slave --containerizer=mesos --isolation=network/port_mapping --resources=ports:[31000-32000];ephemeral_ports: [33000-35000]

Mesos Agent会配置成使用非临时(non-ephemeral)端口31000-32000,临时(ephemeral)端口33000-35000。所有容器共享宿主机的IP地址,端口范围被分配到各个容器上(使用目的端口和容器ID之间的1:1映射)。通过网络隔离,你可以定义网络性能(如带宽),使得你能够监控容器的网络流量。更多细节,请看MesosCon 2015 Seattle上的演讲Per Container Network Monitoring and Isolation in Mesos

* 对于Docker containerizer,请看第二章。

## 服务发现
尽管Mesos不提供服务发现功能,但是有一个Mesos特定的解决方案,在praxis中也很常用:Mesos-DNS(Pure-Play DNS-based Solutions)。然而,还有其他的解决方案,如traefik。如果你对于Mesos中的服务发现很感兴趣,我们的文档中有一个专门的章节介绍它。
# Hashicorp Nomad
Nomad是HashiCorp开发的集群调度器,HashiCorp也开发了Vagrant。Nomad于2015年9月份引入,主要目的是简化性。Nomad易于安装和使用。据说,它的调度器设计受到Google的Omega的影响,比如维护了集群的全局状态、使用优化的、高并发的调度器。

Nomad的架构是基于agent的,它有一个单独的二进制文件,可以承担不同的角色,支持滚动升级(rolling upgrade)和draining nodes(为了重新平衡)。Nomad使用了一致性协议(强一致性)来实现所有的状态复制和调度,使用gossip协议来管理服务器地址,从而实现集群自动化(automatic clustering)和多区域联合(multiregion federation)。从图5-9可以看到,Nomad agent正在启动。
17.png

图 5-9

Jobs定义为HCL格式(HashiCorp-proprietary format)或JSON格式。Nomad提供了命令行接口和HTTP API,来和服务器进程进行交互。

接下来,我假设你已经熟悉了Nomad和它的术语,否则我不建议你读这一节。如果你不熟悉的话,我建议你读一下Nomad: A Distributed, Optimistically Concurrent Schedule: Armon Dadgar, HashiCorp(这是HashiCorp的CTO Armon Dadgar对于Nomad的介绍)和Nomad的文档
## 网络
Nomad中有几个所谓的任务驱动(task drivers),从通用的Java可执行程序到qemu和Docker。在之后的讨论中,我们将会专注后者。

在写这篇文章的时候,Nomad要求Docker的版本为1.8.2,并使用端口绑定技术,将容器中运行的服务暴露在宿主机网卡接口的端口空间中。Nomad提供了自动的和手动的映射方案,绑定Docker容器的TCP和UDP协议端口。

关于网络选项的更多细节,例如端口映射(mapping ports)和标签(labels),我建议你读一下该文章
## 服务发现
v0.2中,Nomad提供了基于Consul的服务发现机制,请参考相关文档。其中包含了健康检查(health checks),并假设运行在Nomad中的任务能够与Consul agent通信(使用bridge模式网络),这是一个挑战。
# 我应该用哪个呢?
以下内容当然只是我的一个建议。这是基于我的经验,自然地,我也偏向于我正在使用的东西。可能有各种原因(包括政治上的原因)导致你选择一个特定的技术。

从纯粹的可扩展性的角度来看,这些选项有以下特点:
18.png

对于少量的节点来说,自然是无所谓的:根据你的偏好和经验,选择以上四个选项中的任意一个都可以。但是请记住,管理大规模的容器是很困难的

* Docker Swarm可以管理1000个节点,请参考HackerNews和Docker的这篇博客
* Kubernetes 1.0据说可以扩展至100个节点,并在持续改进中,以达到和Apache Mesos同样的可扩展性
* Apache Mesos可以管理最多50000个节点
* 到目前为止,还没有资料表明Nomad可以管理多少个节点。

从工作负载的角度来看,这些选项有以下特点:
19.png


非容器化(Non-containerized)意味着你可以运行任何Linux Shell中可以运行的程序,例如bash或Python脚本、Java程序等。容器化(containerized)以为你需要生成一个Docker镜像。考虑到有状态服务,当今应用中的很大一部分需要一些调整。如果你想更多地学习编排工具,请参考:

* Docker Clustering Tools Compared: Kubernetes vs Docker Swarm
* O'Reilly Radar的Swarm v. Fleet v. Kubernetes v. Mesos

为了完整性,我想介绍这个领域的一个新成员Firmament,这是一个非常不错的项目。这个项目的开发者们也是Google的Omega和Borg的贡献者,这个新的调度器将任务和机器组成了一个流网络,并运行最小成本优化(minimum-cost optimization)。特别有趣的一点是,Firmament不仅可以单独使用,也可以与Kubernetes和Mesos整合。
## 容器的一天
当选择使用哪种容器编排方案时,你需要考虑容器的整个生命流程。
20.png

图 5-10

Docker容器典型的生命周期包括以下几个阶段:
###阶段1: dev
容器镜像(你的服务和应用)从一个开发环境中开始它的生命流程,通常是从一名开发者的笔记本开始的。你可以使用生产环境中运行的服务和应用的特性请求(feature requests)作为输入。
###阶段2: CI/CD
然后,容器需要经历持续集成和持续发布(continuous integration and continous delivery),包括单元测试、整合测试和冒烟测试
###阶段3: QA/staging
然后,你可以使用一个QA环境(企业内部或云中的集群)和/或staging阶段。
###阶段4:prod
最后,容器镜像是部署到生产环境中的。你也需要有一个策略去分发这些镜像。不要忘记以canaries的方式进行构建,并为核心系统(如Apache Mesos)、潜在的高层组件(如Marathon)和你的服务和应用的滚动式升级(rolling upgrade)做计划。

在生产环境中,你会发现bugs,并收集相关指标,可以用来改善下一个迭代(返回到阶段1)。

这里讨论的大部分系统(Swarm、Kubernetes、Mesos和Nomad)提供了很多指令、协议和整合点来覆盖这些阶段。然而,在你选择任何一个系统之前,你仍然需要端到端地试用该系统。
## 社区是很重要的
当选择编排系统时,另一个你需要考虑的一件方面是背后的社区。以下是一些指标:

* 是否由一个正式的实体或流程来管理?例如,Apache软件基金会或Linux基金会。
* 邮件列表、IRC频道、bug/issue追踪器、Git仓库(补丁或PR的数量)是否活跃?看一下历史情况,但是请特别注意活跃度。一个健康的社区至少会在其中一个领域非常活跃。
* 该编排工具是否由一个单一实体实际控制?例如,对于Nomad来说,很明显的是,HashiCorp具有完全控制权。那么Kubernetes和Mesos呢?
* 是否有多个独立的提供商提供支持?例如,你可以在多个不同的环境中运行Kubernetes或Mesos,并从很多商业或非商业的组织和个人得到帮助。

我们已经到了本书的结尾。在容器的网络和服务发现方面,你已经学习到了不少知识。看完本章之后,你已经可以选择和部署容器化应用了。如果你希望深入地了解本书中的各个主体,请查看附录A,附录A提供了大量的资源列表。

#附录A 参考
以下这些链接,有的包含了背景知识,有的包含了一些高级内容。
##网络参考

* Docker Networking
* Concerning Containers’ Connections: on Docker Networking
* Unifying Docker Container and VM Networking
* Exploring LXC Networking
* Letting Go: Docker Networking and Knowing When Enough Is Enough
* Networking in Containers and Container Clusters

##服务发现参考

* Service Discovery on p24e.io
* Understanding Modern Service Discovery with Docker
* Service Discovery in Docker Environments
* Service Discovery, Mesosphere
* Docker Service Discovery Using Etcd and HAProxy
* Service discovery with Docker: Part 1 and Part 2
* Service Discovery with Docker: Docker Links and Beyond

##其他高级话题

* [url=http://bit.ly/1ObcJq2]What M

k8s calico 网络问题

回复

在别处 发起了问题 • 1 人关注 • 0 个回复 • 1289 次浏览 • 2018-08-15 15:46 • 来自相关话题

docker使用host模式 主机却无法ping通容器

回复

cyan 回复了问题 • 2 人关注 • 2 个回复 • 4372 次浏览 • 2017-01-03 19:17 • 来自相关话题

flannel网络配置问题

回复

jun.yang 回复了问题 • 2 人关注 • 2 个回复 • 2490 次浏览 • 2016-07-04 09:43 • 来自相关话题

请叫一个关于自动添加docker network bridge的问题

回复

S_ON_G 发起了问题 • 1 人关注 • 0 个回复 • 2301 次浏览 • 2016-06-21 18:42 • 来自相关话题

【精贴】(神速)5分钟内拉取Dockerhub镜像 附带Mesos中文版下载链接

回复

挑灯看剑 回复了问题 • 10 人关注 • 5 个回复 • 6337 次浏览 • 2016-04-08 17:13 • 来自相关话题

分配在不同docker网络的容器如何单独配置网络互通?

回复

yingz 回复了问题 • 4 人关注 • 3 个回复 • 4122 次浏览 • 2016-01-31 11:18 • 来自相关话题

Kubernetes能不能够固定容器的IP?

回复

beyondblog 回复了问题 • 12 人关注 • 7 个回复 • 12417 次浏览 • 2015-12-25 14:31 • 来自相关话题

如何实现为容器多添加一块网卡,让容器中有两块网卡?

回复

CMGS 回复了问题 • 2 人关注 • 1 个回复 • 3958 次浏览 • 2015-05-07 16:44 • 来自相关话题

多个Docker容器如何桥接到不同的网桥中?

回复

我另一个女友叫五姑娘 回复了问题 • 5 人关注 • 4 个回复 • 4631 次浏览 • 2015-05-06 16:22 • 来自相关话题

Docker容器通信频繁的场景

回复

徐新坤 回复了问题 • 4 人关注 • 4 个回复 • 3969 次浏览 • 2015-05-05 18:07 • 来自相关话题

DockOne微信分享(一九八):容器网络限流实践

范彬 发表了文章 • 0 个评论 • 1162 次浏览 • 2019-01-09 09:51 • 来自相关话题

【编者的话】我们需要为“上云“的应用提供流量带宽保证,使其不受到其他应用或其他用户的应用的影响。我们需要提供租户级别或者应用级别的有效隔离。今天将分享一下我们为了达到这个目标做了哪些实践工作。 # 容器平台做容器网络限流的意义 无论我们 ...查看全部
【编者的话】我们需要为“上云“的应用提供流量带宽保证,使其不受到其他应用或其他用户的应用的影响。我们需要提供租户级别或者应用级别的有效隔离。今天将分享一下我们为了达到这个目标做了哪些实践工作。
# 容器平台做容器网络限流的意义
无论我们的目标是搭建公有云的容器云平台还是为客户提供容器平台的私有部署或解决方案,我们都会面临一个问题:容器网络限流的问题。在我们实验室的环境下,如果没有对容器带宽进行限制,单Pod使用的最大吞吐量将可以独占整个带宽,从而导致其他应用不能被访问。

单用户单Pod在没有做任何网络带宽限制情况下,网络吞吐量测试结果如下:
0.png

我们需要为“上云”的应用提供流量带宽保证,使其不受到其他应用或其他用户的应用的影响。我们需要提供租户级别或者应用级别的有效隔离。今天将分享一下我们为了达到这个目标做了哪些实践工作。

在Kubernetes众多的网络插件中,我们选择使用Open vSwitch容器网络插件。通常情况下,我们根据VNID实现租户间的网络隔离,并且在此基础上我们还可以根据Networkpolicy网络策略提供更细粒度的网络隔离,可以实现Pod之间、跨Namespace的网络访问控制。
1.png

# 使用Open vSwitch容器网络插件如何进行容器网络限流
使用Open vSwitch容器网络插件如何进行容器网络限流呢?Open vSwitch本身不实现QoS,它使用Linux内核自带的traffic-control机制进行流量控制。主要两种实现方式:

* Policing管制:Policing用于控制接口上接收分组(ingress)的速率,是一种简单的QoS的功能,通过简单的丢包机制实现接口速率的限制,它既可以作用于物理接口,也可以作用于虚拟接口。
* Shaping整形:Shaping是作用于接口上的出口流量(egress)策略,可以实现QoS队列,不同队列里面处理不同策略。

2.png

##Policing的实现
Policing在OVS中采用ingress_policing_rate和ingress_policing_burst两个字段完成ingress入口限速功能,该两个字段放在Interface表中。

入口限速直接配置在网络接口上,命令示例如下:
# ovs-vsctl set interface eth1 ingress_policing_rate=1000
# ovs-vsctl set interface eth1 ingress_policing_burst=100


* eth1:加入OVS桥端口的网络接口名称;
* ingress_policing_rate:为接口最大收包速率,单位kbps,超过该速度的报文将被丢弃,默认值为0表示关闭该功能;
* ingress_policing_burst:为最大突发流量大小,单位kb。默认值0表示1000kb,这个参数最小值应不小于接口的MTU,通常设置为ingress_policing_rate的10%更有利于tcp实现全速率;

通过命令ovs-vsctl list interface eth1可以查看配置:
OpenvSwitch-QoS-fig-1.png

##Shaping的实现
Shaping用于实现出口流量的控制,使用了队列Queue,可以缓存和调度数据包发送顺序,比Policing更加精确和有效,在OVS的数据表中主要使用QoS和Queue两张表。

QoS创建命令:
ovs-vsctl set port eth1 qos=@newqos--  
--id=@newqoscreate qos type=linux-htb queues=0=@q0--
--id=@q0create queue other-config:max-rate=100000000

创建Queue:
--id=@q0 create queue other-config:max-rate=100000000

创建q0队列,设置最大速率100M,通过ovs-vsctl查看配置的Queue表内容如下:
OpenvSwitch-QoS-fig-4.png

创建Qos规则:
--id=@newqos create qos type=linux-htb queues=0=@q0

创建QoS规则newqos,类型为linux-htb,并连接key值为0的队列q0,通过ovs-vsctl查看配置的QoS表内容如下:
OpenvSwitch-QoS-fig-5.png

创建接口Qos:
set port eth1 qos=@newqos

设置接口eth1的QoS为newqos,通过ovs-vsctl list port查看配置的port表内容如下:
OpenvSwitch-QoS-fig-6.png

我们采用的技术栈是Golang。我们也可以使用红帽提供的OVS的库github.com/openshift/origin/pkg/util/ovs实现上面Policing和Shaping功能。

代码示意如下:
image.png

image1.png

在Kubernetes上,如果使用Open vSwitch CNI插件,我们可以在创建Pod资源的时候为其配置速率限制。

创建iperf-pod.yaml,并为其配置速率限制:
cat <iperf-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: iperf
annotations:
kubernetes.io/ingress-bandwidth: 3M
kubernetes.io/egress-bandwidth: 3M
spec:
containers:
- name: iperf
image: yadu/hello-openshift-iperf
imagePullPolicy: IfNotPresent
nodeSelector:
zone: default
EOF

流入测试:

Pod容器里启动iperf server:
$ iperf -s -p 12345 -i 1
------------------------------------------------------------
Server listening on TCP port 12345
TCP window size: 85.3 KByte (default)
------------------------------------------------------------

在任意节点向iperf server产生流量:
[root@a-node4 ~]# iperf -c 10.130.2.103 -p 12345 -i 1 -t 10 -w 5m
------------------------------------------------------------
Client connecting to 10.130.2.103, TCP port 12345
TCP window size: 416 KByte (WARNING: requested 4.77 MByte)
------------------------------------------------------------
[ 3] local 10.130.2.1 port 58162 connected with 10.130.2.103 port 12345
[ ID] Interval Transfer Bandwidth
[ 3] 0.0- 1.0 sec 773 KBytes 6.33 Mbits/sec
[ 3] 1.0- 2.0 sec 316 KBytes 2.59 Mbits/sec
[ 3] 2.0- 3.0 sec 314 KBytes 2.57 Mbits/sec
(omitted)

查看Pod里流入的日志:
iperf -s -p 12345 -i 1
------------------------------------------------------------
Server listening on TCP port 12345
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
[ 4] local 10.130.2.103 port 12345 connected with 10.130.2.1 port 58162
[ ID] Interval Transfer Bandwidth
[ 4] 0.0- 1.0 sec 354 KBytes 2.90 Mbits/sec
[ 4] 1.0- 2.0 sec 351 KBytes 2.87 Mbits/sec
[ 4] 2.0- 3.0 sec 349 KBytes 2.86 Mbits/sec
(omitted)

流出测试:

在任意节点上启动iperf server作为测试:
iperf -s -p 12345 -i 1
------------------------------------------------------------
Server listening on TCP port 12345
TCP window size: 85.3 KByte (default)
------------------------------------------------------------

Pod中用iperf client进行测试:
iperf -c 172.18.143.117 -p 12345 -i 1 -t 10 -w 5m
------------------------------------------------------------
Client connecting to 172.18.143.117, TCP port 12345
TCP window size: 416 KByte (WARNING: requested 5.00 MByte)
------------------------------------------------------------
[ 3] local 10.130.2.103 port 44602 connected with 172.18.143.117 port 12345
[ ID] Interval Transfer Bandwidth
[ 3] 0.0- 1.0 sec 1.62 MBytes 13.6 Mbits/sec
[ 3] 1.0- 2.0 sec 384 KBytes 3.15 Mbits/sec
[ 3] 2.0- 3.0 sec 384 KBytes 3.15 Mbits/sec
(omitted)

查看node4上流入的日志:
iperf -s -p 12345 -i 1
------------------------------------------------------------
Server listening on TCP port 12345
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
[ 4] local 172.18.143.117 port 12345 connected with 10.130.2.103 port 44602
[ ID] Interval Transfer Bandwidth
[ 4] 0.0- 1.0 sec 1.28 MBytes 10.7 Mbits/sec
[ 4] 1.0- 2.0 sec 373 KBytes 3.05 Mbits/sec
[ 4] 2.0- 3.0 sec 380 KBytes 3.11 Mbits/sec
[ 4] 3.0- 4.0 sec 339 KBytes 2.77 Mbits/sec
(omitted)

查看tc的配置:
[root@a-node4 ~]# tc -s -d class show dev vethddb66bac
class htb 1:1 parent 1:fffe prio 0 quantum 1450 rate 11600bit ceil 3000Kbit burst 1513b/1 mpu 0b overhead 0b cburst 1513b/1 mpu 0b overhead 0b level 0
Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0
lended: 0 borrowed: 0 giants: 0
tokens: 16314655 ctokens: 63083

class htb 1:fffe root rate 3000Kbit ceil 3000Kbit burst 1449b/1 mpu 0b overhead 0b cburst 1449b/1 mpu 0b overhead 0b level 7
Sent 4187548 bytes 2872 pkt (dropped 0, overlimits 0 requeues 0)
rate 0bit 0pps backlog 0b 0p requeues 0
lended: 998 borrowed: 0 giants: 0
tokens: 60416 ctokens: 6041

#实现AdmissionWebhook组件:bandwidth-inject-webhook
在公有云平台中,我们可以根据租户等级,为其创建的Pod设置不同级别的限流限制。我们通过自研开发实现了AdmissionWebhook组件:bandwidth-inject-webhook。当创建Pod的配置文件yaml提交给apiserver时,可以为其增加网络限流配置。
image2.png

上面是我们基于Open vSwitch的CNI做的一些研究和开发工作。当然,我们也可以借鉴华为自研的CNI插件,去支持任何网络插件的情景。
image4.png


参考文章:Open vSwitch之QoS的实现:https://www.sdnlab.com/19208.html
#Q&A
Q:网络插件为什么没用Flannel?
A:如果选择flannel cni网络插件,可以采用华为开发的限流CNI插件。

Q:目前Istio也具有限速功能,这与tc限速共存吗?
A:SDN控制器,红帽开源的OpenShift有相应的实现。OVS选择是vxlan方式解决节点间通信。Istio的限流方式暂时我还没有了解。

以上内容根据2019年1月8日晚微信群分享内容整理。分享人范彬,现电信云容器项目研发组长。对技术保有一颗热衷的心。自2016年起开始一直从事容器、微服务等方面的研究和开发工作。熟悉Golang技术栈、Kubernetes分布式系统架构和工作原理。DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesd,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

FAQ宝典之常见问题排查与修复方法

Rancher 发表了文章 • 1 个评论 • 1363 次浏览 • 2017-12-29 12:33 • 来自相关话题

一、服务/容器 #1、为什么我只能编辑容器的名称? Docker容器在创建之后就不可更改了。唯一可更改的内容是我们要存储的不属于Docker容器本身的那一部分数据。无论是停止、启动或是重新启动,它始终在使用相 ...查看全部
一、服务/容器

#1、为什么我只能编辑容器的名称?

Docker容器在创建之后就不可更改了。唯一可更改的内容是我们要存储的不属于Docker容器本身的那一部分数据。无论是停止、启动或是重新启动,它始终在使用相同的容器。如需改变任何内容都需要删除或重新创建一个容器。

你可以克隆,即选择已存在的容器,并基于已有容器的配置提前在添加服务界面中填入所有要设置的内容,如果你忘记填入某项内容,可以通过克隆来改变它之后删除旧的容器。

#2、service-link的容器/服务在Rancher中是如何工作的?

在Docker中,关联容器(在docker run中使用--link)的ID和IP地址会出现在容器的/etc/hosts中。在Rancher中,我们不需要更改容器的/etc/hosts文件,而是通过运行一个内部DNS服务器来关联容器,DNS服务器会返回给我们正确的IP。

#3、不能通过Rancher的界面打开命令行或查看日志,如何去访问容器的命令行和日志?

Agent主机有可能会暴露在公网上,Agent上接受到的访问容器命令行或者日志的请求是不可信的。Rancher Server中发出的请求包括一个JWT(JSON Web Token),JWT是由服务器签名并且可由Agent校验的,Agent可以判断出请求是否来自服务器,JWT中包括了有效期限,有效期为5分钟。这个有效期可以防止它被长时间使用。如果JWT被拦截而且没有用SSL时,这一点尤为重要。

如果你运行docker logs -f (rancher-agent名称或ID)。日志会显示令牌过期的信息,随后检查Rancher Server主机和Rancher Agent主机的时钟是否同步。

#4、在哪里可以看到我的服务日志?

在服务的详细页中,我们提供了一个服务日志的页签日志。在日志页签中,列出了和服务相关的所有事件,包括时间戳和事件相关描述,这些日志将会保留24小时。

#5、RANCHER SERVER 点击WEB shell屏幕白屏

如果RANCHER SERVER 运行在V1.6.2版本,点击WEB shell出现白屏,这是UI上的一个BUG,请选择升级server服务。

#二、跨主机通信

如果容器运行在不同主机上,不能够ping通彼此,可能是由一些常见的问题引起的。

#1、如何检查跨主机通信是否正常?

在应用->基础设施中,检查 healthcheck 应用的状态。如果是active跨主机通信就是正常的。

手动测试,你可以进入任何一个容器中,去ping另一个容器的内部IP。在主机页面中可能会隐藏掉基础设施的容器,如需查看点击“显示系统容器”的复选框。

#2、UI中显示的主机IP是否正确?

有时,Docker网桥的IP地址会被错误的作为了主机IP,而并没有正确的选择真实的主机IP。这个错误的IP通常是172.17.42.1或以172.17.x.x开头的IP。如果是这种情况,在使用docker run命令添加主机时,请用真实主机的IP地址来配置CATTLE_AGENT_IP环境变量。


sudo docker run -d -e CATTLE_AGENT_IP= --privileged \
-v /var/run/docker.sock:/var/run/docker.sock \
rancher/agent:v0.8.2 http://SERVER_IP:8080/v1/scripts/xxxx


#3、Rancher的默认子网(10.42.0.0/16)在我的网络环境中已经被使用或禁止使用,我应该怎么去更改这个子网?

Rancher Overlay网络默认使用的子网是10.42.0.0/16。如果这个子网已经被使用,你将需要更改Rancher网络中使用的默认子网。你要确保基础设施服务里的Network组件中使用着合适的子网。这个子网定义在该服务的rancher-compose.yml文件中的default_network里。

要更改Rancher的IPsec或VXLAN网络驱动,你将需要在环境模版中修改网络基础设施服务的配置。创建新环境模板或编辑现有环境模板时,可以通过单击编辑来配置网络基础结构服务的配置。在编辑页面中,选择配置选项>子网输入不同子网,点击配置。在任何新环境中将使用环境模板更新后的子网,编辑已经有的环境模板不会更改现在已有环境的子网。

这个实例是通过升级网络驱动的rancher-compose.yml文件去改变子网为10.32.0.0/16。


ipsec:
network_driver:
name: Rancher IPsec
default_network:
name: ipsec
host_ports: true
subnets:
# After the configuration option is updated, the default subnet address is updated
- network_address: 10.32.0.0/16
dns:
- 169.254.169.250
dns_search:
- rancher.internal
cni_config:
'10-rancher.conf':
name: rancher-cni-network
type: rancher-bridge
bridge: docker0
# After the configuration option is updated, the default subnet address is updated
bridgeSubnet: 10.32.0.0/16
logToFile: /var/log/rancher-cni.log
isDebugLevel: false
isDefaultGateway: true
hostNat: true
hairpinMode: true
mtu: 1500
linkMTUOverhead: 98
ipam:
type: rancher-cni-ipam
logToFile: /var/log/rancher-cni.log
isDebugLevel: false
routes:
- dst: 169.254.169.250/32


注意:随着Rancher通过升级基础服务来更新子网,以前通过API更新子网的方法将不再适用。



#4、VXLAN 网络模式下,跨主机容器无法通信

Vxlan 通过4789端口实现通信,检查防火墙有没有开放此端口;

执行iptables -t filter -L -n参看IPtable表,查看chain FORWARD 是不是被丢弃,如果是,执行sudo iptables -P FORWARD ACCEPT

三、DNS

#1、如何查看我的DNS是否配置正确?

如果你想查看Rancher DNS配置,点击应用 > 基础服务。点击network-services应用,选择metadata,在metadata中,找到名为network-services-metadata-dns-X的容器,通过UI点击执行命令行后,可以进入该容器的命令行,然后执行如下命令。


cat /etc/rancher-dns/answers.json


#2、在Ubuntu上运行容器时彼此间不能正常通信。

如果你的系统开启了UFW,请关闭UFW或更改/etc/default/ufw中的策略为:


DEFAULT_FORWARD_POLICY="ACCEPT"


四、负载均衡

#1、为什么我的负载均衡一直是Initializing状态?

负载均衡器自动对其启用健康检查。如果负载均衡器处于初始化状态,则很可能主机之间无法进行跨主机通信。

#2、我如何查看负载均衡的配置?

如果要查看负载均衡器的配置,你需要用进入负载均衡器容器内部查找配置文件,你可以在页面选择负载均衡容器的执行命令行


cat /etc/haproxy/haproxy.cfg


该文件将提供负载均衡器的所有配置详细信息。

#3、我在哪能找到HAproxy的日志?

HAProxy的日志可以在负载均衡器容器内找到。负载均衡器容器的docker logs只提供与负载均衡器相关的服务的详细信息,但不提供实际的HAProxy日志记录。


cat /var/log/haproxy


#4、如何自定义负载均衡的配置



如图,在自定义配置中,按照global、defaults、frontend、backend的格式配置。

五、健康检查

#1、为什么健康检查服务一直显示黄色初始化状态?

healthcheck不仅为其他服务提供健康检查,对系统组件(比如调度服务)也提供健康检查服务,healthcheck也对自己进行健康检查。多个healthcheck组件时,它们会相互交叉检查,只有健康检查通过后,容器状态才会变成绿色。而healthcheck一直显示黄色初始化状态,说明一直没有通过健康检查。健康检查都是通过网络访问的,所以一定是网络通信异常导致。

六、调度

为什么节点关机后,应用没有自动调度到其他节点上?Rancher上应用的调度,需要配合健康检查功能。当健康检查检查到应用不健康才会重新调度,如果没有配置健康检查,即使关机,cattle也不会对应用做调度处理。

七、CentOS

#1、为什么容器无法连接到网络?

如果你在主机上运行一个容器(如:docker run -it ubuntu)该容器不能与互联网或其他主机通信,那可能是遇到了网络问题。Centos默认设置/proc/sys/net/ipv4/ip_forward为0,这从底层阻断了Docker所有网络。

解决办法:


vi /usr/lib/sysctl.d/00-system.conf


添加如下代码:


net.ipv4.ip_forward=1
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-arptables = 1


重启network服务


systemctl restart network


查看是否修改成功


sysctl net.ipv4.ip_forward


如果返回为net.ipv4.ip_forward = 1则表示成功了

八、京东云

#1、京东云运行rancher server出现以下问题



解决办法:sudo sysctl -w net.ipv4.tcp_mtu_probing=1

推荐阅读:《FAQ宝典之Rancher Server》《FAQ宝典之Rancher Server、K8s、Docker》

原文链接:Rancher Labs

FAQ宝典之Rancher Server、K8s、Docker

Rancher 发表了文章 • 1 个评论 • 1588 次浏览 • 2017-12-13 10:29 • 来自相关话题

Rancher FAQ宝典系列第二弹,Rancher Agent、Kubernetes、Docker相关的常见问题,本文一网打尽。 Rancher Agent常见问题 #1、Rancher Agent无法启动 ...查看全部
Rancher FAQ宝典系列第二弹,Rancher Agent、Kubernetes、Docker相关的常见问题,本文一网打尽。

Rancher Agent常见问题

#1、Rancher Agent无法启动的原因是什么?

1.1、添加 --NAME RANCHER-AGENT(老版本)

如果你从UI中编辑docker run .... rancher/agent...命令并添加--name rancher-agent选项,那么Rancher Agent将启动失败。Rancher Agent在初始运行时会启动3个不同容器,一个是运行状态的,另外两个是停止状态的。Rancher Agent要成功连接到Rancher Server必须要有两个名字分别为rancher-agent和rancher-agent-state的容器,第三个容器是docker自动分配的名称,这个容器会被移除。

1.2、使用一个克隆的虚拟机

如果你使用了克隆其他Agent主机的虚拟机并尝试注册它,它将不能工作。在rancher-agent容器的日志中会产生ERROR: Please re-register this agent.字样的日志。Rancher主机的唯一ID保存在/var/lib/rancher/state,因为新添加和虚拟机和被克隆的主机有相同的唯一ID,所以导致无法注册成功。

解决方法是在克隆的VM上运行以下命令:


rm -rf /var/lib/rancher/state; docker rm -fv rancher-agent; docker rm -fv rancher-agent-state


完成后可重新注册。

#2、我在哪里可以找到Rancher agent容器的详细日志?

从v1.6.0起,在rancher-agent容器上运行docker logs将提供agent相关的所有日志。

#3、主机是如何自动探测IP的?我该怎么去修改主机IP?如果主机IP改变了(因为重启),我该怎么办?

当Agent连接Rancher Server时,它会自动检测Agent的IP。有时,自动探测的IP不是你想要使用的IP,或者选择了docker网桥的IP,如. 172.17.x.x。或者,你有一个已经注册的主机,当主机重启后获得了一个新的IP, 这个IP将会和Rancher UI中的主机IP不匹配。你可以重新配置“CATTLE_AGENT_IP”设置,并将主机IP设置为你想要的。当主机IP地址不正确时,容器将无法访问管理网络。要使主机和所有容器进入管理网络,只需编辑添加自定义主机的命令行,将新的IP指定为环境变量“CATTLE_AGENT_IP”。在主机上运行编辑后的命令。不要停止或删除主机上的现有的Rancher Agent容器!


sudo docker run -d -e CATTLE_AGENT_IP= --privileged \
-v /var/run/docker.sock:/var/run/docker.sock \
rancher/agent:v0.8.2 http://SERVER_IP:8080/v1/scripts/xxxx


#4、错误提示如下:INFO: Attempting to connect to: http://192.168.xx.xx:8080/v1 ERROR: http://192.168.xx.xx:8080/v1 is not accessible (Failed to connect to 192.168.xx.xx port 8080: No route to host)

这个问题主要有以下几种情况:

  • RANCHER SERVER服务器防火墙没有开通8080端口;
  • 云平台安全组没有放行8080端口;
  • Agent 服务器没有开启IP转发规则 [为什么我的容器无法连接到网络?]:{site.baseurl}}/rancher/faqs/ troubleshooting/1为什么我的容器无法连接到网络;
=1为开启,=0为关闭
/etc/sysctl.confnet.ipv4.ip_forward=1net.ipv6.conf.all.forwarding=1
  • 主机hosts(/etc/hosts)文件没有配置;

#5、rancher下创建的服务容器,docker inspect 查看到Entrypoint和CMD后面有/.r/r字符,这个起什么作用?

./r 是基于weave wait编译出来的。CNI网络下会添加/.r/r 这个参数,目的是:当容器启动时,其实网络设备还没设置好,这时候需要container 等待,不能启动真实业务,否则会失败。

#6、添加hosts后 server上没有列出,agent报Host not registered yet. Sleeping 1 second and trying again.” Attempt=0 reportedUuid=752031dd-8c7e-4666-5f93-020d7f4da5d3

检查主机名和hosts配置, hosts中需要配置:

127.0.0.1 localhost
hostip hostname

Kubernetes常见问题

#1、部署Kubernetes时候出现以下有关cgroup的问题


Failed to get system container stats for "/system.slice/kubelet.service":
failed to get cgroup stats for "/system.slice/kubelet.service": failed to
get container info for "/system.slice/kubelet.service": unknown container
"/system.slice/kubelet.service"



Expected state running but got error: Error response from daemon:
oci runtime error: container_linux.go:247: starting container
process caused "process_linux.go:258: applying cgroup configuration
for process caused \"mountpoint for devices not found\""


以上问题为Kubernetes版本与docker版本不兼容导致cgroup功能失效

#2、Kubernetes err: [nodes "iZ2ze3tphuqvc7o5nj38t8Z" not found]”

Rancher-Kubernetes中,节点之间通信需要通过hostname,如果没有内部DNS服务器,那么需要为每台节点配置hosts文件。

配置示例:假如某个节点主机名为node1,ip 地址为192.168.1.100


cat /etc/hosts< 127.0.0.1 localhost
192.168.1.100 node1
EOF


#3、如何验证你的主机注册地址设置是否正确?

如果你正面临Rancher Agent和Rancher Server的连接问题,请检查主机设置。当你第一次尝试在UI中添加主机时,你需要设置主机注册的URL,该URL用于建立从主机到Rancher Server的连接。这个URL必须可以从你的主机访问到。为了验证它,你需要登录到主机并执行curl命令:


curl -i /v1


你应该得到一个json响应。如果开启了认证,响应代码应为401。如果认证未打开,则响应代码应为200。

注意:普通的HTTP请求和websocket连接(ws://)都将被使用。如果此URL指向代理或负载平衡器,请确保它们可以支持Websocket连接。

#4、Kuberbetes UI显示Service unavailable

很多同学正常部署Kuberbetes环境后无法进入Dashboard,基础设施应用栈均无报错。但通过查看 基础架构|容器 发现并没有Dashboard相关的容器.因为Kuberbetes在拉起相关服务(如Dashboard、内置DNS等服务)是通过应用商店里面的YML文件来定义的,YML文件中定义了相关的镜像名和版本。

而Rancher部署的Kuberbetes应用栈属于Kuberbetes的基础框架,相关的镜像通过dockerhub/rancher 仓库拉取。默认Rancher-catalog Kuberbetes YML中服务镜像都是从谷歌仓库拉取,在没有科学上网的情况下,国内环境几乎无法成功拉取镜像。

为了解决这一问题,优化中国区用户的使用体验,在RANCHER v1.6.11之前的版本,我们修改了http://git.oschina.net/rancher/rancher-catalog仓库中的YML文件,将相关的镜像也同步到国内仓库,通过替换默认商店地址来实现加速部署;在RANCHER v1.6.11及之后的版本,不用替换商店catalog地址,直接通过在模板中定义仓库地址和命名空间就行实现加速;在后期的版本种,Kuberbetes需要的镜像都会同步到docker hub中。

安装方法见:《原生加速中国区Kubernetes安装》《Rancher-k8s加速安装文档》

Docker常见问题

#1、镜像下载慢,如何提高下载速度?


touch /etc/docker/daemon.json
cat >> /etc/docker/daemon.json < {
"insecure-registries": ["0.0.0.0/0"],
"registry-mirrors": ["https://7bezldxe.mirror.aliyuncs.com"]
}
EOF
systemctl daemon-reload && systemctl restart docker



PS:0.0.0.0/0 表示信任所有非https地址的镜像仓库,对于内网测试,这样配置很方便。对于线上生产环境,为了安全请不要这样配置


#2、如何配置Docker后端存储驱动?

以overlay为例


touch /etc/docker/daemon.json
cat >> /etc/docker/daemon.json < {
"storage-driver": "overlay"
}
EOF
systemctl daemon-reload && systemctl restart docker


#3、docker info 出现 WARNING


WARNING: No swap limit support
WARNING: No kernel memory limit support
WARNING: No oom kill disable support


编辑/etc/default/grub文件,并设置:`GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"`

接着

SUSE


grub2-mkconfig -o /boot/grub2/grub.cfg


Cetos


Update grub


Ubuntu


update-grub


#4、我怎么通过rancher让docker里的程序代理上网呢?

启动容器的时候,加一下


-e http_proxy= -e https_proxy=




#5、Docker错误:无法删除文件系统

一些基于容器的实用程序(例如Google cAdvisor)会将Docker系统目录(如/ var / lib / docker /)挂载到容器中。例如,cadvisor的文档指示您运行cadvisor容器,如下所示:


$ sudo docker run \
--volume=/:/rootfs:ro \
--volume=/var/run:/var/run:rw \
--volume=/sys:/sys:ro \
--volume=/var/lib/docker/:/var/lib/docker:ro \
--publish=8080:8080 \
--detach=true \
--name=cadvisor \
google/cadvisor:latest


当挂载/var/lib/docker/时,这会有效地将所有其他正在运行的容器的所有资源作为文件系统安装在挂载/var/lib/docker/的容器中。当您尝试删除这些容器中的任何一个时,删除尝试可能会失败,出现如下所示的错误:


Error: Unable to remove filesystem for
74bef250361c7817bee19349c93139621b272bc8f654ae112dd4eb9652af9515:
remove /var/lib/docker/containers/74bef250361c7817bee19349c93139621b272bc8f654ae112dd4eb9652af9515/shm:
Device or resource busy


如果将/var/lib/docker/在/var/lib/docker/中的文件系统句柄上使用statfsor或fstatfs并且不关闭它们的容器,就会发生此问题。

通常,我们会以这种方式建议禁止挂载/var/lib/docker。然而,cAdvisor的核心功能需要这个绑定挂载。

如果您不确定是哪个进程导致错误中提到的路径繁忙并阻止它被删除,则可以使用lsof命令查找其进程。例如,对于上面的错误:


sudo lsof /var/lib/docker/containers/74bef250361c7817bee19349c93139621b272bc8f65


原文来源:Rancher Labs

阿里云经典网络与Rancher VXLAN兼容性问题

Rancher 发表了文章 • 1 个评论 • 1996 次浏览 • 2017-09-12 12:34 • 来自相关话题

近期国内很多用户曝出在阿里云的环境中无法使用Rancher的VXLAN网络,现象是跨主机的容器无法正常通信,healthcheck服务一直无法更新正常状态。经过一系列走访排查,最终定位此现象只发生在阿里云的经典网络环境下。如果你也遭遇了同样的情况,请关注此文。 ...查看全部
近期国内很多用户曝出在阿里云的环境中无法使用Rancher的VXLAN网络,现象是跨主机的容器无法正常通信,healthcheck服务一直无法更新正常状态。经过一系列走访排查,最终定位此现象只发生在阿里云的经典网络环境下。如果你也遭遇了同样的情况,请关注此文。

阿里云经典网络部署最新的stable(v1.6.7)版本并启用VXLAN网络,使用经典网络的内网IP加入两台主机,现象如下:



Rancher的VXLAN网络除了VXLAN本身的机制外,还需要在IPtables中的RAW表中进行数据包标记,然后在Filter表中对标记数据包设置ACCEPT规则,进而实现容器跨主机通信。但是在阿里云经典网络环境中,无论如何配置安全组功能,RAW表中始终无法匹配进入主机栈的数据包。



依据“大胆假设,小心求证”的troubleshooting原则,首先我们验证了使用经典网络的公网IP注册主机,VXLAN并没有问题,这说明存在某种安全规则是作用在经典网络的内网IP的。



其次,我们知道Rancher VXLAN的实现是基于Linux kernel的VXLAN module,IPtables的数据包处理也基本是kernel处理,所以理论上讲肯定系统中存在权限更高的组件截获了VXLAN的数据,因为我们测试了在其他公有云环境并无此问题,考虑阿里云会对经典网络的内网安全做诸多限制,所以怀疑阿里云镜像内做了一些特殊的定制。

以过往使用阿里云的经验,我们对系统中内置的“安全加固”组件疑惑很大,尝试删除这个组件,可以使用这个脚本 http://update.aegis.aliyun.com/download/uninstall.sh ,但重启机器后发现VXLAN网络依然不通。无法确定是否存在删除不彻底的情况,所以重建环境并在创建VM时选择去掉“安全加固”选项。



重新添加主机,发现VXLAN一切恢复正常。



我们也正在尽力与阿里云官方取得联系,确认这种情况是否存在误杀。当前可选择的临时方案除了按照上面的说明删除“安全加固”组件外,还可以在创建VM的时候选择不使用安全加固镜像,这样Rancher VXLAN就可以正常工作。

在这里,非常感谢社区用户的热情发问,没有大家对技术专注的态度和刨根问底的精神,Rancher也无法真正发现问题的根源,Rancher会一如既往地接受用户的问题与需求,改进自身产品,真真正正能够提供一个有生产力的工具。

原文来源:Rancher Labs

9月27日,北京海航万豪酒店,容器技术大会Container Day 2017即将举行。

CloudStack之父、海航科技技术总监、华为PaaS部门部长、恒丰银行科技部总经理、阿里云PaaS工程总监、民生保险CIO······均已加入豪华讲师套餐!

11家已容器落地企业,15位真·云计算大咖,13场纯·技术演讲,结合实战场景,聚焦落地经验。免费参会+超高规格,详细议程及注册链接请戳

DockOne微信分享(一三八):白话Kubernetes网络

FanLin 发表了文章 • 0 个评论 • 5231 次浏览 • 2017-08-22 00:47 • 来自相关话题

【编者的话】容器的网络是在CaaS集群中无法避免的话题,作为当下最主流的一种容器集群解决方案,Kubernetes对网络进行了合理的抽象,并采用了开放的CNI模型。面对各种容器网络实现,他们有什么不同,应该如何选择?本文将带大家回顾Kubernetes各种主流 ...查看全部
【编者的话】容器的网络是在CaaS集群中无法避免的话题,作为当下最主流的一种容器集群解决方案,Kubernetes对网络进行了合理的抽象,并采用了开放的CNI模型。面对各种容器网络实现,他们有什么不同,应该如何选择?本文将带大家回顾Kubernetes各种主流网络方案的发展历程,并透过现象清本质,用形象的例子展示Weave、Flannel、Calico和Romana等网络解决方案背后的原理。

【3 天烧脑式基于Docker的CI/CD实战训练营 | 北京站】本次培训围绕基于Docker的CI/CD实战展开,具体内容包括:持续集成与持续交付(CI/CD)概览;持续集成系统介绍;客户端与服务端的 CI/CD 实践;开发流程中引入 CI、CD;Gitlab 和 CI、CD 工具;Gitlab CI、Drone 的使用以及实践经验分享等。

白话Kubernetes网络.001_.jpeg

这次讲一讲容器集群中的网络。其实不同的容器集群解决方案,在网络方面的核心原理都是相似的,只不过这次我们将以Kubernetes为线索,来窥斑见豹的一睹容器网络的发展过程。
白话Kubernetes网络.002_.jpeg

我是来自ThoughtWorks的林帆,我们从Docker的0.x版本开始就在对容器的应用场景进行探索,积累了一线的容器运用经验。这次分享会用简洁易懂的方式告诉大家我们对容器网络方面的一些知识归纳。
白话Kubernetes网络.003_.jpeg

初入容器集群的人往往会发现,和单节点的容器运用相比,容器的网络和存储是两个让人望而却步的领域。在这些领域里,存在大量的技术名词和术语,就像是一道道拒人于门外的高门槛。
白话Kubernetes网络.004_.jpeg

为了便于理解,我们将这些名称简单的分个类别,从简单到复杂,依次递增。今天的话题会涉及的深度大致在这个大池子的中间,希望大家看完以后会对目标线以上的内容不再陌生,目标线以下的内容我们也会依据需要适当的提及。
白话Kubernetes网络.005_.jpeg

此外,这个话题会按照Kubernetes的网络发现过程作为时间主线,其中重点介绍CNI标准和它的主流实现。
白话Kubernetes网络.006_.jpeg

在早期的Kubernetes中,对网络是没有什么标准的。文档中对网络的描述只有很简单的几句话,其实就是让用户在部署Kubernetes之前,预先准备好容器互联的网络解决方案。Kubernetes只对网络提出设计假设,这三条假设总结起来就是:所有容器都可以和集群里任意其他容器或者主机通信,并且通信双方看到的对方IP地址就是实际的地址(即不经过网络地址转换)。

基于这样的底层网络,Kubernetes设计了Pod - Deployment - Service的经典三层服务访问机制。

既然Kubernetes不提供底层网络实现,在业界就出现了很多企业级的以及开源的第三方解决方案,其中下面这页图中展示了这个时期的主流开源方案。
白话Kubernetes网络.007_.jpeg

我们将这些方案依据配置的复杂度,分为“全自动”和“半自动”两类,就像是汽车中的自动挡和手动挡的差别。

“全自动”的解决方案使用起来简单,适用于标准网络环境的容器跨节点通信。

“半自动”的解决方案实际上是对底层协议和内核模块功能的封装,提供了选择十分丰富的网络连接方法,但对使用者的网络原理知识有一定要求。
白话Kubernetes网络.008_.jpeg

在Kubernetes的1.1版本中,发生了一件很重要的变化,那就是Kubernetes全面采纳CNI网络标准。

CNI诞生于2015年4月,Kubernetes的1.1版本诞生于2015年9月,之间仅隔5个月。在这个时期,Docker也设计了一套网络标准,称为CNM(即Libnetwork)。Kubernetes采用CNI而非CNM,这背后有很长的一段故事,核心的原因就是CNI对开发者的约束更少,更开放,不依赖于Docker工具,而CNM对Docker有非常强的依赖,无法作为通用的容器网络标准。在Kubernetes的官方博客里有一篇博文详细讨论了个中细节,InfoQ上有一篇该博客的翻译,有兴趣的读者不妨一读。
白话Kubernetes网络.009_.jpeg

几乎在Kubernetes宣布采纳CNI以后的1个月,之前提到的“全自动”网络方案就悉数实现了CNI的插件,这也间接说明了CNI的简单。

那么CNI到底有多简单呢?举几个数字。

实现一个CNI插件需要的内容包括一个Json配置文件和一个可执行的文件(脚本或程序),配置文件描述插件的版本、名称、描述等基本信息,可执行文件就是CNI插件本身会在容器需要建立网络和需要销毁容器的时候被调用。

当一个CNI插件被调用时,它能够通过6个环境变量以及1个命令行参数(Json格式文本)来获得需要执行的操作、目标网络Namespace、容器的网卡必要信息,每个CNI插件只需实现两种基本操作:创建网络的ADD操作,和删除网络的DEL操作(以及一个可选的VERSION查看版本操作)。

最新的CNI规范可以通过上图中的链接访问,只有一页网页的内容而已。同时Kuberntes社区也提供了一个利用“docker network”命令实现的简单CNI插件例子,只用了几十行Bash脚本。
白话Kubernetes网络.010_.jpeg

那么面对这么多的社区CNI插件,我们怎样选择呢?

直观的说,既然是网络插件,在功能差不多的情况下,我们当然先关心哪个的速度快。

为此我此前专门做过一次对比测试,不过由于使用了公有云的网络环境(云上环境的不同主机之间相对位置不固定),在汇总数据的时候才发现测试结果偏离理论情况过于明显。

这个数据大家且当娱乐,不过对于同一种插件的不同工作模式(比如Flannel的三种模型)之间,由于是使用的相同的虚拟机测试,还是具有一定可参考性。

先抛开测试结果,从理论上说,这些CNI工具的网络速度应该可以分为3个速度等级。

最快的是Romana、Gateway模式的Flannel、BGP模式的Calico。

次一级的是IPIP模式的Calico、Swarm的Overlay网络、VxLan模式的Flannel、Fastpath模式的Weave。

最慢的是UDP模式的Flannel、Sleeve模式的Weave。
白话Kubernetes网络.012_.jpeg

这里我也提供出测试容器网络速度的具体方法,以便大家重复这个测试。
白话Kubernetes网络.013_.jpeg

要解释这些网络插件和模式速度不同的原因,我们需要先回到这些工具最初要解决的问题上来。那就是跨节点的网络不通。

如果仔细观察,会发现在3种网络速度模式中都有Flannel的身影。因此我们不妨先以Flannel为例来看这些网络工具(和相应的CNI插件)是如何解决网络不通问题的。
白话Kubernetes网络.014_.jpeg

跨节点网络不同有几个方面的原因,首先是容器的地址重复。

由于Docker等容器工具只是利用内核的网络Namespace实现了网络隔离,各个节点上的容器是在所属节点上自动分配IP地址的,从全局来看,这种局部地址就像是不同小区里的门牌号,一旦拿到一个更大的范围上看,就可能是会重复的。
白话Kubernetes网络.015_.jpeg

为了解决这个问题,Flannel设计了一种全局的网络地址分配机制,即使用Etcd来存储网段和节点之间的关系,然后Flannel配置各个节点上的Docker(或其他容器工具),只在分配到当前节点的网段里选择容器IP地址。

这样就确保了IP地址分配的全局唯一性。
白话Kubernetes网络.016_.jpeg

是不是地址不重复网络就可以联通了呢?

这里还有一个问题,是对于不同的主机、以及网络上的路由设备之间,并不知道这些IP容器网段的地址是如何分配的,因此数据包即使被发送到了网络中,也会因为无法进行路由而被丢掉。

虽然地址唯一了,依然无法实现真正的网络通信。
白话Kubernetes网络.017_.jpeg

为此,Flannel采用了几种处理方法(也就是Flannel的几种网络模式)。

早期时候用的比较多的一种方式是Overlay网络。

在这种方式下,所有被发送到网络中的数据包会被添加上额外的包头封装。这些包头里通常包含了主机本身的IP地址,因为只有主机的IP地址是原本就可以在网络里路由传播的。

根据不同的封包方式,Flannel提供了UDP和Vxlan两种传输方法。

UDP封包使用了Flannel自定义的一种包头协议,数据是在Linux的用户态进行封包和解包的,因此当数据进入主机后,需要经历两次内核态到用户态的转换。

VxLAN封包采用的是内置在Linux内核里的标准协议,因此虽然它的封包结构比UDP模式复杂,但由于所有数据装、解包过程均在内核中完成,实际的传输速度要比UDP模式快许多。

但比较不幸的是,在Flannel开始流行的时候,大概2014年,主流的Linux系统还是Ubuntu 14.04或者CentOS 6.x,这些发行版的内核比较低,没有包含VxLAN的内核模块。因此多数人在开始接触Flannel时候,都只能使用它的UDP模式,因此Flanned一不小心落得了一个“速度慢”的名声,特别是在之后的Calico出来以后(其实Flannel的Gateway模式与Calico速度相当,甚至理论上还要快一点点,稍后解释)。

这是第一种解决网络无法路由的方法。
白话Kubernetes网络.018_.jpeg

第二种思路是,既然在无法进行路由是因为网络中的节点之间没有路由信息,但Flannel是知道这个信息的,能不能把这个信息告诉网络上的节点呢?

这就是Flannel的Host-Gateway模式,在这种模式下,Flannel通过在各个节点上的Agent进程,将容器网络的路由信息刷到主机的路由表上,这样一来所有的主机就都有整个容器网络的路由数据了。

Host-Gateway的方式没有引入像Overlay中的额外装包解包操作,完全是普通的网络路由机制,它的效率与虚拟机直接的通信相差无几。

然而,由于Flannel只能够修改各个主机的路由表,一旦主机直接隔了个其他路由设备,比如三层路由器,这个包就会在路由设备上被丢掉。

这样一来,Host-Gateway的模式就只能用于二层直接可达的网络,由于广播风暴的问题,这种网络通常是比较小规模的,但近年来也出现了一些专门的设备能够构建出大规模的二层网络(就是我们经常听到的“大二层”网络)。

那么其他的CNI插件呢?

由于Flannel几乎是最早的跨网络通信解决方案,其他的方案都可以被看做是Fannel的某种改进版。
白话Kubernetes网络.019_.jpeg

比如Weave的工作模式与Flannel是很相似的,它最早只提供了UDP(称为sleeve模式)的网络方式,后来又加上了fastpass方式(基于VxLAN),不过Weave消除了Flannel中用来存储网络地址的额外组件,自己集成了高可用的数据存储功能。
白话Kubernetes网络.020_.jpeg

Calico的设计比较新颖,之前提到Flannel的Host-Gateway模式之所以不能跨二层网络,是因为它只能修改主机的路由,Calico把改路由表的做法换成了标准的BGP路由协议。

相当于在每个节点上模拟出一个额外的路由器,由于采用的是标准协议,Calico模拟路由器的路由表信息就可以被传播到网络的其他路由设备中,这样就实现了在三层网络上的高速跨节点网络。

不过在现实中的网络并不总是支持BGP路由的,因此Calico也设计了一种IPIP模式,使用Overlay的方式来传输数据。IPIP的包头非常小,而且也是内置在内核中的,因此它的速度理论上比VxLAN快一点点,但安全性更差。
白话Kubernetes网络.021_.jpeg

Cannal将Calico和Flannel做了一下组合,同时支持两者的特性。
白话Kubernetes网络.022_.jpeg

Romana只支持与Flannel相同的Host-Gateway模式,但它在网络策略方面做了比较多的增强,通过额外引入的租户概念简化了网络策略所需的IPtables规则数量。
白话Kubernetes网络.023_.jpeg

这是几种主流CNI工具的横向对比。
白话Kubernetes网络.024_.jpeg

在Kubernetes的1.2版本以后开始引入了一个新的工具,叫做 kubernet,它实现了内置的网络地址分配功能。结合一些云平台上的内网路由表功能,就能够直接执行跨网络通信,相当于把跨网络功能内建到Kubernetes里面了。

这是一个从“只做假设”到“设定标准”到“内置实现”的很大的改变。
白话Kubernetes网络.025_.jpeg

在Kubernetes的1.3版本以后,开始加入网络策略相关的支持。并且在1.7版本后结束了Beta阶段,成为正式API的一部分。

值得一说的是,Kubernetes的网络策略采用了比较严格的单向流控制,即假如允许服务A访问服务B,反过来服务B并不一定能访问服务A。这与Docker内置的Network命令实现的隔离有很大不同。
白话Kubernetes网络.026_.jpeg

纵向的对比一下主流的容器集群对今天提到的这些网络特性的支持情况和时间点。
# Q&A
Q:Kubernetes的网络策略采用了比较严格的单向流控制,即假如允许服务A访问服务B,反过来服务B并不一定能访问服务A。为什么要设计成严格单向流呢?

A:主要是安全性的原因,这是一种更精细的权限控制策略,除了方向,Kuberetes还允许对可访问的端口进行控制。



Q:Open vSwitch有测过么?

A:没有测试,Open vSwitch同样可以配置成Overlay网络或者Macvlan网络等不同的通信模式,速度也会落到相应的档位上。那个测试例子只是为了说明网络速度与采用的通信原理有关,同时引出几种主流的通信模式原理,测试数据是不准确的,建议以在自己的实际环境中测试结果为准。



Q:Calico怎么做网段间的隔离?

A:各种网络工具的网络策略基本上都是基于内核的Iptables模块实现的。比如Calico只是根据用户配置,自动管理各个节点上的Iptables规则。其他有些改进的,比如Romana设计了一种基于“租户”的规则管理机制,可以用更少的Iptables规则实现网络隔离。



Q:如果在Kubernetes里面需要做到平行网络,让每一个Pod获取一个业务IP,除了Bridge+Vlan的方式,还有更好的建议么?

A:这次讲的这些CNI插件都会让每一个Pod获得一个独立业务IP。可以根据实际网络情况和对速度的需求选择。



Q:Calico BGP IPIP NAT三种模式分别怎么配置?原理是怎样的?其中IPIP还有两种模式,区别在哪?

A:在Calico的配置中设置`spec.ipip.enabled: ture`就会开启IPIP模式,否则默认是纯BGP模式。IPIP的两种模式其实是指纯IPIP(ipip always模式)或者混合IPIP和BGP(ipip cross-subnet),后者指的是“同子网内路由采用BGP,跨子网路由采用IPIP”,主要用于即想在内网获得高速,又想在跨公网时能保持联通的情况。这种模式需要每个节点启动时用`--ip`参数预先配置节点的子网,并且所有节点版本都在v2.1以上。



Q:能麻烦具体介绍一下kube-proxy这种网络模式的优缺点吗,在测试过程中发现很不稳定,但是又没发现足够的证据。

A:kube-proxy是Kubernetes的一个组件,提供通过Service到Pod的路由,并不是一种网络模式,不同的网络插件都会使用到这个组件。



以上内容根据2017年08月15日晚微信群分享内容整理。分享人林帆,ThoughtWorks DevOps和容器技术咨询师。从事软件开发运维以及社区宣传工作,热衷于对DevOps和容器技术应用的推广,在容器规模化运维方面有较丰富实践经验,著有《CoreOS实践之路》一书。 DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesa,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

容器网络——从CNI到Calico(360搜索)

man4acs 发表了文章 • 0 个评论 • 8344 次浏览 • 2017-08-07 10:51 • 来自相关话题

从容器诞生开始,存储和网络这两个话题就一直为大家津津乐道。我们今天这个环境下讲网络这个问题,其实是因为容器对网络的需求,和传统物理、虚拟环境对网络环境需求是有差别的,主要面临以下两个问题: 过去IaaS层在网络方便做了很多工作,已经形 ...查看全部
从容器诞生开始,存储和网络这两个话题就一直为大家津津乐道。我们今天这个环境下讲网络这个问题,其实是因为容器对网络的需求,和传统物理、虚拟环境对网络环境需求是有差别的,主要面临以下两个问题:

  • 过去IaaS层在网络方便做了很多工作,已经形成了成熟的环境,如果和容器环境适配,两边都需要做很多改造
  • 容器时代提倡微服务,导致容器的粒度之小,离散程度之大,原有IaaS层网络解决方案很难承载如此复杂的需求
我们来看下一些主流的容器网络接入方案:# Host network最简单的网络模型就是让容器共享Host的network namespace,使用宿主机的网络协议栈。这样,不需要额外的配置,容器就可以共享宿主的各种网络资源。# 共享物理网卡这种接入方式主要使用SR-IOV技术,每个容器被分配一个VF,直接通过PCIe网卡与外界通信。SR-IOV 技术是一种基于硬件的虚拟化解决方案,可提高性能和可伸缩性。SR-IOV 标准允许在虚拟机之间高效共享 PCIe设备,并且它是在硬件中实现的,可以获得能够与本机性能媲美的 I/O 性能。启用了 SR-IOV 并且具有适当的硬件和 OS 支持的 PCIe 设备(例如以太网端口)可以显示为多个单独的物理设备,每个都具有自己的 PCIe 配置空间。SR-IOV主要用于虚拟化中,当然也可以用于容器:
1.png
SR-IOV配置(需要网卡支持,线上主流万兆卡Intel 540可以支持128个VF(Virtual Function)):
modprobe ixgbevflspci -Dvmm|grep -B 1 -A 4 Ethernetecho 2 > /sys/bus/pci/devices/0000:82:00.0/sriov_numvfs # check ifconfig -a. You should see a number of new interfaces created, starting with “eth”, e.g. eth4
Intel也给Docker实现了一个SR-IOV network plugin,同样也有相应的CNI(后面会提到)Plugin。SR-IOV的接入方式可以达到物理网卡的性能,但是需要硬件支持,而且VF的数量是有限的。# 共享容器网络多个容器共享同一个netns,只需要第一个容器配置网络。比如Kubernetes Pod就是所有容器共享同一个pause容器的网络。# VSwitch/Bridge容器拥有独立的network namespace,通过veth-pair连接到VSwitch或者Bridge上。容器网络技术日新月异,有些相当复杂,而且提供某种功能的方式也多种多样。这样就给容器runtime与调度系统的实现与各种接入方式的适配带来的很大的困难。为了解决这些问题,Docker与CoreOS相继发布了容器网络标准,便是CNM与CNI,为Linux容器网络提供了统一的接口。先来看下CNM:
2.png
Libnetwork是CNM的原生实现。它为Docker daemon和网络驱动程序之间提供了接口。网络控制器负责将驱动和一个网络进行对接。每个驱动程序负责管理它所拥有的网络以及为该网络提供的各种服务,例如IPAM等等。由多个驱动支撑的多个网络可以同时并存。网络驱动可以按提供方被划分为原生驱动(libnetwork内置的或Docker支持的)或者远程驱动 (第三方插件)。原生驱动包括 none、bridge、overlay 以及 MACvlan。驱动也可以被按照适用范围被划分为本地(单主机)的和全局的 (多主机)。
3.png
  • Sandbox:一个Sandbox对应一个容器的网络栈,能够对该容器的interface、route、dns等参数进行管理。一个Sandbox中可以有多个Endpoint,这些Endpoint可以属于不同的Network。Sandbox的实现可以为linux network namespace、FreeBSD Jail或其他类似的机制。
  • Endpoint: Sandbox通过Endpoint接入Network,一个Endpoint只能属于一个Network。Endpoint的实现可以是veth pair、Open vSwitch internal port或者其他类似的设备。
  • Network:一个Network由一组Endpoint组成,这些Endpoint彼此间可以直接进行通信,不同的Network间Endpoint的通信彼此隔离。Network的实现可以是linux bridge、Open vSwitch等。
我们可以以Docker操作为例,简单看下CNM创建容器的工作流:
  • Create Network(docker network create)
- IpamDriver.RequestPool:创建subnetpool用于分配IP - IpamDriver.RequestAddress:为gateway获取IP - NetworkDriver.CreateNetwork:创建network和subnet
  • Create Container(docker run / docker network connect)
- IpamDriver.RequestAddress:为容器获取IP - NetworkDriver.CreateEndpoint:创建port - NetworkDriver.Join:为容器和port绑定 - NetworkDriver.ProgramExternalConnectivity - NetworkDriver.EndpointOperInfoCNM与libnetwork相对比较复杂,这里不做详细介绍,相关内容可参考libnetwork的Design Doc。再看下CNI:
4.png
其基本思想为:Container Runtime在创建容器时,先创建好network namespace,然后调用CNI插件为这个netns配置网络,其后再启动容器内的进程。CNI插件包括两部分:
  • CNI Plugin负责给容器配置网络,它包括两个基本的接口
- 配置网络:AddNetwork(net NetworkConfig,rt RuntimeConf)(types.Result,error) - 清理网络:DelNetwork(net NetworkConfig, rt RuntimeConf) error
  • IPAM Plugin负责给容器分配IP地址,实现包括host-local和dhcp等
再来看下CNI创建容器的工作流:
  • 容器runtime分配一个网络命名空间以及一个容器ID
  • 连同一些CNI配置参数传给网络驱动
  • 网络驱动会将该容器连接到网络并将分配的IP地址以JSON的格式返回给容器runtime
所有CNI插件均支持通过环境变量和标准输入传入参数:
$ echo '{"cniVersion": "0.3.1","name": "mynet","type": "macvlan","bridge": "cni0","isGateway": true,"ipMasq": true,"ipam": {"type": "host-local","subnet": "10.244.1.0/24","routes": [{ "dst": "0.0.0.0/0" }]}}' | sudo CNI_COMMAND=ADD CNI_NETNS=/var/run/netns/a CNI_PATH=./bin CNI_IFNAME=eth0 CNI_CONTAINERID=a CNI_VERSION=0.3.1 ./bin/bridge$ echo '{"cniVersion": "0.3.1","type":"IGNORED", "name": "a","ipam": {"type": "host-local", "subnet":"10.1.2.3/24"}}' | sudo CNI_COMMAND=ADD CNI_NETNS=/var/run/netns/a CNI_PATH=./bin CNI_IFNAME=a CNI_CONTAINERID=a CNI_VERSION=0.3.1 ./bin/host-local
直观的来看,CNI 的规范比较小巧。它规定了一个容器runtime和网络插件之间的简单的契约(详细内容请参考SPEC)。在斟酌某项技术的时候,我们需要考虑采纳的成本;是否会增加对供应商的依赖。社区的采纳程度和支持程度也是比较重要的考量。插件开发者还需要考虑哪种方式相对比较容易实现。目前,主流容器调度框架(Mesos、Kubernetes)与网络解决方案(Calico、Flannel等)都对CNI有良好的支持,另外其简单的接口使插件的开放成本很低;并且不依赖docker runtime,使容器解决方案有了更多选择(例如Mesos Containerizer)。所以,我们选择了CNI。在对比业内支持CNI接口的主流网络解决方案之前,需要对多主机条件下,容器的组网方案做下分类,来方便大家理解不同解决方案之间的区别:##Flat
  • L2 Flat
- 各个host中容器在虚拟与物理网络形成的VLAN(大二层)中 - 容器可以在任意host间迁移不用改变其IP - 不同租户IP不可Overlap
  • L3 Flat
- 各个host中容器在虚拟与物理网络中可路由,且为32位路由 - 因为是32位路由,所以容器在任意host间迁移不用改变IP - 不同租户IP不可Overlap,容器与物理网络IP也不可Overlap
5.png
##L3 Hierarchy - 各个host中容器在虚拟与物理网络中可路由 - 路由在不同层次上(VM/Host/Leaf/Spine)以聚合路由的形式存在 - 相同CIDR的容器需在物理上被组织在一起 - 容器在host间迁移需要改变IP - 不同租户IP不可Overlap,容器与物理网络IP也不可Overlap
6.png
##Overlay
  • L2 over L3
- 容器可跨L3 Underlay进行L2通信 - 容器可在任意host间迁移而不改变其IP
7.png
  • L3 over L3
- 容器可跨L3 Underlay进行L3通信 - 容器可在任意host间迁移可能需要改变其IP - 不同租户IP可Overlap,容器IP也可与Underlay网络Overlap下面我们来看下社区比较认可的几种容器网络解决方案。# Flannel通过给每台宿主机分配一个子网的方式为容器提供虚拟网络,它基于Linux TUN/TAP,使用UDP封装IP包来创建overlay网络,并借助etcd维护网络的分配情况。控制平面上host本地的flanneld负责从远端的ETCD集群同步本地和其它host上的subnet信息,并为POD分配IP地址。数据平面flannel通过Backend(比如UDP封装)来实现L3 Overlay,既可以选择一般的TUN设备又可以选择VxLAN设备。
8.png
从上图可以看出,Flannel是典型的L3 over L3组网方案。支持的Backend:
  • udp:使用udp封装,默认使用8285端口
  • vxlan:vxlan封装,需要配置VNI,Port(默认8472)和GBP
  • host-gw:直接路由的方式
  • 公有云vpc:aws-vpc、gce、ali-vpc
如上图,可以方便的与Docker集成:
source /run/flannel/subnet.envdocker daemon --bip=${FLANNEL_SUBNET} --mtu=${FLANNEL_MTU} &
也提供CNI接口:CNI插件会将flannel网络配置转换为bridge插件配置,并调用bridge插件给容器netns配置网络。比如下面的flannel配置:
 {    "name": "mynet",    "type": "flannel",    "delegate": {        "bridge": "mynet0",        "mtu": 1400    }} 
会被插件转换为:
 {    "name": "mynet",    "type": "bridge",    "mtu": 1472,    "ipMasq": false,    "isGateway": true,    "ipam": {        "type": "host-local",        "subnet": "10.1.17.0/24"    }} 
Flannel便是通过CNI与Mesos、Kubernetes集成。由于历史原因,我们线上Kubernetes集群是通过前一种方式直接与Docker集成的。优点:
  • 配置安装简单,使用方便
  • 与公有云集成方便,VPC方式无Overhead
缺点:
  • Vxlan模式对平滑重启支持不好(重启需要数秒来刷新ARP表,且不可变更配置,例如VNI、iface)
  • 功能相对简单,不支持Network Policy
  • Overlay存在一定Overhead
# Weave不同于其它的multi-host方案,其支持去中心化的控制平面,各个host上的wRouter间通过建立Full Mesh的TCP链接,并通过Gossip来同步控制信息。这种方式省去了集中式的K/V Store,能够在一定程度上减低部署的复杂性。不过,考虑到docker libnetwork是集中式的K/V Store作为控制平面,因此Weave为了集成docker,它也提供了对集中式控制平面的支持,能够作为docker remote driver与libkv通信。数据平面上,Weave通过UDP封装实现L2 Overlay,封装支持两种模式:
  • 运行在user space的sleeve mode:通过pcap设备在Linux bridge上截获数据包并由wRouter完成UDP封装,支持对L2 traffic进行加密,还支持Partial Connection,但是性能损失明显。
9.png
  • 运行在kernal space的 fastpath mode:即通过OVS的odp封装VxLAN并完成转发,wRouter不直接参与转发,而是通过下发odp 流表的方式控制转发,这种方式可以明显地提升吞吐量,但是不支持加密等高级功能。
10.png
- 所有容器都连接到Weave网桥 - weave网桥通过veth pair连到内核的OpenVSwitch模块 - 跨主机容器通过openvswitch vxlan通信 - policy controller通过配置iptables规则为容器设置网络策略关于Service的发布,Weave做的也比较完整。首先,wRouter集成了DNS功能,能够动态地进行服务发现和负载均衡,另外,与libnetwork 的overlay driver类似,weave要求每个容器有两个网卡,一个就连在lb/ovs上处理L2 流量,另一个则连在docker0上处理Service流量,docker0后面仍然是iptables作NAT。同事,提供了一个容器监控和故障排查工具Weave Scope,可以方便的生成整个集群的拓扑并智能分组。优点:去中心化、故障自愈、加密通讯、支持组播缺点:
  • sleeve mode性能损耗巨大
  • full mesh模型限制了集群规模
  • Partial Connection在fastpath未实现
# Contiv思科开源的容器网络方案,是一个用于跨虚拟机、裸机、公有云或私有云的异构容器部署的开源容器网络架构,并与主流容器编排系统集成。Contiv最主要的优势是直接提供了多租户网络,并支持L2(VLAN),L3(BGP),Overlay(VXLAN)以及思科自家的ACI。主要由两部分组件组成:
  • Netmaster
- 对外提供REST API - 学习并分发路由到Netplugin - 管理集群资源(IP、VLAN、VXLAN ID等)
  • Netplugin
- 运行在集群中每个节点上 - 实现了CNI与CNM接口 - 通过REST方式与Netmaster通讯,监听事件,并做相应网络配置 - 数据平面使用OVS实现(插件架构,可替换,例如VPP、BPF)
11.png
优点:
  • 支持多种组网方式,集成现有SDN方案
  • 多租户网络混部在同一台主机上
  • 插件化的设计,可替换的数据平面
  • 即时生效的容器网络Policy/ACL/QoS规则
  • 基于OVS的高性能Load Balancer的支持
  • 清晰的设计,方便二次开发
缺点:
  • 功能丰富带来的副作用便是配置和使用比较复杂
  • 因为发展时间较短,社区和文档都不怎么成熟,也存在一些bug,稳定性有待商榷
  • CNI plugin对Mesos支持不友好(跟Cisco官方沟通后,对Mesos支持仍在POC阶段)
# OpenContrail是Juniper推出的开源网络虚拟化平台,其商业版本为Contrail。OpenContrail主要由控制器和vRouter组成:
  • 控制器提供虚拟网络的配置、控制和分析功能
  • vRouter提供分布式路由,负责虚拟路由器、虚拟网络的建立以及数据转发
vRouter支持三种模式:
  • Kernel vRouter:类似于ovs内核模块
  • DPDK vRouter:类似于ovs-dpdk
  • Netronome Agilio Solution (商业产品):支持DPDK, SR-IOV and Express Virtio (XVIO)
12.png
从上图可以看出,OpenContrail的架构是相当复杂的。相应的,其提供的feature基本覆盖了前所有提到的方案;甚至包括基于Cassandra后端的流量采样与分析平台;由于篇幅所限,这里不做详细介绍,相关内容可参考Arch Doc。计算机科学的先驱David Wheeler曾经说过——“Any problem in computer science can be solved with another level of indirection.”, SDN即是Network的indirection。容器网络解决方案多不胜数,我们在这里就不一一介绍了。但是我们可以看到,每种方案其实都是对network做了不同程度的indirection,但是不要忘了后面还有一句——“except of course for the problem of too many indirections”,所以大家在不同的方向上做出了取舍与权衡。正如前面所提到的,在斟酌某项技术的时候,我们需要考虑采纳成本、对供应商的依赖、社区的支持程度等等。我们正在如此权衡之后,并没选择上面的方案,而是选择了Calico,下面我会详细说明。# CalicoCalico 是一个纯三层的数据中心网络方案(不需要Overlay),并且与OpenStack、Mesos、Kubernetes、AWS、GCE等IaaS和容器平台都有良好的集成。Calico是一个专门做数据中心网络的开源项目。当业界都痴迷于Overlay的时候,Calico实现multi-host容器网络的思路确可以说是返璞归真——pure L3,pure L3是指容器间的组网都是通过IP来完成的。这是因为,Calico认为L3更为健壮,且对于网络人员更为熟悉,而L2网络由于控制平面太弱会导致太多问题,排错起来也更加困难。那么,如果能够利用好L3去设计数据中心的话就完全没有必要用L2。不过对于应用来说,L2无疑是更好的网络,尤其是容器网络对二层的需求则更是强烈。业界普遍给出的答案是L2 over L3,而Calico认为Overlay技术带来的开销(CPU、吞吐量)太大,如果能用L3去模拟L2是最好的,这样既能保证性能、又能让应用满意、还能给网络人员省事,看上去是件一举多得的事。用L3去模拟L2的关键就在于打破传统的Hierarchy L3概念,IP不再以前缀收敛,大家干脆都把32位的主机路由发布到网络上,那么Flat L3的网络对于应用来说即和L2一模一样。这个思路不简单,刨了L2存在必要性的老底儿,实际上如果不用考虑可扩展性、隔离性,IP地址和MAC地址标识endpoint的功能上确实是完全冗余的,即使考虑可扩展性,一个用L3技术形成的大二层和一个用L2技术形成的大二层并没有本质上的差距。而且,L3有成熟的、完善的、被普遍认可接受的控制平面,以及丰富的管理工具,运维起来要容易的多。于是,Calico给出了下面的设计:
13.png
Calico在每一个计算节点利用Linux Kernel实现了一个高效的vRouter来负责数据转发,而每个vRouter通过BGP协议负责把自己上运行的workload的路由信息向整个Calico网络内传播—,路由条目全是/32的v4或者/128的v6。小规模部署可以直接互联,大规模下可通过指定的BGP route reflector来完成。 这样保证最终所有的workload之间的数据流量都是通过IP路由的方式完成互联的。Calico节点组网可以直接利用数据中心的网络结构(无论是L2或者L3),不需要额外的NAT,隧道或者Overlay Network。
14.png
此外,Calico基于iptables还提供了丰富而灵活的网络Policy,保证通过各个节点上的ACLs来提供Workload的多租户隔离、安全组以及其他可达性限制等功能。另外,对CNM与CNI的支持使其可以方便适配绝大多数场景。这里有必要说明下,CNI和CNM并非是完全不可调和的两个模型。二者可以进行转化的,calico项目最初只支持CNI,后面才加入CNM的支持。从模型中来看,CNI中的container应与CNM的sandbox概念一致,CNI中的network与CNM中的network一致。在CNI中,CNM中的endpoint被隐含在了ADD/DELETE的操作中。CNI接口更加简洁,把更多的工作托管给了容器的管理者和网络的管理者。从这个角度来说,CNI的ADD/DELETE接口其实只是实现了docker network connectdocker network disconnect两个命令。类似的,kubernetes/contrib项目提供了一种从CNI向CNM转化的过程,这里就不做详细介绍了。我们详细看下Calico中的各个组件:
  • Felix:Calico Agent,跑在每台需要运行Workload的节点上,主要负责通过iptables来配置ACLs
  • etcd:分布式键值存储,主要负责网络元数据一致性,确保Calico网络状态的准确性
  • confd:根据etcd上状态信息,与本地模板,生成并更新BIRD配置
  • BGP Client(BIRD):主要负责容器的路由信息分发到当前Calico网络,确保Workload间的通信的有效性
  • BGP Route Reflector(BIRD):大规模部署时使用,摒弃所有节点互联的 mesh 模式,通过一个或者多个BGP Route Reflector来完成集中式的路由分发
这个架构,技术成熟、高性能、易维护,看起来是生产级别的容器网络环境最好的选择。但是,也有不如意的地方:
  • 没有了外面的封装,就谈不上VRF,多租户的话地址没法Overlap
  • L2和L3的概念模糊了,那么network级别的安全就难以实现,port级别的安全实现难是因为需要的规则都是1:1的,数量太多
上面并不是什么严重的问题。但是有一点,Calico控制平面的上述设计中,物理网络最好是L2 Fabric,这样vRouter间都是直接可达的,路由不需要把物理设备当做下一跳。如果是L3 Fabric,控制平面的问题就来了:物理设备如果要存32位的路由,路由表将变得巨大无比。因此,为了解决以上问题,Calico不得不采取了妥协,为了支持L3 Fabric,Calico推出了IPinIP的选项,用作cross-subnet下容器间通讯,但是有一定性能损耗。另一种方案是回退到L3 Hierarchy(calico目前支持),如果对容器迁移保持IP不变的需求不大,可以选择这种,这也是我们最后选择的方案。不过,对于使用L2 Fabric、没有多租户需求的企业来说,用calico上生产环境应该最理想选择。Calico最理想的部署方式是基于L2 Fabrics的,官方也有相应说明(Calico over an Ethernet interconnect fabric),这里就不做详细说明了。由于我们数据中心规模比较大,显然L2 Fabrics不是理想的选择。事实也是如此,我们多个数据中心组成的网络是以BGP为控制层面组成的L3 Fabrics。每个数据中心为一个AS。这里不讨论跨数据中心的问题,大家只需知道我们跨数据中心在L3上是互通的便可以。官方给出了3种基于L3 Fabrics的组网建议(详细介绍可点击进去查看):AS per Rack这种模型在每个ToR下加入了RR(Route Reflector),关于RR,前面有提到过,这里有必要解释一下:首先说下BGP的水平分割原则(这里只谈IBGP),从IBGP学习到的路由绝不对再传播给其它的IBGP邻居(可以传给EBGP邻居)。IBGP水平分割主要是为了防止在AS内部产生路由环路。所以,为了AS内路由正确收敛,需要所有节点组成full mesh结构(也就是两两之间建立邻居)。但是,这种架构在大型网络中显然行不通。另一种解决方案便是RR,一种C/S模型。在同AS内,其中一台设备作为RR,其他设备作为Client。Client与RR之间建立IBGP连接。路由反射器和它的客户机组成一个Cluster。这里不详细讨论RR的工作原理。显然,路由反射破坏了水平分割的原则,所以便要许多额外的配置来防止环路,这会给实际部署过程带来很多负担。另外,我们同一数据中心内运行的是IBGP,也就是都在同AS内。这使的配置改造更为复杂,而且,显然不符合AS per Rack。另外两种模型同样要求每个ToR在不同的AS,也面临上述问题。另外,如果不在ToR上做路由聚合,AS per Compute Server会造成Linux服务器上有全网的路由,庞大的路由表也会成为性能的瓶颈。经过与网络部门的认真研讨,我们最终选择了下面的部署模型:
15.png
  • 每个Server选择不同的AS号,且与数据中心AS不同,与ToR建立EBGP邻居
  • Server使用原有网关(默认路由),ToR不向Server宣告任何路由条目
  • Server本地聚合路由到28位,并宣告给ToR
  • 与网络部门制定一定算法(方便自动化),用Server的IP地址计算出AS号

可以看到,上述方案,几乎不用对数据中心现有网络架构做出改变;而且,也大大减少了Server与ToR上路由条目数。

实际部署Calico的Agent时,我们还遇到了一些问题:官方默认只提供基于Docker的部署方式,也就是之前提到的几个组件都部署在一个Docker容器中。calicoctl也是基于Docker容器做部署操作。但是,实际环境中,我们线上的Mesos集群有部分是只是用Mesos Containerizer的,也就是并没有Docker环境;而且,我们认为,Calico Agent加入对Docker daemon的依赖,考虑到稳定性,显然不是一个良好的选择。

所以,我们对Calico组件进行拆解,重新拼装,并去掉我们用不到IPv6模块;最终通过systemd在每台server上运行bird、confd、felix这三个模块,实现了去Docker化的部署(实际上对confd的模板也做了些改造,去掉了IPinIP的支持,并且适配的非Docker环境)。整个过程基于Ansible,实现了一键部署。

关于性能问题,虽然Calico在众多基于软件的容器网络解决方案里是性能最好的,但是也不是完全没有性能损耗。前面说过,Calico实现namespace内外通讯是通过linux内核的veth pair来实现的(就是之前提到的接入方式中的VSwitch/Bridge)。确实增加了一层overhead,但是好在veth pair的实现比较简单,性能损耗几乎可以忽略(无policy条件下)。我们实际测试中,对于echo server(小报文测试),请求延迟会增加0.02到0.04ms;对于bandwidth(大报文测试,万兆环境),很难看到差别。

到了这一步,你可能觉得我们大功告成,实则不然。其实我们还有很多事情可以做,也需要去做。Calico支持丰富的安全策略,但是在server上是用kernel的netfilter实现的(iptables),大量policy下的性能仍有待考察。

业内也有一些其他的实现思路,例如Google大力支持cilium方案,其policy的实现就用了BPF(Berkeley Packet Filter,最早在kernel 3.15中加入,4.8版本以后标为stable)。BPF的基本思路是把用作包处理的代码通过llvm编译成ir,然后插入到正在运行的kernel网络栈中,通过jit方式执行,大幅度提高了处理能力。这里不做详细介绍,相关信息可以看这里。cilium还加入了对XDP的支持(一种类似DPDK的技术,但是目前集成在kernel中),来加速网络栈的处理。这些都不失为未来改造calico的一个方向。

另外一个问题是,calico目前并没有对traffic shaping的支持。试想,当大量容器运行与同一物理机,其进出流量都共享物理网卡,如果不对容器流量进行限制,单个容器过分使用网络资源就会影响其他容器提供服务(磁盘IO也有同样问题,但是不在本文讨论范围)。Calico社区目前也在讨论这个问题,详情可见这个issue,目前还在API制定的阶段。

上述问题,底层实现目前可行选择是linux自带的tc(OVS同样用到了tc)。上层切入点却有两个选择,一是拓展Calico的API,在felix上实现应用tc规则的逻辑;另一种是在CNI plugin上hook,通过相应的调度系统,传参数进来,由plugin来应用tc规则。由于,calico社区已经在讨论这个问题,而且第二种方案实现起来成本也比较低。现阶段,我们只考虑方案二,也做了相应的POC。

实践过程中,由于veth pair两端的流量是相反的(ingress与egress),理论上可以在两端的egress上应用tc规则(tc只支持egress方向的shaping),来实现两个方向上的QoS。但是,我们还是遇到了一些问题,namespace内的虚拟网卡上的tc规则虽然可配置,但是并不生效。而且,这些规则对容器内应用是可见、可修改的,这样做也并不安全。所以,我们用到了ifb内核模块,把物理机上虚拟网卡的ingress流量变成egress,最终在在ifb网卡上应用tc规则,来实现容器egress方向的QoS。关于ifb,功能比较简单,大家可以看下kernel代码中相关的介绍:
/* drivers/net/ifb.c:

The purpose of this driver is to provide a device that allows
for sharing of resources:

1) qdiscs/policies that are per device as opposed to system wide.
ifb allows for a device which can be redirected to thus providing
an impression of sharing.

2) Allows for queueing incoming traffic for shaping instead of
dropping.

The original concept is based on what is known as the IMQ
driver initially written by Martin Devera, later rewritten
by Patrick McHardy and then maintained by Andre Correa.

You need the tc action mirror or redirect to feed this device
packets.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version
2 of the License, or (at your option) any later version.

Authors: Jamal Hadi Salim (2005)

*/

迫于篇幅限制,这次就先到这里吧,后续我会把一些详细实现拿出来给大家分享,欢迎共同交流。

看了上面这么多,有人可能会问,我们做了这么多工作,究竟是为了什么。回过头来看今天,我们理所当然的用着方便的跨数据中心环网、接入负载均衡、共享存储、对象存储,甚至到上层的云平台等等。正是因为有了这些,业务们拿出编译好的代码,快的不到几分钟就可以被线上的用户所使用。

这就是基础设施,这些是这座大楼的地基。正因为如此,基础设施的改造才异常困难。我们需要用合理的抽象来解决顽疾,更需要对上层建筑的兼容。正如我们在网络方面所做的工作,让容器和现有物理设备在三层上的互通,实现了网络上对业务的透明;同时又提供了良好的性能,消除了业务迁移到云平台上的顾虑;在提高资源利用率的混部环境下,同时提供可配置的策略,为服务质量提供了有效的保障。

作者:郝一昕,来自360搜索私有云团队

同程容器云平台网络方案演进

李颖杰 发表了文章 • 0 个评论 • 2650 次浏览 • 2017-07-26 22:53 • 来自相关话题

【编者的话】同程旅游PaaS平台是从2014年开始搭建的,到现在已经持续发展了三个年头。规模从原来的几百个容器到现在上万个容器。在容器调度上从原来的手动操作到现在的自动伸缩与扩容,在宿主机部署密度上从原来的十几个容器到现在上百个容器……我们的PaaS云平台在三 ...查看全部
【编者的话】同程旅游PaaS平台是从2014年开始搭建的,到现在已经持续发展了三个年头。规模从原来的几百个容器到现在上万个容器。在容器调度上从原来的手动操作到现在的自动伸缩与扩容,在宿主机部署密度上从原来的十几个容器到现在上百个容器……我们的PaaS云平台在三年间进行了3次大版本的迭代。本文主要介绍同程旅游PaaS云平台在持续集成和持续部署方面,基于Docker对网络方案的选型及应用,以及随着业务需求的增加而经历的网络方案变更过程。

【3 天烧脑式基于Docker的CI/CD实战训练营 | 北京站】本次培训围绕基于Docker的CI/CD实战展开,具体内容包括:持续集成与持续交付(CI/CD)概览;持续集成系统介绍;客户端与服务端的 CI/CD 实践;开发流程中引入 CI、CD;Gitlab 和 CI、CD 工具;Gitlab CI、Drone 的使用以及实践经验分享等。
#系统的初始形态
PaaS平台最初是基于Swarm搭建的,Swarm是Docker公司推出的一套容器调度平台。它的特点是简单易用,部署方便,学习成本低,因为它所有的命令和Docker命令基本上是一致的。容器有4种网络模式Bridge、Host、Container以及None ,开始我们使用的网络方案是Host模式,这种模式下,容器没有独立的IP网络栈,它共用了宿主机的IP地址。为了防止端口冲突,应用对外暴露服务的时候,需要指定端口,并且这个端口在同一宿主机上唯一(不然会冲突),然后再对接负载均衡器,这样就打通了整个网络链路。整个架构非常简洁,对于当时每天几十个容器以及无状态的应用,是能够完全满足需要的。

网络访问流程如下所示:
001.png

后来随着业务的发展,各种业务也慢慢的容器化,比如说Redis、Hadoop、Database、中间件等等。Host模式越来越显得力不从心,最严重的情况是很多应用没办法往上部署。举个例子来说,像Redis应用,它主要功能是做缓存,在高并发的情况下,一个Redis容器能把网络跑满,如果同一台宿主机上还有其它容器,这就会导致其它容器无法正常对外提供服务。像Database服务,为了做HA,需要容器拥有独立的网络,在迁移的时候保持IP不变。

但在Host模型下,容器网络依赖宿主机网络,容器对外访问需要通过宿主机IP加容器唯一端口,当容器发生迁移的时候,访问容器的方式(IP:Port)也要跟着改变,无法满足用户在平台外部需要直接使用IP访问的需求。为了解决此类问题,急需对容器进行网络隔离,让每个容器拥有独立IP。
#基于Public IP的网络订制
为了满足业务需求,开始研究如何使容器实例以Public IP方式供用户使用。首先什么是Public IP,Public IP就是让容器拥有一个独立的网络协议栈,有一个独立的IP地址。用户可以直接通过这个独立的IP地址访问应用,这样可以方便地解决端口冲突问题。有了这个目标以后,接下来就对目前现有的Docker网络方案进行调研评估。首先简单介绍下现有的容器网络方案,网上也看了很多对比,对于各方案的优缺点这里也做一个简单的总结。
##隧道方案
其典型的代表是:

* Weave,UDP广播,本机建立新的BR,通过PCAP互通。
* Open vSwitch(OVS),基于VxLAN和GRE协议,但是性能方面损失比较严重。
* Flannel,UDP广播,VxLan。

隧道方案在IaaS层的网络中应用也比较多,大家共识是随着节点规模的增长复杂度会提升,而且出了网络问题跟踪起来比较麻烦,大规模集群情况下这是需要考虑的一个点。另外,由于隧道方案性能损失比较严重,所以隧道方案暂时不考虑使用。
##路由方案
其比较典型的代表有:

* Calico,基于BGP协议的路由方案,支持很细致的ACL控制,对混合云亲和度比较高。
* Macvlan,从逻辑和Kernel层来看隔离性和性能最优的方案,基于二层隔离,所以需要二层路由器支持,大多数云服务商不支持,所以混合云上比较难以实现。

路由方案一般是从3层或者2层实现隔离和跨主机容器互通的,出了问题也很容易排查。

在这里我们说一下Calico。

首先它既支持Docker的CNM网络模型也支持像Kubernetes主推的CNI网络模型。既有着不俗的性能表现,提供了很好的隔离性,而且还有不错的ACL控制能力。通过将整个互联网的可扩展IP网络原则压缩到数据中心级别,Calico在每一个计算节点利用Linux Kernel实现了一个高效的vRouter来负责数据转发,而每个vRouter通过BGP协议负责把自己上运行的workload的路由信息像整个Calico网络内传播——小规模部署可以直接互联,大规模下可通过指定的BGP route reflector来完成。这样保证最终所有的workload之间的数据流量都是通过IP路由的方式完成互联的。

此外,Calico基于iptables还提供了丰富而灵活的网络Policy,保证通过各个节点上的ACLs来提供Workload的多租户隔离、安全组以及其他可达性限制等功能。

Calico 架构如下图所示:
002.jpg

对于Calico方案,我们也做了一些测试,首先它的网络转性能非常高,接近原生物理网卡的性能。但Calico依赖BGP协议,需要根据需要,频繁变更物理路由器的配置。对于传统物理网络有一定的侵入性,为了兼容以往的网络架构只能放弃。
##Vlan方案
其比较典型的代表有:

* Contiv netplugin
* Pipework

这里我们着重讲一下Contiv。

Contiv是Cisco开源出来的针对容器的基础架构,主要功能是提供基于Policy的网络和存储管理,是面向微服务的一种新基架,同时它又支持CNM以及CNI网络模型。Contiv能够和主流的容器编排系统整合,包括:Docker Swarm、Kubernetes、Mesos and Nomad。
003.png

如上图所示,Contiv比较“诱人”的一点就是,它的网络管理能力,既有L2(VLAN)、L3(BGP),又有 Overlay(VxLAN),而且还能对接Cisco自家的 SDN 产品 ACI。可以说有了它就可以无视底层的网络基础架构,向上层容器提供一致的虚拟网络了。

最主要的一点是,既满足了业务场景,又兼容了以往的网络架构。在转发性能上,它能达到物理网卡95%的性能。在高并发的场景下,OVS可能会消耗一部分CPU性能。对于这方面后期打算通过DPDK来做改善。另外,Contiv netmaster节点Down了以后不会造成网络中断,可以降低风险。还有一个优点是基于OVS可以灵活地做Policy/ACL/Qos监控等等,最终选择使用Contiv netplugin。

接下来我们说一下Contiv Netplugin在公司的落地情况。

首先根据实际网络访问描述下Contiv在PaaS平台整体部署结构:
004.jpg

目前我们通过Mesos + Marathon实现了容器的动态扩容以及动态负载,能够根据业务负载快速响应,做到自动伸缩,下面我们介绍一下网络模块Contiv。

Contiv主要包含3部分:

  1. netctl客户端主要用来发送命令到Contiv Netmaster;
  2. Netmaster服务端用来管理所有的Netplugin,以及提供IP地址分配IPMI功能;
  3. Netplugin插件跑在每个swarm node节点上,接收Netmaster指令控制OVS实现路由转发功能。

Contiv带来的方便是用户可以根据实例IP直接进行访问,可以借助ovs做很多策略,以及监控等,Contiv Netplugin特性主要有以下几点:

  1. 多租户网络混部在同一台主机上;
  2. 集成现有SDN方案;
  3. 能够和非容器环境兼容协作,不依赖物理网络具体细节;
  4. 即时生效的容器网络Policy/ACL/QoS规则。

可以说Contiv有很多丰富的特性,能够满足大部分业务场景,但有些场景目前Contiv还无法支持需要做二次开发,比如说应用容器IP固定,流量监控等。接下来讲一下我们是如何基于Contiv做IP持久化的。

大家都知道,Docker容器网络模型使用的是CNM(Container Network Model),这的底层是通过Libnetwork实现的,只要符合这个模型的网络接口就能被用于容器之间通信,而通信的过程和细节可以完全由网络接口来实现。
005.jpg


* Sandbox:对应一个容器中的网络环境,包括相应的网卡配置、路由表、DNS配置等。CNM很形象的将它表示为网络的『沙盒』,因为这样的网络环境是随着容器的创建而创建,又随着容器销毁而不复存在的。沙盒的实现可以是Linux Network Namespace、FreeBSD Jail之类的概念,并包含连接多个网络的Endpoint;
* Endpoint:实际上就是一个容器中的虚拟网卡,在容器中会显示为eth0、eth1依次类推。它可以是veth对,或者Open vSwitch的internal port。一个Endpoint只能属于一个沙盒;
* Network:指的是一个能够相互通信的容器网络,加入了同一个网络的容器直接可以直接通过对方的名字相互连接。它的实体本质上是主机上的虚拟网卡或网桥。

在CNM模型下,容器需要先通过IPMI获取IP,然后再创建Endpoint。我们的做法是,在启动容器之前,先调用Contiv rest API获取IP,Contiv Netmaster收到allocate ip的请求以后,将分配的IP保留起来,接下来在创建容器的时候指定所获取的IP,Netmaster收到创建Endpoint的请求将,保留的IP分配给容器,这样就做到了IP持久化。

创建容器的时序图如下:
006.png

#网络监控
在网络流量监控方面,我们通过使用OVS的sFlow来抓取宿主机上所有的网络流量,然后自开发了一个简单的sFlow Collecter,服务器收到sFlow的数据包进行解析,筛选出关键数据,丢到Redis(这里的Redis是做来做缓存的作用)。然后再通过ELK集群定时从Redis拉取数据,进行汇总分析。前端通过调用ELK的API,得到所需要的监控数据。

通过对网络进行改造,目前已经将Redis,大数据,DB等诸多复杂的业务成功的跑在了容器中,切切实实解决了业务的痛点。随着PaaS云平台的演进,由Swarm切换为Mesos + Marathon,后期也会根据需求对Contiv不断优化。

三年多的持续迭代,只为达到更高的要求。
>铭记初心,只为让更多人享受旅游的乐趣。
>
——王文建



原文链接:同程容器云平台网络方案演进&version=12020610&nettype=WIFI&fontScale=100&pass_ticket=FLwEXJsRPG3OGe5piakWkIHrzthK2rlKfn3ITRd1TSLnVhmID7y9j4z8eu7HFxt7)(作者:王文建)

DockOne微信分享(一三三):深入理解Kubernetes网络策略

尼古拉斯 发表了文章 • 0 个评论 • 4326 次浏览 • 2017-07-21 15:45 • 来自相关话题

【编者的话】当我们逐渐向着微服务、云原生迈进的时候,传统静态的、相对简单的网络安全策略开始显得吃力。 Kubernetes 的 Network Policy 特性正是来解决这个问题的。在刚刚出炉不久的1.7版本中,该特性也被扶正成为GA。让我们来一起看看 Ne ...查看全部
【编者的话】当我们逐渐向着微服务、云原生迈进的时候,传统静态的、相对简单的网络安全策略开始显得吃力。 Kubernetes 的 Network Policy 特性正是来解决这个问题的。在刚刚出炉不久的1.7版本中,该特性也被扶正成为GA。让我们来一起看看 Network Policy 是什么,能为我们做什么,以及是如何实现的。

【3 天烧脑式基于Docker的CI/CD实战训练营 | 北京站】本次培训围绕基于Docker的CI/CD实战展开,具体内容包括:持续集成与持续交付(CI/CD)概览;持续集成系统介绍;客户端与服务端的 CI/CD 实践;开发流程中引入 CI、CD;Gitlab 和 CI、CD 工具;Gitlab CI、Drone 的使用以及实践经验分享。

# CNI
Kubernetes 对网络做了较好的抽象。它将对网络的需求交给外部的组件完成,也就是 CNI driver。

Pod 的网络必须满足以下三个需求:

  1. 所有 Pod 之间无需 NAT 即可互通
  2. 主机和 Pod 之间无需 NAT 即可互通
  3. Pod 自省的 IP 地址和之外部看到该 Pod 的地址一致

CNI 对网络的实现做了详细的定义。CNI 的实现可以被分成三种:

  1. 3 层路由实现
  2. Overlay 实现
  3. 2 层交换实现

现在比较常用的 CNI 实现有:Flannel、Calico、Weave。 Flannel 通过 VXLan Overlay 来实现跨主机 Pod 网络, Calico 则完全通过 3 层路由来实现了跨主机的容器网络,Weave也是 Overlay 的实现。
# 什么是Network Policy
随着业务逻辑的复杂化,微服务的流行,越来越多的云服务平台需要大量模块之间的网络调用。

传统的单一外部防火墙,或依照应用分层的防火墙的做法渐渐无法满足需求。在一个大的集群里面,各模块,业务逻辑层,或者各个职能团队之间的网络策略的需求越来越强。

Kubernetes 在 1.3 引入了 Network Policy 这个功能来解决这个问题。这些 Policy 允许用户在同一个 Cluster 内实现网络的隔离。也就是在某些需要的 Pod 之间架起防火墙。可以简单的理解为各个微服务之间的动态防火墙。也有人把这叫做分布式防火墙。

并非所有的网络驱动都支持这个功能。比如大家比较熟悉的,比较流行的 Flannel 就还没有加入对 Network Policy 的支持。Calico 和 Weave 都各自实现了 NPC(network policy controller)。虽然 Flannel 不支持 Network Policy。但是,可以使用 Flannel 提供网络方案,同时使用 Calico 或者Weave 的 NPC 组件来共同完成。Canal 就提供了将 Flannel 和 Calico NPC 组合的方案。
# DEMO
下面我们就以Calico为基础,给大家做一个demo。

这里我已经搭好了一个 Kubernetes 的简单的集群:只有一个 master 和两个 minion。我们先来部署 Calico。这里要注意的是,由于我们要 demo 的是最新的 Kubernetes API,我们必须使用 Kubernetes 1.7 和 Calico 2.3,并且,Calico只能配置成 Kubernetes Datastore 的模式。在这种模式下,Calico 对网络状态的控制是通过 Kubernetes API 来完成的。另外还有一种模式是通过 etcd 集群。那种模式暂时还不支持最新的API。Kubernetes Datastore 这种方式有时也叫做KDD — Kubernetes datastore driver。

在进行 KDD 模式的 Calico 安装时要注意以下这么几点:

  1. IPAM 要使用 host-local
  2. 通过 controller manager 来分配 CIDR

细节请点击:http://docs.projectcalico.org/v2.3/getting-started/kubernetes/installation/hosted/kubernetes-datastore/

配置好 Calico之后,我们来看一个简单的 demo,实际操作一下 Network Policy:

为了简单起见,我们会直接使用 default namespace。如果你在一个现有的环境里面, 可以将以下的命令在一个独立的 namespace 里面运行。

创建 namespace 使用这个命令:
kubectl create ns np-demo

接下来运行一个简单的 nginx deployment 并用80端口暴露服务:
kubectl run nginx --replicas=2 --image=nginx
deployment "nginx" created
kubectl expose deploy nginx --port=80
service "nginx" exposed

现在我们还没有做任何的限制,所以 Kubernetes 缺省情况是所有 Pod 都是开放的。

我们来用一个 BusyBox 的 Pod 验证一下:
kubectl run busy --rm -ti --image busybox /bin/sh
If you don't see a command prompt, try pressing enter.
/ # wget -q nginx -O - | head -4

上面的 Wget 命令是在 BusyBox 这个 Pod 里面执行的。`-q` 和 `-O -` 的组合会使这个命令在命令行输出 nginx 的缺省首页,这表明我们的验证是成功的。用 Ctl-D 退出容器。

接下来我们就要加入限制了。我们的做法是先限制对所有 Pod 的访问,然后建立白名单。 kubectl apply下面的 YAML 文件就可以限制所有访问:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: default-deny
spec:
podSelector:

注意我们提供了一个空的 podSelector。

我们再试着用之前的 BusyBox 的方式来访问一下:
kubectl run busy --rm -ti --image busybox /bin/sh
/ # wget -q --timeout=5 nginx -O -


这此我们设置了 5 秒的超时。因为访问被拒接,所以确实会超时:
wget: download timed out 

好,我们的第一个 Network Policy 已经生效了。然而,限制对所有 Pod 的访问显然是没有意义的。接下来我们建立一个白名单 . apply 下面的 YAML 文件:
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: access-nginx
spec:
podSelector:
matchLabels:
run: nginx
ingress:
- from:
- podSelector:
matchLabels:
run: access

这个 Network Policy 的意思是:标签 run:access 选中的 Pod 可以访问标签 run:nginx 的 Pod,也就是我们 demo 开始时创建的 Nginx 的 Pod。这些 label 都是 kubectl run 命令自动 添加的。

接下来我们试试看能否成功地访问了:
kubectl run access --rm -ti --image busybox /bin/sh
wget -q nginx -O -

我们依然会看到熟悉的 Nginx 缺省首页。如果我们运行一个不符合上述 selector 的 Pod,就无法访问。这个留给有兴趣的同学自己回去验证。

如果你接触过 1.7 之前的 Network Policy 的话,你可能会发现这里的 API 有些不同。Kubernetes 1.7 已经将 Network Policy 正式提升到 GA。

正式的 API 和之前的 API 区别有:

  1. 不再使用 Annotation 来表达 default-deny 等这样的规则
  2. API version 从 extension/beta1 升级到了 networking.k8s.io/v1

# 实现
Calico 的实现是基于 iptables 的。在每个 chain 的顶端,Calico 都插入了一条定制的 chain,从而使得 packet 优先经过 Calico 定义的规则。我们在其中一个 minion 上面运行 iptables-save -c 就可以检查这些规则。可以看出 kube-proxy 和 Calico 都定义了大量的 iptable 规则。

这里细节很多,我们只需要关注这几点:

Calico 使用 conntrack 来优化。就是说,一旦一个连接已经建立,之后的packet都会直接被允许通过。比如:
-A cali-fw-cali7af3f94d3a1 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT 
-A cali-fw-cali7af3f94d3a1 -m conntrack --ctstate INVALID -j DROP

名为 cali-pi-xxxx 的规则是负责 Network Policy Ingress 的。我们可以想见,如果我们定义了很多 Policy,一个一个单独定义的规则会导致性能下降。这里 Calico 利用了 iptables 的 ipset 特性。使得一个 rule 可以通过 hash 表来匹配多种地址。
-A cali-pi-_G7e-YAvXRsfDoqGDf36 -m set --match-set cali4-s:2I5R46OBA_TBIUlpH0dCd_n src -j MARK --set-xmark 0x1000000/0x1000000 
-A cali-pi-_G7e-YAvXRsfDoqGDf36 -m mark --mark 0x1000000/0x1000000 -j RETURN

Weave 的实现也类似。底层还是使用了 iptables 和 netfilter。Weave 也创建了自定义的 chain。但由于一个是 Overlay 一个是路由,规则还是有些不同的。

另外一个细微的不同是,Weave使用了 -m state 而不是 -m conntrack。conntrack 是比较新的语法,但实际使用中功能是一样的。下面是几个 Weave 安装的 iptables rules 的例子:
FORWARD chain:
-o weave -j WEAVE-NPC
-o weave -j DROP
WEAVE_NPC chain:
-m state --state RELATED,ESTABLISHED -j ACCEPT
-m state --state NEW -j WEAVE-NPC-DEFAULT
-m state --state NEW -j WEAVE-NPC-INGRESS
-m set --match-set weave-v/q_G.;Q?uK]BuDs2 dst -j ACCEPT
-m set --match-set weave-k?Z;25^M}|1s7P3|H dst -j ACCEPGo

# Q&A
Q:Calico 和 Weave 从 Policy 处理性能来看,两者哪个更优?

A:两者在 iptables 层面上的实现原理是一样的。都用了-m
state 和 ipset 优化,性能差别不大。



Q:Calico 结合 Kubernetes 怎么实现多租户,比如网络隔离之类的?

A:可以考虑用 namespace 来隔离。没有 Network Policy 的情况下当然是互通的。但是 Kubernetes 的 Network Policy 支持 namespaceSelector,可以轻松搞定。



Q:Weave、Calico、Flannel 比较,适用场景和优缺点是什么,Flannel out了么?

A:各有各的市场 :-)。
Flannel 比较简单,资源消耗也会小些。Flannel 不能算 out 了。Cannel 的出现将 Flannel 和 Calico 整合了起来。



Q:NPC 必须用 iptables 实现吗?在某些情况下,Pod 出向流量并不会由主机协议栈,这样 iptables 就用不了,这种情况下 NPC 怎么实现呢 ?

A:Calico、Weave、Romana 的 NPC 都是通过 iptables 实现的。Pod
egress 不通过主机协议栈也会通过 netfilter。



以上内容根据2017年07月20日晚微信群分享内容整理。分享人梁文智:睿云智合研发顾问。 DockOne每周都会组织定向的技术分享,欢迎感兴趣的同学加微信:liyingjiesa,进群参与,您有想听的话题或者想分享的话题都可以给我们留言。

3 天烧脑式容器存储网络训练营 | 深圳站

李颖杰 发表了文章 • 0 个评论 • 5321 次浏览 • 2017-06-21 18:29 • 来自相关话题

容器进入云计算AI时代,大规模容器集群即将进入千万家企业,业务特征十分复杂,如:容器数量庞大,需要满足快速部署灵活迁移,保证容器间跨物理机间的通信;保证业务、资源与物理位置无关,容器可以任意迁移;承载多种业务,需要保证业务间的安全隔离及访问控制。存储和网络的容 ...查看全部
容器进入云计算AI时代,大规模容器集群即将进入千万家企业,业务特征十分复杂,如:容器数量庞大,需要满足快速部署灵活迁移,保证容器间跨物理机间的通信;保证业务、资源与物理位置无关,容器可以任意迁移;承载多种业务,需要保证业务间的安全隔离及访问控制。存储和网络的容器化技术成为关键点,云计算从业者必须尽快在传统数据中心在使用云化后,着手解决大二层网络中的经典问题如MAC表项不足、ARP风暴、VLAN的4k上限等问题。目前业界主要有两种容器网络模型CNM和CNI来实现容器的网络方案,其中坑多知识点也多,尽快掌握这些技术方案成为不断完善自身业务能力的必须课程。

* 培训时间:7月20日——7月22日
* 课程难度:中高级
* 课程人数:20-40人
* 地点: 广东深圳市南山区粤兴三道9号华中科技大学产学研基地B座二楼T204教室
* 费用:4999元/人
* 报名链接:http://www.bagevent.com/event/649106
* 垂询电话:132 4116 6558
* 微信:liyingjiesa

培训对象:

* 容器开发和运维工程师
* 有志于从事容器技术的在职人员或者学生

技能要求:

* 对容器技术有一定了解
* 工作或者学习中有使用到容器技术

优惠信息:

* 团购3-4人每人优惠300
* 团购5人第6人免费

证书:

培训结束后,将提供『云计算容器(Docker)技术能力』中级测评考试,考试通过后,将获得『云计算容器(Docker)技术能力』中级能力测评认证证书,此认证是由科技部统一印制、统一编号、统一管理的国家级职业技能证书,是反映开源软件开发与应用技能水平的国家级职业资格认证。该证书在全国范围内通用有效,目前也是国内首个『容器技术』认证证书。

培训结束将统一为学员安排考试,考试时长1小时。

内容设置:

Docker文件系统基础

  • Docker分层文件系统
  • image的存储表现
  • Container的存储表现
Cgroup文件系统分析及实战
  • Cgroup及其subsystem介绍
  • Cgroup进行资源限制实战
Docker Plugin是如何设计的Docker storage driver分析及选型
  • AUFS
  • Btrfs
  • Device mapper
  • OverlayFS
  • OverlayFS2
  • ZFS
Docker Volume Plugin的工作原理常见Docker Volume Pulgin
  • Local volume plugin
  • Local Persist Plugin
  • Contiv Volume Plugin
  • Convoy plugin
  • Flocker plugin
  • GlusterFS plugin
  • rbd-docker-plugin
Kubernetes Storage机制
  • Volume类型介绍
  • PV/PVC原理及使用
  • Dynamic provisioning介绍及使用

Kubernetes管理有状态应用案例

经验分享

容器网络实现原理

* 容器实现原理
* Namespace介绍
* Cgroup介绍
* Cgroup手动实现容器网络之实战

容器网络模型: CNI vs CNM

* Docker网络模型CNM
* Kubernetes网络模型CNI

Docker网络实现CNM之Libnetwork

* Docker原生网络Bridge、Overflay、IPVLAN、MacVLAN
* Libnetwork plugin driver

容器网络插件

* CNM libnetwork插件的开发实现
* CNI插件的开发实现
* 常见的network driver

Calico原理及实现

* 什么是Calico
* Calico实现框架
* Calico典型部署

Contiv Netplugin原理及实现、性能

* Netplugin介绍
* Netplugin架构分析
* Netplugin源码实现
* 经验分享

开源企业级镜像仓库Harbor原理及实现

* Harbor介绍及主要特性
* Harbor架构分析
* Harbor高可用实现

讲师

* 王涛,原唯品会资深云计算工程师。西电研究生毕业后,一直从事云计算领域的开发和架构近六年。曾先后在华为和唯品会从事FusionSphere增值服务开发,以及IaaS、PaaS平台的架构开发。专注于研究Docker、Kubernetes、Mesos等容器技术,对Docker和Kubernetes源码有较深入研究和二次开发经验。

* 贺佰元,唯品会资深云计算开发工程师,北邮计算机硕士。研究生期间开始从事虚拟化和云计算的课题研究,曾先后任职于雅虎北研、中国移动,一直负责私有云和公有云的研发和架构工作,包括IaaS\PaaS平台、对象存储、容器云等的开发和架构设计,已有6年多的云计算领域实践经验。对虚拟化及OpenStack、Docker容器技术、Kubernetes和Mesos、分布式存储等有丰富的源码二次开发和架构选型经验。

报名链接:http://www.bagevent.com/event/649106

备忘录 | 哪些网络开放课程可能改变你人生?

enncloud 发表了文章 • 0 个评论 • 1358 次浏览 • 2017-05-16 10:24 • 来自相关话题

“在这个共享经济的时代,生活中的种种资源都可以共享。有个长辈曾经和我说,你们真是活在了好时代,网络上那么多资源,要是我们能有这条件,哪一个不比你们优秀?脑司机今天搜集了一些网络上的课程资源供大家随意取用。” 01 兰迪· ...查看全部
“在这个共享经济的时代,生活中的种种资源都可以共享。有个长辈曾经和我说,你们真是活在了好时代,网络上那么多资源,要是我们能有这条件,哪一个不比你们优秀?脑司机今天搜集了一些网络上的课程资源供大家随意取用。”


01 兰迪·波许教授的最后一课

兰迪·波许是美国卡内基梅隆大学的计算机科学、人机交互及设计教授。在美国一些高校,「最后的讲座」是著名教授退休前的最后一课。兰迪教授并没有准备退休,但是他患了胰腺癌,只剩下几个月的生命。

他是在自己领域做出些成就的人,他愿意在他生命剩下不足3个月的时候准备和做这样一场演讲,这必须是他诚心想表达的观念,是他对人生的真实态度。不一定要跟他走一样的路,但是他的乐观和对童年梦想的追求确实很动人。

02 人生七年

看着这些孩子从7岁开始,7,14,21…直到56岁的成长变化,慢慢地有一种将这14个孩子视若己出的感觉,其中每一个人的特点都是那么鲜明,每一个人都那么的可爱。

人生的复杂就意味着它是需要多种评判价值标准同时共存的,没有哪一种单一的评价标准可以用来衡量每一个人,既没有这一标准,也不存在有可以做出这种评判资格的人。每一个人都有自己的精彩,他们也会不断强调、展现自己的精彩,如果你不能理解那种精彩,采用不了那种评价标准,那么那就是不属于你的精彩,不属于你的,你无法理解的,自然也就没有资格去评价。无论如何这都是一部很值得观看的纪录片。

03 哈佛大学公开课:计算机科学 cs50


CS50 是哈佛的一门计算机科学的导论性的课程,内容包括基本的计算机知识以及基础算法,常见的编程语言等等,还会探讨最新的计算机科学领域的成果,课程发散性思维强。CS50 课程的讲课形式让人耳目一新,真正做到了快乐学习。

04 斯坦福大学公开课:编程方法学


课程介绍了当代程序设计基本思想:面向对象,模块化,封装,抽象化与测试。《编程方法学》将良好的编程思想连同广泛应用的 Java 语言一同讲授。着重教授良好的编程风格和 Java 语言的特色。这门课同样适合文科,主修社会科学的同学和编程爱好者学习观看。

05Codecademy


推荐个自己一直用的,Codecademy 课程有不同的路线和实际应用,每一步都有提示。我用这个学的 Ruby,Angular 什么的,很基础但感觉打得挺牢,而且偏实用。最关键是免费。其他的很多要么是订阅要么是单买。如果想比较快速过一下相关领域的基础,还是挺不错的。新智云www.enncloud.cn

更多知识请关注微信“极客脑司机”