基于Neutron的Kubernetes SDN实践经验之谈
首先,向大家科普下Kubernetes所选择的CNI网络接口,简单介绍下网络实现的背景。
CNI即Container Network Interface,是一套容器网络的定义规范,包括方法规范、参数规范、响应规范等等。CNI只要求在容器创建时为容器分配网络资源、删除容器时释放网络资源。CNI与调用者之间的整个交互过程如下图所示:
CNI实现与外界的交互都通过进程参数和环境变量传递,也只要求输出结果符合CNI规范即可,与实现语言也没什么特殊要求。比如Calico早期版本就使用Python实现了CNI规范,为Kubernetes提供了网络实现。常见的环境变量设置如下:
CNI_COMMAND:调用指定CNI动作,ADD表示增加网卡,DEL表示释放网卡
CNI_CONTAINERID:容器ID
CNI_NETNS:容器网络命名空间文件位置
CNI_ARGS:额外传递的参数
CNI_IFNAME:设置的容器网卡名称,如eth0
正因如此,CNI规范实现起来非常容易扩展,除了CNI自带的Bridge、Macvlan等基本实现以外,还有大量的第三方实现可供选择,包括Calico、Romana、Flannel等常用实现。同时CNI支持多种容器运行时,包括Docker、rkt、Mesos、Hyper等容器引擎都可以使用。这也是Kubernetes选择使用CNI的一大重要原因。
相对的,Docker提出的CNM(Cotainer Network Model)模型实现就比较复杂,但更为完善,比较接近传统的网络概念。如下图所示:
Sandbox就是容器的网络命名空间,Endpoint为容器连接到网络中的一张网卡,而网络则是一组相互通信的Endpoint的集合,比较接近Neutron中的网络定义。
在CNM中,docker engine通过HTTP REST API调用网络实现,为容器配置网络。这些API接口涵盖网络管理、容器管理、创建endpoint等十几个接口。同时CNM模型还隐含在docker自身附带的service机制、dns机制等附加约束,因此可以在一定程度上说,CNM模型只是专为docker容器实现的,对别的容器运行时并不友好。
由于上面这些技术上的原因以及一些商业上的原因,Kubernetes最终选择了CNI作为自己的网络接口。
当然,Kubernetes也提供一些取巧的方法,将CNI接口转化为对CNM模型的调用,从而实现两种模型的通用。例如to_docker,这个脚本就将Kubernetes对CNI的调用转换为Docker CNM网络的对应操作,从而实现CNI到CNM的转换。
接下来,给大家介绍下Kubernetes中网络概念和通信原理。
在Kubernetes的网络模型中,约定了三个基本约束:
所有容器之间都可以无须SNAT即可相互直接以IP通信。
所有主机与容器之间都可以无须SNAT即可相互直接以IP通信。
容器看到的自身IP与其他容器看到的容器IP相同。
在满足约束的基础上,Kubernetes不关心具体的网络通信原理,只以三个约束为既定事实,在此基础上,根据Kubernetes自身逻辑处理网络通信,从而避免Kubernetes功能纠结在纷繁复杂的网络实现中。
而在网络概念上,Kubernetes中有两种核心IP:
POD IP:有CNI实现提供,Kubernetes不管这个IP是否可达,只负责使用这个IP实现配置iptables、做健康检查等功能。默认情况下,这个IP在Kubernetes集群范围内都是可达的,并且可以进行ping等操作。
cluster IP:即服务IP,这个IP在Kubernetes中只是用于实现服务交互通信,本质上只是iptables上的几条DNAT规则。默认情况下,这个IP上只能提供服务端口的访问,且不可ping。
以集群的DNS服务为例,相关的核心iptables如下图所示:
这些iptables都是由kube-proxy生成的,而且kube-proxy并不实际负责进行转发,因此即使kube-proxy服务异常,已经产生的iptables依然可以使流量能够正确的在服务IP和POD IP之间流转。其网络流量路径可以参考下图:
当访问DNS服务的端口10.254.0.3时,kube-proxy生成的iptables DNAT规则,将流量转发到后端POD IP及对应端口上,将流量按后端POD的IP个数实行随机均等分配。
而kube-proxy可以从kube-apiserver获取服务和POD的状态更新,随时根据其状态更新iptables,从而实现服务的高可用与动态扩展。
在基础的IP通信机制上,Kubernetes还通过Network Policy和Ingress提高网络安全性和响应性能。
Network Policy提供了网络隔离能力,它基于SIG-Network group演进而来,Kubernetes只提供内置的labelSelector和label以及Network Policy API定义,本身并不负责实现如何隔离。在Kubernetes使用的CNI网络实现中,目前只有Calico、Romana、Contiv等少少几个实现了Network Policy集成。一个典型的Network Policy定义如下所示:
apiVersion: extensions/v1beta1
kind: NetworkPolicy
metadata:
name: test-network-policy
namespace: default
spec:
podSelector:
matchLabels:
role: db
ingress:
- from:
- podSelector:
matchLabels:
role: frontend
ports:
- protocol: tcp
port: 6379
它指定约束,具有role:db标签的POD只能被具有role:frontend标签的POD访问,除此之外拒绝所有流量。从功能上来讲,Network Policy可以等价于Neutron的安全组。
Ingress是负责对外提供服务的,通过Nginx对外提供一个单独接口,实现集群中的所有服务的对外提供,从而取代使用NodePort暴露每个服务的现有实现。目前,Kubernetes的Ingress提供了Nginx和GCE两种实现,感兴趣的同学可以直接参考官文档,https://github.com/kubernetes/ingress/tree/master/controllers。
Kubernetes社区中,比较常见的几种网络实现主要是以下两种:
基于Overlay网络:以Flannel、Weave为代表。Flannel是CoreOS为Kubernetes专门定制实现的Overlay网络方案,也是Kubernetes默认的网络实现。它基于VXLAN或者UDP整个集群的Overlay网络,从而实现容器在集群上的通信,满足Kubernetes网络模型的三大基本约束。由于在通信过程中存在数据包的封包解包等额外损耗,性能较差,但已经基本满足使用。
以L3路由为基础实现网络:以Calico、Romana为代表。其中,Calico是广泛流传的性能最好的Kubernetes网络实现,基于纯三层的路由实现网络通信,结合iptables实现的安全控制,可以满足大多数云的性能需求。但是由于它要求主机上必须打开BGP形成路由拓扑,在一些数据中心上可能不会被允许。同时,Calico还比较早地支持了Network Policy,并且可以将Calico自身的数据直接托管在Kubernetes中,从而实现与Kubernetes的深度集成。
从上面这些网络实现来看,目前Kubernetes的网络实现都还谈不上是比较成熟的SDN,因此我们公司在考察Kubernetes后,决定基于Neutron,为Kubernetes提供一个可用的SDN实现,这就是Skynet项目的由来。
下面我来跟大家分享下,Skynet在实践过程中的一些经验。
在实践中,首先要解决的就是Kubernetes中的网络概念,怎么翻译到Neutron中,才能比较合适地实现功能。
在第一个版本中,Kubernetes网络中概念翻译对应如下表所示:
POD ----> 虚拟机
Service -------> loadbalancer
Endpoints -------> pool
Service后端POD ----> member
但是,由于Kubernetes中支持同一服务上设置多个服务端口,而Neutron的每个Load Balancer仅支持一个对外端口。好在,去年OpenStack的Mitaka版本后,Neutron LBaaS V2正式发布,因此有了第二个版本的概念翻译。
POD ----> 虚拟机
Service -----> lbaasv2 loadbalancer
Service port ----->lbaasv2 listener
Endpoints -----> lbaasv2 pool
Service后端POD ------>lbaasv2 member
POD livenessProbe ----->health monitor
LBaaS V2的基本术语图解如下所示:
Load Balancer:负载均衡器,对应一个HAProxy进程,占据一个子网IP。可以逻辑上映射为Kubernetes中的Service。
Listener:监听器,表示负载均衡器本身提供的一个前端监听端口。对应service定义中的ports中port。
pool:监听器后端的成员集合记录。
member:监听器后端的成员。对应service使用的Endpoints的addresses列表,每个地址可以对应service声明中的targetPort的映射。
health monitor:pool中的成员健康检查器,类似Kubernetes中的livenessProbe,目前不映射。
就资源数量的映射来说:Kubernetes的一个service,对应一个Load Balancer。service中的每个port对应监听这个Load Balancer的一个Listener。每个Listener后端都对接一个pool包含其后端资源。而Kubernetes中的每个Service都有一个对应的Endpoints来包含其后端POD。Endpoints中的每个IP+Service声明port的targetPort就对应pool中的一个member。
初步完成了概念的映射后,我们简单介绍下开发中的思路。
在整体结构上,Skynet居于Kubernetes和Neutron之间,实现了CNI规范,基于Neutron为容器配置网络。service-watcher负责监听Kubernetes的资源,对服务等概念翻译为Neutron实现,从而实现完整的网络功能。如下所示:
kubelet是创建POD的直接操作者,在为POD设置网络时,通过CNI接口规范,调用Skynet实现。Skynet通过调用Neutron为容器分配IP,并通过在POD容器网络命令空间中操作,实现IP、路由等通信规则的设置。
而Neutron原生的DHCP、LBaaS v2等机制可以基本保持不变。从而实现完整的集成,可以使Kubernetes集群获得完整的Neutron SDN功能。而当容器内需要进行DNS时,则可以通过Neutron自带的DHCP Agent负责实现解析,在集群网络中正常工作。
如前文所述,Skynet实现了CNI规范,kubelet与Skynet之间的交互过程如下所示:
简要介绍下每个步骤:
kubelet通过CNI机制调用skynet,主要传递的参数如下:
CNI_COMMAND:调用指定CNI动作,ADD表示增加网卡,DEL表示释放网卡
CNI_CONTAINERID:容器ID
CNI_NETNS:容器网络命名空间文件位置
CNI_ARGS:额外传递的参数
CNI_IFNAME:设置的容器网卡名称,如eth0
执行ADD操作时,Skynet根据传入的参数和POD的配置,通过neutron-server为POD创建port。
执行ADD操作时,Skynet根据port和网络配置,为容器创建网络设备,并挂载到容器命名空间中。
neutron-linuxbridge-agent,根据容器的网络和安全组规则生成iptables。从而利用Neutron原生的安全组功能,同时也可以直接利用Neutron的一整套SDN实现,包括vRouter、FWaaS、VPNaaS等服务。
service-watcher将Kubernetes服务映射为Neutron LBaaS v2实现后,以VLAN网络为例,POD与服务之间的流量通信过程如下图:
当集群内容器访问服务时,Kubernetes默认都是通过服务名称访问,服务名通过Neutron的DHCP机制,可以由每个网络的Dnsmasq进程负责解析,获得service对应负载均衡的IP地址后,即可用于网络通信,由物理交换机负责流量的中转。
在实际实现中,以Kubernetes中一个服务的定义映射到Neutron的loadbalancer为例演示下。
例如对下面的service实现:
kind: Service
apiVersion: v1
metadata:
name: neutron-service
namespace: default
labels:
app: neutron-service
annotations:
skynet/subnet_id: a980172e-638d-474a-89a2-52b967803d6c
spec:
ports:
- name: port1
protocol: TCP
port: 8888
targetPort: 8000
- name: port2
protocol: TCP
port: 9999
targetPort: 9000
selector:
app: neutron-service
type: NodePort
kind: Endpoints
apiVersion: v1
metadata:
name: neutron-service
namespace: default
labels:
app: neutron-service
subsets:
- addresses:
- ip: 192.168.119.187
targetRef:
kind: Pod
namespace: default
name: neutron-service-puds0
uid: eede8e24-85f5-11e6-ab34-000c29fad731
resourceVersion: '2381789'
- ip: 192.168.119.188
targetRef:
kind: Pod
namespace: default
name: neutron-service-u9nnw
uid: eede9b70-85f5-11e6-ab34-000c29fad731
resourceVersion: '2381787'
ports:
- name: port1
port: 8000
protocol: TCP
- name: port2
port: 9000
protocol: TCP
POD和Service通过特定注解来指定使用的Neutron网络、IP等配置,与Kubernetes尽量解耦。
上面的Service映射成Load Balancer后,其定义如下所示:
{
"statuses": {
"loadbalancer": {
"name": "neutron-service",
"provisioning_status": "ACTIVE",
"listeners": [
{
"name": "neutron-service-8888",
"provisioning_status": "ACTIVE",
"pools": [
{
"name": "neutron-service-8888",
"provisioning_status": "ACTIVE",
"healthmonitor": {},
"members": [
{
"name": "",
"provisioning_status": "ACTIVE",
"address": "192.168.119.188",
"protocol_port": 8000,
"id": "461a0856-5c97-417e-94b4-c3486d8e2160",
"operating_status": "ONLINE"
},
{
"name": "",
"provisioning_status": "ACTIVE",
"address": "192.168.119.187",
"protocol_port": 8000,
"id": "1d1b3da6-b1a1-485b-a25a-243e904fcedb",
"operating_status": "ONLINE"
}
],
"id": "95f42465-0cab-477e-a7de-008621235d52",
"operating_status": "ONLINE"
}
],
"l7policies": [],
"id": "6cf0c3dd-3aec-4b35-b2a5-3c0a314834e8",
"operating_status": "ONLINE"
},
{
"name": "neutron-service-9999",
"provisioning_status": "ACTIVE",
"pools": [
{
"name": "neutron-service-9999",
"provisioning_status": "ACTIVE",
"healthmonitor": {},
"members": [
{
"name": "",
"provisioning_status": "ACTIVE",
"address": "192.168.119.188",
"protocol_port": 9000,
"id": "2faa9f42-2734-416a-a6b2-ed922d01ca50",
"operating_status": "ONLINE"
},
{
"name": "",
"provisioning_status": "ACTIVE",
"address": "192.168.119.187",
"protocol_port": 9000,
"id": "81f777b1-d999-48b0-be79-6dbdedca5e97",
"operating_status": "ONLINE"
}
],
"id": "476952ac-64a8-4594-8972-699e87ae5b9b",
"operating_status": "ONLINE"
}
],
"l7policies": [],
"id": "c6506b43-2453-4f04-ba87-f5ba4ee19b17",
"operating_status": "ONLINE"
}
],
"pools": [
{
"name": "neutron-service-8888",
"provisioning_status": "ACTIVE",
"healthmonitor": {},
"members": [
{
"name": "",
"provisioning_status": "ACTIVE",
"address": "192.168.119.188",
"protocol_port": 8000,
"id": "461a0856-5c97-417e-94b4-c3486d8e2160",
"operating_status": "ONLINE"
},
{
"name": "",
"provisioning_status": "ACTIVE",
"address": "192.168.119.187",
"protocol_port": 8000,
"id": "1d1b3da6-b1a1-485b-a25a-243e904fcedb",
"operating_status": "ONLINE"
}
],
"id": "95f42465-0cab-477e-a7de-008621235d52",
"operating_status": "ONLINE"
},
{
"name": "neutron-service-9999",
"provisioning_status": "ACTIVE",
"healthmonitor": {},
"members": [
{
"name": "",
"provisioning_status": "ACTIVE",
"address": "192.168.119.188",
"protocol_port": 9000,
"id": "2faa9f42-2734-416a-a6b2-ed922d01ca50",
"operating_status": "ONLINE"
},
{
"name": "",
"provisioning_status": "ACTIVE",
"address": "192.168.119.187",
"protocol_port": 9000,
"id": "81f777b1-d999-48b0-be79-6dbdedca5e97",
"operating_status": "ONLINE"
}
],
"id": "476952ac-64a8-4594-8972-699e87ae5b9b",
"operating_status": "ONLINE"
}
],
"id": "31b61658-4708-4a48-a3c4-0d61a127cd09",
"operating_status": "ONLINE"
}
}
}
其对应的HAProxy进程配置如下所示:
# Configuration for neutron-service
global
daemon
user nobody
group nogroup
log /dev/log local0
log /dev/log local1 notice
stats socket /var/lib/neutron/lbaas/v2/31b61658-4708-4a48-a3c4-0d61a127cd09/haproxy_stats.sock mode 0666 level user
defaults
log global
retries 3
option redispatch
timeout connect 5000
timeout client 50000
timeout server 50000
frontend 6cf0c3dd-3aec-4b35-b2a5-3c0a314834e8
option tcplog
bind 192.168.119.178:8888
mode tcp
default_backend 95f42465-0cab-477e-a7de-008621235d52
frontend c6506b43-2453-4f04-ba87-f5ba4ee19b17
option tcplog
bind 192.168.119.178:9999
mode tcp
default_backend 476952ac-64a8-4594-8972-699e87ae5b9b
backend 476952ac-64a8-4594-8972-699e87ae5b9b
mode tcp
balance roundrobin
server 81f777b1-d999-48b0-be79-6dbdedca5e97 192.168.119.187:9000 weight 1
server 2faa9f42-2734-416a-a6b2-ed922d01ca50 192.168.119.188:9000 weight 1
backend 95f42465-0cab-477e-a7de-008621235d52
mode tcp
balance roundrobin
server 1d1b3da6-b1a1-485b-a25a-243e904fcedb 192.168.119.187:8000 weight 1
server 461a0856-5c97-417e-94b4-c3486d8e2160 192.168.119.188:8000 weight 1
综上所述,通过基于Neutron的Skynet,我们为Kubernetes初步实现了SDN的功能,同时提供了如下网络功能增强:
POD的IP、Mac、主机名等网络配置的保持;
基于Neutron安全组,实现了POD之间的网络隔离功能,更加通用;
支持通过HAProxy直接对外提供服务,性能上会比原生的iptables好很多。
当然,目前有一些Kubernetes特性在Skynet网络方案中还不支持,需要在后面进行增强或实现:
Headless services这一类没有集群IP的Service无法处理。
由于neutron-server与neutron-plugin之间的消息都是通过RabbitMQ进行,不是特别适合容器环境下网络快速变更的现状,会是整个方案的一大瓶颈。
基于Neutron的Kubernetes SDN实践经验之谈的更多相关文章
- QCon技术干货:个推基于Docker和Kubernetes的微服务实践
2016年伊始,Docker无比兴盛,如今Kubernetes万人瞩目.在这个无比需要创新与速度的时代,由容器.微服务.DevOps构成的云原生席卷整个IT界.在近期举办的QCon全球软件开发大会上, ...
- 灵雀云Kube-OVN:基于OVN的开源Kubernetes网络实践
近日,灵雀云发布了基于OVN的Kubernetes网络组件Kube-OVN,并正式将其在Github上开源.Kube-OVN提供了大量目前Kubernetes不具备的网络功能,并在原有基础上进行增强. ...
- 【译】Kubernetes监控实践(2):可行监控方案之Prometheus和Sensu
本文介绍两个可行的K8s监控方案:Prometheus和Sensu.两个方案都能全面提供系统级的监控数据,帮助开发人员跟踪K8s关键组件的性能.定位故障.接收预警. 拓展阅读:Kubernetes监控 ...
- 026.[转] 基于Docker及Kubernetes技术构建容器云平台 (PaaS)
[编者的话] 目前很多的容器云平台通过Docker及Kubernetes等技术提供应用运行平台,从而实现运维自动化,快速部署应用.弹性伸缩和动态调整应用环境资源,提高研发运营效率. 本文简要介绍了与容 ...
- 洪强宁:宜信PaaS平台基于Calico的容器网络实践
洪强宁:宜信PaaS平台基于Calico的容器网络实践 本文内容来自由七牛云主办的ECUG Con,独家授权InfoQ整理完成 容器云面临的网络挑战 在传统的IDC的架构里面网络是很重要的事情,在 ...
- 基于Rust-vmm实现Kubernetes运行时
随着容器及K8s的广泛使用,越来越多的容器安全与隔离问题被暴露出来,如:容器逃逸.水平攻击.DDos攻击等严重威胁了办公和生产环境的安全与稳定,影响了业务的正常运行.安全容器技术孕育而生,产生了kat ...
- TopoLVM: 基于LVM的Kubernetes本地持久化方案,容量感知,动态创建PV,轻松使用本地磁盘
正文 研发测试场景下,一般追求的是一键快速起环境,横向动态复制,一人一套,随起随用,用完即走.作为使用方,其不用关心实际的物理资源是怎样的,环境起在哪里,只要声明自己的使用需求即可.但作为方案构建者以 ...
- 学习笔记——Maven实战(四)基于Maven的持续集成实践
Martin的<持续集成> 相信很多读者和我一样,最早接触到持续集成的概念是来自Martin的著名文章<持续集成>,该文最早发布于2000年9月,之后在2006年进行了一次修订 ...
- 基于Open vSwitch的OpenFlow实践
Open vSwitch(下面简称为 OVS)是由 Nicira Networks 主导的,运行在虚拟化平台(例如 KVM,Xen)上的虚拟交换机.在虚拟化平台上,OVS 可以为动态变化的端点提供 2 ...
随机推荐
- 关于wordpress主题、插件上传和下载问题及其上传图片权限问题解决方案
主题官方下载地址:https://wordpress.org/themes/ 插件官方下载地址: https://wordpress.org/plugins/ 主题的上传下载,无疑是需要ftp服务器的 ...
- 优化方法:SGD,Momentum,AdaGrad,RMSProp,Adam
参考: https://blog.csdn.net/u010089444/article/details/76725843 1. SGD Batch Gradient Descent 在每一轮的训练过 ...
- python3 mock
mock的官网学习备忘录:官网地址https://docs.python.org/3/library/unittest.mock.html#quick-guide 1,安装 python3 unitt ...
- webStorm常用设置之过滤文件夹
webStorm是一款很好用的前端IDE,但是不能否认的是webStorm很重,没有sublime轻便 尤其是项目cnpm后,加载node_modules时的状态,简直想那块豆腐自杀有莫有,就算你耐心 ...
- 树上差分学习笔记 + [USACO15DEC]最大流$Max \ \ Flow \ \ By$
#\(\mathcal{\color{red}{Description}}\) \(Link\) \(FJ\)给他的牛棚的\(N(2≤N≤50,000)\)个隔间之间安装了\(N-1\)根管道,隔间编 ...
- P3133 [USACO16JAN]无线电联系Radio Contact
题目描述 Farmer John has lost his favorite cow bell, and Bessie the cow has agreed to help him find it! ...
- Unity游戏开发之“分层碰撞”
有没有同学遇到过这样的情况:在游戏开发3D游戏中非经常见,比方让一个物体能穿过一个物体 而还有一个物体不能穿过这个物体,并且3个物体都不能穿过地面.在unity中这样的情况的处理是通过分层碰撞来解决的 ...
- Vmware 下安装linux虚拟机
由于想自己玩玩linux系统,就想着装一个linux的虚拟机,虚拟机vmware很好找,也很好用,但是linux镜像安装老是出问题,然后就找了很多版本的,最后实验成功一种,在这里分享给大家. 一.安装 ...
- 【数据结构与算法】001—栈与队列(Python)
栈与队列 1.栈(stacks)是一种只能通过访问其一端来实现数据存储与检索的线性数据结构,具有后进先出(last in first out,LIFO)的特征 2.队列(queue)是一种具有先进先出 ...
- python3爬虫-下载网易云音乐,评论
# -*- coding: utf-8 -*- ''' 16位随机字符的字符串 参数一 获取歌曲下载地址 "{"ids":"[1361348080]" ...