容器云的背景前端
伴随着微服务的架构的普及,结合开源的Dubbo和Spring Cloud等微服务框架,宜信内部不少业务线逐渐了从原来的单体架构逐渐转移到微服务架构。应用从有状态到无状态,具体来讲将业务状态数据如:会话、用户数据等存储到中间件中服务中。linux
微服务的拆分虽然将每一个服务的复杂度下降,但服务实例的数目却呈现出爆炸式增加,这给运维增长难度,一方面是服务部署、升级,另外一方面是服务的监控故障恢复等。nginx
在2016年,容器技术尤为是Docker迅速流行起来,公司内部开始尝试将容器放到容器内运行,虽然经过容器解决了服务发布问题,但不少容器的运维仍然让运维捉襟见肘。宜信是一家金融科技公司,在引入开源组件的时候,稳定可靠是做为考量的最重要标准,在2017年初kubernetes慢慢成熟,成为容器的管理标准,而且被国内外不少公司采用,在这种背景下,宜信借鉴开源社区和商业PAAS平台产品,基于kubernetes自研一套容器管理平台。git
总体架构github
整个架构围绕kubernetes构建,分为四个层级,最底层主要是基础资源,包括网络、计算、存储,全部的容器都是部署在物理服务器上,容器挂载商业NAS存储,网络经过vxlan互连;中间层核心的是资源调度层,主要完成多集群的管理、发布部署、智能调度、自动伸缩等,这层主要是资源管理和服务编排;左侧面是提供系统安全,主要是为了系统安全和容器镜像安全,右侧面是一套代码自动编译、自动构建、自动部署系统;中间件层主要提供经常使用的中间件服务,Nginx配置和监控告警等;最上层的是用户接入层,主要提供用户的操做入口。总体架构以下图所示:web
Nginx自助管理算法
公司大部分的服务都是经过Nginx反向代理对外提供服务,为了服务的隔离和负载均衡,总计十几套的Nginx集群,这些nginx的版本、配置方式各有不一样,致使单纯靠人工去运维的成本很是高并且容易出错,而且容器的IP地址不固定,没法直接配置到nginx后端。自研了一套nginx管理系统,主要是为了解决nginx的模板化配置,以下图所示:docker
Nginx-mgr提供HTTP请求,负责接收nginx配置请求,并更新到etcd,每一个nginx-agent经过watch Etcd批量刷新nginx的配置。在实际的生产环境里,部署的是阿里开源的Tengine而并不是nginx,因为配置基本相同不作区分。每一个服务都配置了健康检查,这样可以保障在后端故障中自动切换。若是有虚拟机场景须要手动切换,下图展现了手动切换nginx的页面:shell
因为不少业务都是虚拟机和容器混跑的状况下,若是后端是容器,咱们经过kubernetes的API获取容器的IP地址动态刷新。数据库
多集群管理
虽然kubernetes自己存在采用高可用的部署架构,避免单点故障,但这远远还不够,一方面是由于单个kubernetes集群部署在一个机房,若是发生机房级别的故障,将会致使服务中断,另外一方面因为单个kubernetes集群自己故障,如集群的网络配置错误致使整个网络故障等,都将会影响业务的正常使用,在宜信将kubernetes部署在多个机房内,机房之间经过专线互连。那么多集群的管理将成为主要难点:第一是如何分配资源,当用户选择多集群部署后,系统根据每一个集群的资源用量,决定每一个集群分配的容器数量,而且保证每一个集群至少有一个容器。集群自动伸缩时,也会按照此比例建立和回收容器。第二是故障迁移,如图中的集群控制器主要为了解决多集群的自动伸缩和集群故障时的容器迁移,控制器定时检测集群的多个节点,若是屡次失败后将触发集群容器迁移的操做,保障服务可靠运行。
第三是网络和存储的互连,因为跨机房的网络须要互连,咱们采用vxlan的网络方案实现,存储也是经过专线互连。容器的镜像仓库采用Harbor,多集群之间设置同步策略,而且在每一个集群都设置各自的域名解析,分别解析到不一样的镜像仓库。
DNS解析
因为业务人员对容器技术还存在疑虑,因此大部分应用都是虚拟机和容器的混合部署,容器经过域名访问虚拟机和虚拟机经过域名访问容器都是广泛存在的,为了统一管理域名,咱们没有采用kubernetes自带的kube-dns(coreDns)而采用bind提供域名解析。经过kubernetes支持的Default DNS策略将容器的域名指向公司的DNS服务器,并配置域名管理的API动态添加。
网络方案
kubernetes的CNI的网络方案有不少种,主要分为二层、三层和overlay方案。一方面机房并不容许跑BGP协议,而且须要跨机房的主机互连,因此咱们采用了flannel的vxlan方案,为了实现跨机房的互通,两个集群的flannel链接到同一个etcd集群,这样保障网络配置的一致性。老版本的Flannel存在不少问题,包括:路由条数过多,ARP表缓存失效等问题。建议修改为网段路由的形式,而且设置ARP规则永久有效,避免由于etcd等故障致使集群网络瘫痪。
Flannel的使用还须要注意一些配置优化,默认状况下天天都会申请Etcd的租约,若是申请失败会删除etcd网段信息。为了不网段变化,能够将etcd数据节点的ttl置为0(永不过时);Docker默认是会masq全部离开主机的数据包,致使flannel中没法获取源容器的IP地址,经过设置Ipmasq添加例外,排除目标地址为flannel网段数据包;因为flannel使用vxlan的方式,开启网卡的vxlan offloading对性能提高很高。Flannel自己没有网络隔离,为了实现kubernetes的network policy咱们采用canal,它是calico实现kubernetes的网络策略的插件。
CICD
为了支持Devops流程,在最初的版本咱们尝试使用Jenkins的方式执行代码编译,但Jenkins对多租户的支持比较差。在第二版经过kubernetes的Job机制,每一个用户的编译都会启动一个编译的Job,首先会下载用户代码,并根据编译语言选择对应的编译镜像,编译完成后生成执行程序,若是jar或者war文件。经过Dockerfile打成Docker镜像并推送到镜像仓库,经过镜像仓库的webhook触发滚动升级流程。
服务编排
系统设计了应用的逻辑概念,kubernetes虽然有服务的概念,但缺乏服务的关联关系,一个完整的应用一般包括前端、后端API、中间件等多个服务,这些服务存在相互调用和制约的关系,经过定义应用的概念,不只能够作到服务启动前后顺序的控制,还能够统一规划启停一组服务。
日志
容器的日志归集使用公司自研的watchdog日志系统,每台宿主机上经过DaemonSet方式部署日志采集Agent,Agent经过Docker API获取须要采集的容器和日志路径,采集日志并发送到日志中心,日志中心基于elasticsearch开发,提供多维度日志检索和导出。
监控
容器自己资源监控的性能监控经过Cadvisor + Prometheus的方式,容器内业务的监控集成开源的APM监控系统uav(https://github.com/uavorg/uavstack),完成应用的性能监控。uav的链路跟踪基于JavaAgent技术,若是用户部署应用勾选了使用uav监控,系统在构建镜像时将uav的agent植入到镜像内,并修改启动参数。
除了上述几个模块外,系统还集Harbor完成容器镜像的多租户管理和镜像扫描功能;日志审计是记录用户在管理界面的操做,webshell提供用户的web控制台接入,为了支持安全审计,后台会截获用户全部在webshell的操做命令并记录入库;存储管理主要是集成公司商业的NAS存储,为容器直接提供数据共享和持久化;应用商店主要是经过kubernetes的operator提供开发和测试使用的场景中间件服务。
docker不是虚拟机
在容器推广的初期业务开发人员对容器还不是很熟悉,会下意识认为容器就是虚拟机,其实他们不只是使用方式的区别,更是实现方式和原理的差别,虚拟机是经过模拟硬件指令虚拟出操做系统的硬件环境,而容器是在共享内核的前提下提供资源的隔离和限制。下图展现了4.8内核中linux支持的7种namespace。
换句话说,其余的都没有差别,譬如,时钟,全部容器和操做系统都共享同一个时钟,若是修改了操做系统的时间,全部容器都时间都会变化。除此以外,容器内proc文件系统也是没有隔离,看到的都是宿主的信息,这给不少应用程序带来困扰,JVM初始的堆大小为内存总量的1/4,若是容器被限制在2G的内存上限,而宿主机一般都是200+G内存,JVM很容易触发OOM, 解决方案一般是启动时根据内存和CPU的限制设置JVM,或者借助lxcfs等。
Cgroup的资源限制目前对网络和磁盘IO的限制比较弱,v1的cgroup只支持direct IO的限制,但实际的生产环境都是些缓存的。目前咱们也在测试cgroup v2关于IO的限制。当最新的CNI已经支持网络限速,结合tc能够很好的达到这个效果。
Kubernetes优化
Kubernetes自带了不少调度算法,在启动容器以前会经过调度的算法,这些算法都是须要过滤全部的节点并打分排序,大大增长了容器的部署时间,经过删除一些无用的调度算法,从而提升部署的速度。容器采用反亲和的策略,下降物理机故障对服务形成的影响。
虽然kubernetes开启了RBAC,但kubernetes token仍是不建议挂载到业务容器内,经过关闭ServiceAccountToken提高系统的安全。
Docker镜像存储使用direct-lvm的方式,这样性能更优,在部署的时候划分单独的vg,避免由于Docker问题影响操做系统。经过devicemapper存储限制每一个容器系统盘为10G,避免业务容器耗尽宿主机磁盘空间,容器运行时须要限制每一个容器的最大进程数量,避免fork炸弹。
Etcd里面记录了kubernetes核心数据,因此etcd个高可用和定时备份是必须的,在kubernetes集群超过一百个节点之后,查询速度就会下降,经过SSD可以有效提高速度。本系统在kubernetes以外经过数据库保存服务和
关注证书的有效期,在部署kubernetes集群时候,不少都是自签的证书,在不指定的状况下,openssl默认一年的有效期,更新证书须要很是谨慎,由于整个kubernetes的API都是基于证书构建的,全部关联的服务都须要修改。
总结:
Docker容器加K8S编排是当前容器云的主流实践之一,宜信容器集群管理平台也采用这种方案。本文主要分享了宜信在容器云平台技术上的一些探索和实践。本文主要包含了Nginx自助管理、 多集群管理、DNS解析、网络方案、CICD服务编排、 日志监控、kubernetes 优化一些技术工做,以及宜信内部容器云平台化的一些思考,固然咱们还有不少不足,欢迎各路英雄来宜信进行深刻沟通和交流!