基于Kubernetes(k8s)网络方案演进
VIP PaaS在接近两年时间里,基于kubernetes主要经历四次网络方案的变迁:
1. kubernetes + flannel
2. 基于Docker libnetwork的网络定制
3. kubernetes + contiv + kube-haproxy
4. 应用容器IP固定
先简单说一下背景,PaaS平台的应用管理包括应用配置管理,应用的运行态管理。一个应用的运行态对应kubernetes的一个Replication Controller(后面使用RC简称)和一个Service,应用实例对应kubernetes中的Pod, 我们基于这样的管理方式,需要提供应用之间的相互调用,同时对部分应用要提供基于http/tcp的直接访问。
首先说一下kubernetes + flannel。
flannel主要提供了跨主机间的容器通信;
在kubernetes的Pod、Service模型里,kube-proxy又借助iptables实现了Pod和Service间通信。
基于这种网络访问功能,我们平台提供了以下功能:
基于gorouter提供的平台域名的访问 – watch k8s endpoints event管理router信息;
基于skydns并定制化kube2sky组件和kubelet,提供同一命名空间下应用(Pod)之间基于业务域名的访问 – kube2sky基于k8s Service annotation解析并注册域名信息、kubelet设置容器启动时的domain search及外部dns;
实现容器tty访问控制台 – 每台k8s node部署平台组件 tty agent(根据Pod所属node信息, 建立对应k8s结点的tty连接);
网络访问关系图如下:

