“k8s现在发展越来越成熟了,大家可以思考一下,如果让你来设计基于k8s的PaaS平台,要怎么做?k8s是作为PaaS的内核。”
今天组内leader提了个这个问题,刚好这块之前也有些想法,尤其是这些年在百度的Noah,京东云的云翼,商城的JDOS都有过相关维护也有过从零开发的研发经历,也作为业务方深度使用过相关的PAAS平台(Matrix JPAAS ORP ORCP等),看过各种不同的思路,加上我自己的想法和抉择,打算记录下,形成一个比较好的实践说明,后面不断补充。
PAAS我觉得至少要有3块
- CMDB(机器管理+实例管理+权限管理)
- 部署系统(编译构建+分级) 扩展加上包/镜像管理,编排上线等
- 监控系统(物理监控+业务监控) 扩展出趋势图,故障分析等
以及一些周边系统比如网络和域名管理(负载均衡和域名),安全管理(堡垒机+操作审计),作业平台等
CMDB
首推Noah服务树的模式,资料可以参考这里第八页(目前业界多家互联网公司都用了类似的模式)。简单来说就是以树形结构展示资源信息,每个叶子节点下是具体的机器或者实例列表,每个节点上都可以加入配置信息。
配置管理上:
一般会根据公司组织架构划分1 2级节点,或者按运维团队划分。要求公司管理的所有机器都在树上可查,可快速查到机器的归属关系,配置信息等等。除了界面入口外,一般会提供命令行工具给运维团队快速查询节点和机器的相互对应关系,如查询某个节点a.b.c 下的机器列表,或者查询某个机器的归属节点等。并且界面上也有方便的导入导出工具,减少目前部分团队用excel来管理机器的简陋模式,也能方便IDC,安全等团队,查询机器归属时使用,避免不必要的误操作。
权限管理上:
每个节点上都可以设置权限,权限有继承关系,即有上级节点权限的人有权限操作下级节点,以及下级节点上的人员设置,这个后续会和登陆系统(门神),堡垒机系统等打通。即有权限的同学就可以登陆自己的机器,会根据设置的角色,控制权限,比如只有只读账户权限,还是可以sudo其他账户的权限,这里还可以根据公司要求设置审批流.
部署系统
部署系统目前这个时间点来看,可以分为非镜像的部署(k8s出现前的情况),以及镜像的部署。这2套系统应该是相辅相成的,不应该只有一套系统,另外一套系统没有用同样的用户体验来实现。
非镜像的物理机部署
目前越来越少,主推还是镜像部署,不过这个还是有需求的,实现上应该和作业平台同时考虑(即目前运维可能的用ansible或者puppet实现的操作应该也纳入管理),这部分的功能应该用于支持如master节点,或者虚机管理服务等不是太适合部署在容器中的服务。
基于镜像的容器部署
这块是现在的主流,各种细节我一定要都讲下,开始之前我们思考下:之前的部署模式有怎样的问题?1.业务服务挂了,需要运维去启动 2.物理机挂了服务容量受损 3.服务的资源和分布需要运维人工靠经验安排 4.线上版本由于前面的种种原因可能不一致 5.业务混布相互影响 6.单个业务资源使用情况不清晰,无法单独审计 。。。
那么我们选择容器走镜像的部署模式就必须把这些问题解决:
(下面的内容可能会有点杂,我一点一点的写)
从架构上来说目前k8s+docker(阿里的pouch解决了些问题,不过时间不久先关注着)是不二的选择
首先我们要有个架子,我们先部署个k8s集群:k8s的master节点apiserver controllermanager scheduler建议还是物理机部署,不要部署在容器中,减少不必要的麻烦,尤其是etcd部署在有ssd的服务器上比较好
在这个环节中我们有几个抉择:
网络
是选择overlay的网络还是和物理机一样扁平的网络,这里推荐用扁平的网络即和物理机一样的网络,业界普通的方案都是用calico走bgp模式,也可以自己实现我们这边也实现过走macvlan(后面写篇文章介绍怎么实现个).这些都需要公司管IDC网络的同学配合实施
DNS
目前业界的选择多半是coredns了,也推荐我们团队实现的containerdns ,并且建议提前划分好一个二级域名,和相应的办公网和IDC的DNS团队沟通好,将这个子域的解析指向你搭建的DNS服务,这样用户创建的service都能自动成为域名并且在idc和办公网都可以解析。
负载均衡
由于是用的扁平的网络,所以负载均衡用公司既有方案就可以了(理论上来说不太推荐用kube-proxy), 推荐juptier 可以做相应的改造自动支持k8s的service, 我这里是自动关联上了,具体是负载均衡的同学做的就不细表了,没有自己的负载均衡的公司可以参考https://github.com/adohe/kube2haproxy ,不过需要留意的是这些方案都会有些延迟生效的问题
Docker的设置
- docker建议设置上live-restore,便于以后如果升级docker的情况
- docker的镜像存储建议使用direct-lvm 尤其不推荐用loop data的模式,我目前看到几种模式:有用lvm创建一个盘出来,然后用loop data占满,来存储镜像的,然后另外一个lvm盘用来存储用户的数据,还有用一个大的thinpool即docker的镜像和用户的数据;我推荐结合下还是创建2个thinpool,一个存镜像,一个存业务数据,只有一个thinpool的情况下,可能会导致docker的image不会gc
- docker启动的systemd配置记得设置LimitNOFILE=1048576 等一系列参数
镜像仓库
Harbor,没其他选的,需要对后端存储做改进,比如支持公司内的对象存储,账号系统也应该和公司内的账号打通,并且可以实现用户有权限push到 xxx.docker.com/uesrname下(有的团队实现了,有的团队还是人工管理)另外需要注意做好业务镜像的权限限制,避免全公开化。一般为了方便使用我们可能会idc内部用的一个域名是不用授权的,对办公网的是需要授权的,当然做的更好点可以设置个超级账户,podSpec上都写pullSecret。另外镜像仓库可以做CDN(建议)或者P2P方案(后期量大的话可以考虑这个dragonfly或者karken);CDN模式是指在各个机房搭建cache层,不同的机房用不同的harbor的域名,这个可以通过podSpec控制,也可以自己实现admission自动修改
胖容器还是瘦容器
胖容器是指:除了业务进程外,还需要运行别的程序:至少有sshd和crond
瘦容器是指:只有业务进程的程序,尤其是dockerhub上可以直接运行的镜像
服务启停
容器内的业务启停有2个方案
1:通过entrypoint来启停 entrypoint更符合容器的哲学,也并且也方便业务方自己把这个容器拿走调试
2:通过lifecycle来实现 无论是用那种方式启动服务,都建议lifecycle的stop中加入停止的逻辑,方便业务程序优雅退出1
2
3
4
5
6
7lifecycle:
postStart:
exec:
command: ["bin/control", "start"]
preStop:
exec:
command: ["bin/control", "stop" ]
以上两种方式我还没考虑用那种好,是在2个团队,不同的方案,我建议:
- 无论注入的entrypoint的脚本还是lifecycle的脚本都要有自动升级的逻辑,便于后期加入其他功能
- entrypoint 中不建议把sshd 和crond 写进去,防止sshd需要修改配置重启的情况,比如开发pam模块,后期需要重启
健康检查
我现在见过两种容器的玩法:一种还是当成虚拟机在用。虽然走了容器全量部署的模式,但是不管业务方的死活,容器起来后尝试启动业务的程序,无论启动成功与否以及后面运行中服务挂了,都不管;还有一种会管业务的状态,会帮助业务启停
个人建议加上livenessProbe的健康检查,在容器内业务异常时可以帮助其自动恢复,(注意需要收集重启的次数,便于查看以及预防过于频繁的重启的情况)在一个分布式系统的情况下,单机的异常不再应该让运维同学分心,另外这里应当作为一个featrue,业务方也可以选择不设置,即2种方案都支持,而不应该都是个默认值.1
2
3
4
5
6
7
8
9
10
11
12
13
14
"livenessProbe": {
"exec": {
"command": [
"bin/control",
"status"
]
},
"initialDelaySeconds": 3,
"timeoutSeconds": 30,
"periodSeconds": 20,
"successThreshold": 1,
"failureThreshold": 3
},
pod的亲和反亲和
不同的业务需求也不太一
在线业务建议设置上反清q
容器的request和limit
- 容器的request设置成规格大小,limit设置成一个更大的值,容忍业务资源超用
- 容器的limit设置规格大小,request设置成一个小值,便于超卖的实现,业务不可以超用
- request limit设置成一样,并且开启cpuManager绑核心使用
推荐2,3结合使用:2对正常的业务使用,3对混布的离线计算节点使用
附加VIP功能:)
- 改造k8s支持动态修改pod的request limit而不需要重启容器,支持原地调小request和limit
- 新增restartPolcy,支持容器异常时可以直接本地start之前的容器,而不用create一个container,加快异常恢复的时间
PAAS的形态
我认为一个PAAS应该很好的支持一些通用的服务(如tomcat,nodejs,php等),用选择的模式减少研发人员需要做的事情,便于他们直接快速使用,同时也应该支持通用的方式支持自定义的需求,如百度之前对于业务方的要求,无论什么语言的服务都应该提供一个统一的接口脚本,提供start stop status pid等操作(这样可以很好的支持c一类的程序) 。不过我们从设计上应该考虑设计成通用的方案,同时UI上更好的支持通用的服务。
这方面其实主要涉及基础镜像如何制作,以及服务如何启停
未完待续