在k8s + flannel的模型下,容器网络是封闭子网,可以提供平台内部应用之间基于4层和7层的调用,同时对外部提供应用基于域名(工作在七层)的直接访问,但无法满足用户在平台外部需要直接使用IP访问的需求。
在flannel网络稳定使用后,开始研究network plugin以使应用服务实例以public IP 方式供用户直接使用。
当时docker的版本为1.8, 本身还不支持网络插件.同时 kubernetes本身提供一套基于CNI的网络插件, 但本身有bug[CNI delete invoked twice with non-infra container id #20379]。
于是我们尝试从docker network plugin的角度入手,结合libnetwork从docker源码的角度进行定制。
整个架构分为三层:
- Client Layer – Docker CLI和kubernetes(Docker client);
- Docker Layer – Docker daemon 并在代码层面集成libnetwork(内置OVS driver);
- Controller Layer – ovsdb-server及network controller(自开发IPAM);
整体访问结构图:

整个方案包括以下三个流程:
1. 启动Docker Daemon:
初始化network controller -> 加载OVS Driver -> OVS Driver调用libovsdb创建docker0-ovs Bridge -> OVS Driver将主机上的一物理网卡attach到docker0-ovs上;
2. 启动容器:
OVS Driver 创建veth pair 用于连接network namespaces -> OVS Driver调用network controller获取容器IP和VLAN Tag -> OVS Driver将veth pair的一端添加到docker0-ovs上,并设置VLAN Tag -> OVS Driver设置容器内interface的IP,Mac Address以及路由 -> 设置各network interface为up;
3. 停止容器:
OVS Driver调用network controller释放容器IP -> 删除network link -> OVS Driver调用libovsdb删除port;
libnetwork工作完成了测试阶段但没有经历上线,随着Docker版本的推进,Docker1.9开始支持 contiv netplugin,我们开始研究contiv应用,在期间我们也完成了使用haproxy替换kube-proxy的开发[https://github.com/AdoHe/kube2haproxy],并最后采用docker1.10+contiv上线。
这里根据我们实际网络访问关系再描述下PaaS在contiv整体部署结构:

Kube-haproxy替代了kube-proxy,主要是提供服务ip的公共调用,同时避免了容器数量增加后带来的iptables规则的大量增长,方便调试。
contiv带来的方便是用户可以根据实例IP直接进行访问;我们在使用过程中整体比较稳定,中间出现过一次问题: 机房停电导致了部分IP的分配状态不正确,而且contiv当时还没有提供查看已分配IP的接口。
Docker 1.10版本支持指定IP启动容器,并且由于部分应用对实例IP固定有需求,我们开始着手容器IP固定方案的设计与开发。
前面提到应用运行时,对应k8s内一个ReplicationController以及一个Service。 应用的重新部署目前采用的策略主要是重建策略。 重建的流程包括删除RC及RC下所有Pod,更新并创建新的RC(kubernetes会根据RC配置产生新的POD)。
在默认的k8s+contiv的网络环境下,容器(Pod)的IP网络连接是由contiv network plugin来完成的, contiv master只实现了简单的IP地址分配和回收,每次部署应用时,并不能保证Pod IP不变。所以我们引入了新的Pod层面的IPAM,以保证同一个应用多次发生部署时,Pod IP始终是不变的。
作为Pod层面的IPAM,我们把这一功能直接集成在了kubernetes。Pod作为k8s的最小调度单元,原有的k8s Pod Registry(主要负责处理所有与Pod以及Pod subresource相关的请求:Pod的增删改查,Pod的绑定及状态更新,exec/attach/log等操作) 并不支持在创建Pod时为Pod分配IP,Pod IP是通过获取Pod Infra Container的IP来获取的,而Pod Infra Container的IP即为contiv动态分配得来的。
Pod Registry 访问设计图:

在原有kubernetes代码基础上,我们修改了Pod结构(在PodSpec中加入PodIP)并重写了Pod Registry 同时引入了两个新的资源对象:
1. Pod IP Allocator: Pod IP Allocator是一个基于etcd的IP地址分配器,主要实现Pod IP的分配与回收。
Pod IP Allocator通过位图记录IP地址的分配情况,并且将该位图持久化到Etcd;
2. Pod IP Recycler: Pod IP Recycler是一个基于etcd的IP地址回收站,也是实现PodConsistent IP的核心。Pod IP Recycler基于RC全名(namespace + RC name)记录每一个应用曾经使用过的IP地址,并且在下一次部署的时候预先使用处于回收状态的IP。
Pod IP Recycler只会回收通过RC创建的Pod的IP,通过其他controller或者直接创建的Pod的IP并不会记录,所以通过这种方式创建的Pod的IP并不会保持不变; 同时Pod IP Recycle检测每个已回收IP对象的TTL,目前设置的保留时间为一天。
这里对kubelet也进行了改造,主要包括根据Pod Spec中指定IP进行相关的容器创建(docker run加入IP指定)以及Pod删除时释放IP操作。
创建和删除Pod的UML时序图如下:

Pod的创建在PaaS里主要有两种情形:
- 应用的第一次部署及扩容,这种情况主要是从IP pool中随机分配;
- 应用的重新部署:在重新部署时,已经释放的IP已根据RC全名存放于IP Recycle列表中,这里优先从回收列表中获取IP,从而达到IP固定的效果。

整体删除过程为:由PaaSNg或kube-controller-manager调用apiserver Pod Delete并设置DeletionTimestamp, kubelet监听到删除时间并获取GracefulDeletiontime,删除应用容器, 通知apiserver释放IP(释放IP时获取Pod所属RC,根据是否有对应RC 名称决定是否存放在IP Recycle列表),删除Pause Pod,通知apiserver 删除Pod对象。
另外为了防止IP固定方案中可能出现的问题,我们在kubernetes中加入了额外的REST api: 包括对已分配IP的查询,手动分配/释放IP..。
对目前方案的总结:
容器IP固定方案已上线,运行基本没问题,但稳定性有待提升。主要表现为偶然性不能在预期时间内停止旧Pod,从而无法释放IP造成无法复用(初步原因是由于Docker偶尔的卡顿造成无法在规定时间内停止容器)。我们短期的work around是使用额外添加的REST apiss手动修复,后期IP固定方案会继续加强稳定性并根据需求进行优化。
基于Kubernetes(k8s)网络方案演进的更多相关文章
- 基于Kubernetes/K8S构建Jenkins持续集成平台(上)-2
基于Kubernetes/K8S构建Jenkins持续集成平台(上)-2 Kubernetes实现Master-Slave分布式构建方案 传统Jenkins的Master-Slave方案的缺陷 Mas ...
- 基于Kubernetes/K8S构建Jenkins持续集成平台(下)
基于Kubernetes/K8S构建Jenkins持续集成平台(下) Jenkins-Master-Slave架构图回顾: 安装和配置NFS NFS简介 NFS(Network File System ...
- 基于Kubernetes/K8S构建Jenkins持续集成平台(上)-1
基于Kubernetes/K8S构建Jenkins持续集成平台(上)-1 Jenkins的Master-Slave分布式构建 什么是Master-Slave分布式构建 Jenkins的Master-S ...
- 【Kubernetes】K8S网络方案--最近在看的
K8S网络-最近在看的 Create a Minikube cluster - Kubernetes Kubernetes Documentation - Kubernetes Kubernetes ...
- Kubernetes(k8s)网络插件(CNI)的基准测试对比
Kubernetes是一个伟大的容器"乐队".但它不管理Pod-to-Pod通信的网络.这是容器网络接口(CNI)插件的使命,它是实现容器集群工具(Kubernetes,Mes ...
- 一寸宕机一寸血,十万容器十万兵|Win10/Mac系统下基于Kubernetes(k8s)搭建Gunicorn+Flask高可用Web集群
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_185 2021年,君不言容器技术则已,欲言容器则必称Docker,毫无疑问,它是当今最流行的容器技术之一,但是当我们面对海量的镜像 ...
- k8s 各种网络方案 - 每天5分钟玩转 Docker 容器技术(170)
网络模型有了,如何实现呢? 为了保证网络方案的标准化.扩展性和灵活性,Kubernetes 采用了 Container Networking Interface(CNI)规范. CNI 是由 Core ...
- Kubernetes网络方案的三大类别和六个场景
欢迎访问网易云社区,了解更多网易技术产品运营经验. 本文章根据网易云资深解决方案架构师 王必成在云原生用户大会上的分享整理. 今天我将分享个人对于网络方案的理解,以及网易云在交付 Kubernetes ...
- k8s 各种网络方案【转】
网络模型有了,如何实现呢? 为了保证网络方案的标准化.扩展性和灵活性,Kubernetes 采用了 Container Networking Interface(CNI)规范. CNI 是由 Core ...
随机推荐
- 从技术上分析八叉网www.xxxxxxxxvideos.com的自动定时发布文章功能是怎么实现的
做网站开发的都需要用到网站广告自动定时发布功能,也就是说,编辑在网站后台把文章编写好之后,设置发布时间,点确定后发布,这时在网站前台访客是看不到这篇文章的,必须要等到文章设置的发布时间之后才能看到.八 ...
- BZOJ3675: [Apio2014]序列分割(斜率优化)
Time Limit: 40 Sec Memory Limit: 128 MBSubmit: 4186 Solved: 1629[Submit][Status][Discuss] Descript ...
- 安装psutil时提示缺少python.h头文件(作记录)
通过pip或者源码安装psutil,都会提示缺少python.h头文件,错误提示如下: ... psutil/_psutil_common.c:9:20: fatal error: Python.h: ...
- 新手Linux命令学习
一.dd命令:1.可以复制文件,2.可以制作ios镜像,简单理解就是备份 常用的参数 if 设置输入文件的名称 of 设置输出文件的名称 bs 设置每个“”块“”大小 count 要复制“块” ...
- Java : Spring基础 IOC
使用 ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml" ...
- JavaScript6里出现了哪些新语法、新特征?
ES5是2009年就出来的,目前来说在我写这篇文章的时候基本上ES6在浏览器上面还没有普及,不过Google浏览器是支持ES6语法的,谁让Google是美国生产的呢... ES6现在使用的地方其实还是 ...
- 『Python基础-13』函数 Function
这篇笔记记录的知识点: 函数的基本概念 自定义函数 函数的几种参数 编程的三种方式: 1.OOP 面向对象编程,万物皆对象,以class为主,抽象化 2.POP 面向过程编程,万事皆过程,def定义过 ...
- jxls-1.x导出excel入门——基本操作
请注意,一下内容均基于1.x版本,2.x版本将另开随笔记录 一.概述 JXLS是基于Jakarta POI API的Excel报表生成工具,可以生成精美的Excel格式报表.它采用标签的方式,类似J ...
- MySQL入门第三天(下)——存储过程与存储引擎
一.存储过程 1.简介 原始的SQL执行的流程: 通过存储过程,便可以简化以上流程,那么存储过程是什么,如何进行性能提高呢? 是什么? 存储过程是可编程的函数,在数据库中创建并保存,可以由SQL语句和 ...
- uCOS-II中的任务切换-图解多种任务调度时机与问题
[@.1 任务调度时机] 之前的一篇文章分析了具体的uCOS-II中的任务切换机制,是从函数调用的角度上分析的.这次我具体从整个程序运行的时间上来看,分析多种任务调度发生的时机.以下所有图片均可点击放 ...