1、前言
随着容器技术的快速发展,诸如Kubernetes(以下简称k8s)此类容器编排技术应运而生,当人们逐渐意识到容器是云计算的未来,越来越多的人投入到容器技术的怀抱,也就是在这短短几年里,k8s赢得了这场战争,实际上,k8s的带来的影响已经远超容器管理领域本身。 服务网格的概念已经走进大家视线,而这也恰好让人们意识到,k8s岂不正是实现微服务的一种解决方案,这也进一步将k8s推向风口浪尖。
2、k8s的核心概念
本文是建立在已经对docker技术有一定了解的基础上的,就不再赘述docker相关的概念了,初步介绍一下k8s的核心概念和思想,目的是让大家快速熟悉,更好理解接下来的内容。
1. POD
这是k8s里定义的最小单元,因为k8s是源于google,而该项目目标也不仅仅是支持docker
这一种容器技术,抽象出一个pod
的概念,其实k8s本身不关心pod
内部是什么类型容器,可以有多个容器在pod
内启动(官方建议单一pod单一容器),pod
内容器共享网络,共享存储,pod
可以由控制器启动,控制器也就是k8s负责编排的组件之一,常见的有
Deployment
,通过指定副本数量等属性,根据配置的pod模版,部署无状态的服务,能够提供强力的回滚,滚动更新等能力,这个也是最常用的一种;Statefulset
,有状态副本集,一般部署etcd
,elasticsearch
等等这种有状态的服务,一般同时会挂载存储卷(也是k8s中定义的一种对象);DeamonSet
,守护进程集,一般指定节点部署一些服务,比如cpu监控等;
2. Service
pod
被启动后,在k8s中是无法从外部访问的,这时候就需要service
将其暴露出去,service
相当于pod
的负载均衡器,一般通过以下方式:
CluserIP
(默认), 通过iptables
做nat规则转换,将流量转到相应的pod
内,集群内部服务之间访问就是通过这种方式;NodePort
,暴露主机随机端口,kube-proxy
组件将相应规则写入iptables
表,访问主机端口将会被引流至相应的pod,这种方式能够对集群外部暴露服务;LoadBalancer
,NodePort
的变种,一般由具体的云服务商实现,比如阿里云,一旦service创建后, 会自动创建一个负载均衡,会自动做80:3xxxx端口的映射,流量通过负载均衡,会转到相应主机端口,最终根据iptables
规则 将流量转发到pod内;ingress
, 作为7层http负载,作用相当于反向代理的nginx
的服务,流量通过一台负载均衡进来,可由ingress
配置域名或者路径,转发到相应service
;
这里只是简单介绍核心概念,深入学习的话请移步官方文档
3、技术对比
有几种竞争技术可用于管理大型Docker部署和基于容器的服务。你可能听说过其中一些退役的解决方案:Docker Swarm,Apache Mesos,OpenStack Magnum等。然而,现在Kubernetes已经淘汰了其中大多数竞争对手
会被与k8s拿来对比的,应该就Docker Swarm
可以应战,swarm是docker原生的集群工具,部署简单,而且对于熟悉docker的人,学习成本低,而k8s最令开发者头疼的莫过于非常高的复杂度,和学习成本,不过目前不管是阿里云还是其他云服务商,都同时提供了这两个解决方案,而且都有在生产环境大规模使用的案例,这里拿比较成熟的阿里云的这两种解决方案对比:
- 资源调度 这一点上两者都都做到可以按集群资源调度分配,只是调度的粒度不同,swarm是容器,而k8s是pod;
- 自动伸缩 swarm本身不支持,但是依靠阿里云实现了该功能,而k8s有水平自动拓展HPA,可以根据监控数据进行自动伸缩;
- 负载均衡 k8s本身提供了多种方案,内部service是通过iptables实现,外部7层负载均衡有ingress层,阿里云也提供了LoadBalancer支持负载均衡; swarm本身没有负载均衡层,不过阿里云也通过
- 滚动更新 swarm目前也支持了滚动更新,并且在阿里云上实现了蓝绿部署等,k8s本身的deployment支持滚动升级
- 容灾恢复 swarm没有做到,在节点挂掉的情况下,服务无法快速恢复; k8s是能够做到这一点,副本控制器能够维持副本数量,节点挂掉也会迅速从其他节点启动一定数量的副本,并且比较完善的监控也可以及时发现问题;
而从swarm本身来看的话,由于其是集成到docker中的,swarm集群只会有两层交互,容器启动是毫秒级,要远快于k8s, 但是兼容的docker API也使得其无法进行更精细的管理, 相对的k8s有副本控制器可以监控并维护容器的生命周期,有pod可以进行更加精细的管理, 总结来看,其实swarm本身的重心是放在了docker容器编排上,而k8s的却是在考虑如何管理,事实上,现在还是越来越多的人倾向于使用k8s,也正是看中了其诸多优点。
4、实践
我们在使用自建集群的过程中,由于官方的dashboard操作yaml的学习成本很高,所以我们使用了wayne这个开源的k8s管理项目,其功能包含但不限于dashbaord的功能,权限管理,人员划分,部门划分等,属于是一个面向大型项目团队的k8s集群管理后台,以下是一些实例
在使用过程中,改后台,确实是带来了许多便利,可以免去k8s的yaml配置的学习成本,通过可视化界面完成服务的创建,我们前期的一些试验性服务都是通过这个部署; 但是同时也存在一些弊端,在k8s的基础之上,抽象出了更多的概念,包括项目划分,权限管理等等,这些模块的目的是为了针对大型团队,控制项目人员,分配资源,不过同时,这些额外的概念对于使用者,尤其是对k8s也不熟悉,只是关心如何部署服务的开发人员,会混淆k8s本身的概念,导致学习成本进一步上升,针对小型团队,一些复杂的资源划分,项目划分功能反而显得冗余。
当然,正如前文说的,目前我们还是倾向于是用现有的云提供商所实现的k8s解决方案;在阿里云上的实践也证明了其带了的许多便利,确实会极大减少集群维护人员的负担,其相对完善的后台,也能够满足绝大多数情况的开发人员使用,其优势还主要体现在以下方面:
- 阿里云维护的高可用集群,免去了自维护的所面临的机房,网络诸多问题;
- 负载均衡的支持,不需要自己搭建配置ingress组件,创建服务会自动生成负载均衡
- 阿里云镜像仓库支持,可以直接从镜像创建pod,且有创建模版,可以轻松的创建服务;
- 云盘等文件系统支持,非常方便的声明和挂载存储卷;
- 优秀的监控报警系统,从多个维度,对服务进行详细的监控,灵活配置报警;
6、搭建注意事项
想要更加深入的理解和使用k8s, 通过自建k8s集群是一种不错的手段,搭建方法参考官网即可; 这里有一些搭建过程中的值得注意的一些细节:
- 建议使用阿里的源
cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://mirrors.aliyun.com/kubernetes/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=0
EOF
- 如果遇到
kubelet
和docker
的文件驱动不一致,可以修改docker的驱动
//;/etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"]
}
kube-proxy
默认使用iptables,考虑性能可以改为ipvs
yum install -y ipvsadm
- 查看内核模块是否加载
lsmod|grep ip_vs
- 加载内核模块
modprobe -- ip_vs
modprobe -- ip_vs_rr
modprobe -- ip_vs_wrr
modprobe -- ip_vs_sh
modprobe -- nf_conntrack_ipv4
- 修改 kube-proxy 配置
kubectl edit configmap kube-proxy -n kube-system
,把mode
改为ipvs
,scheduler
默认为空,使用轮训方式负载均衡
7、压测数据分析
自建集群进行了一些性能测试,以下有一些压测数据的分析,仅供参考 压测环境
k8s集群 并发60
代码语言:javascript复制Task63 | ReqTPS: 4522 | RespTPS: 4522 | RT: 12 | TotalSend: 3144614 | TotalPass: 3144558 | TotalFail: 0 | Thread: 60 | 2019-08-01 18:14:55
Task63 | ReqTPS: 4538 | RespTPS: 4536 | RT: 12 | TotalSend: 3140137 | TotalPass: 3140081 | TotalFail: 0 | Thread: 60 | 2019-08-01 18:14:54
Task63 | ReqTPS: 4583 | RespTPS: 4584 | RT: 12 | TotalSend: 3135644 | TotalPass: 3135590 | TotalFail: 0 | Thread: 60 | 2019-08-01 18:14:53
Task63 | ReqTPS: 4615 | RespTPS: 4616 | RT: 12 | TotalSend: 3131107 | TotalPass: 3131052 | TotalFail: 0 | Thread: 60 | 2019-08-01 18:14:52
Task63 | ReqTPS: 4525 | RespTPS: 4527 | RT: 12 | TotalSend: 3126538 | TotalPass: 3126482 | TotalFail: 0 | Thread: 60 | 2019-08-01 18:14:51
Task63 | ReqTPS: 4480 | RespTPS: 4480 | RT: 12 | TotalSend: 3122058 | TotalPass: 3122000 | TotalFail: 0 | Thread: 60 | 2019-08-01 18:14:50
Task63 | ReqTPS: 4537 | RespTPS: 4531 | RT: 12 | TotalSend: 3117623 | TotalPass: 3117565 | TotalFail: 0 | Thread: 60 | 2019-08-01 18:14:49
Task63 | ReqTPS: 4529 | RespTPS: 4530 | RT: 12 | TotalSend: 3113131 | TotalPass: 3113079 | TotalFail: 0 | Thread: 60 | 2019-08-01 18:14:48
Task63 | ReqTPS: 4521 | RespTPS: 4522 | RT: 12 | TotalSend: 3108647 | TotalPass: 3108594 | TotalFail: 0 | Thread: 60 | 2019-08-01 18:14:47
Task63 | ReqTPS: 4495 | RespTPS: 4496 | RT: 12 | TotalSend: 3104171 | TotalPass: 3104117 | TotalFail: 0 | Thread: 60 | 2019-08-01 18:14:46
相比之下,裸机java
代码语言:javascript复制Task63 | ReqTPS: 7391 | RespTPS: 7392 | RT: 7 | TotalSend: 3970815 | TotalPass: 3970763 | TotalFail: 0 | Thread: 60 | 2019-08-01 17:42:24
Task63 | ReqTPS: 7363 | RespTPS: 7366 | RT: 7 | TotalSend: 3963498 | TotalPass: 3963445 | TotalFail: 0 | Thread: 60 | 2019-08-01 17:42:23
Task63 | ReqTPS: 7231 | RespTPS: 7229 | RT: 7 | TotalSend: 3956209 | TotalPass: 3956153 | TotalFail: 0 | Thread: 60 | 2019-08-01 17:42:22
Task63 | ReqTPS: 7394 | RespTPS: 7392 | RT: 7 | TotalSend: 3949050 | TotalPass: 3948996 | TotalFail: 0 | Thread: 60 | 2019-08-01 17:42:21
Task63 | ReqTPS: 7227 | RespTPS: 7228 | RT: 7 | TotalSend: 3941730 | TotalPass: 3941678 | TotalFail: 0 | Thread: 60 | 2019-08-01 17:42:20
Task63 | ReqTPS: 7078 | RespTPS: 7080 | RT: 8 | TotalSend: 3934575 | TotalPass: 3934522 | TotalFail: 0 | Thread: 60 | 2019-08-01 17:42:19
Task63 | ReqTPS: 6932 | RespTPS: 6933 | RT: 8 | TotalSend: 3927568 | TotalPass: 3927513 | TotalFail: 0 | Thread: 60 | 2019-08-01 17:42:18
Task63 | ReqTPS: 6887 | RespTPS: 6882 | RT: 8 | TotalSend: 3920698 | TotalPass: 3920642 | TotalFail: 0 | Thread: 60 | 2019-08-01 17:42:17
Task63 | ReqTPS: 6837 | RespTPS: 6840 | RT: 8 | TotalSend: 3913880 | TotalPass: 3913829 | TotalFail: 0 | Thread: 60 | 2019-08-01 17:42:16
Task63 | ReqTPS: 6866 | RespTPS: 6864 | RT: 8 | TotalSend: 3907111 | TotalPass: 3907057 | TotalFail: 0 | Thread: 60 | 2019-08-01 17:42:15
k8s集群 并发40
代码语言:javascript复制Task63 | ReqTPS: 4569 | RespTPS: 4571 | RT: 8 | TotalSend: 1716607 | TotalPass: 1716573 | TotalFail: 0 | Thread: 40 | 2019-08-01 18:58:59
Task63 | ReqTPS: 4571 | RespTPS: 4568 | RT: 8 | TotalSend: 1712084 | TotalPass: 1712048 | TotalFail: 0 | Thread: 40 | 2019-08-01 18:58:58
Task63 | ReqTPS: 4517 | RespTPS: 4520 | RT: 8 | TotalSend: 1707559 | TotalPass: 1707526 | TotalFail: 0 | Thread: 40 | 2019-08-01 18:58:57
Task63 | ReqTPS: 4542 | RespTPS: 4541 | RT: 8 | TotalSend: 1703087 | TotalPass: 1703051 | TotalFail: 0 | Thread: 40 | 2019-08-01 18:58:56
Task63 | ReqTPS: 4473 | RespTPS: 4473 | RT: 8 | TotalSend: 1698590 | TotalPass: 1698555 | TotalFail: 0 | Thread: 40 | 2019-08-01 18:58:55
Task63 | ReqTPS: 4510 | RespTPS: 4514 | RT: 8 | TotalSend: 1694162 | TotalPass: 1694127 | TotalFail: 0 | Thread: 40 | 2019-08-01 18:58:54
Task63 | ReqTPS: 4539 | RespTPS: 4536 | RT: 8 | TotalSend: 1689697 | TotalPass: 1689658 | TotalFail: 0 | Thread: 40 | 2019-08-01 18:58:53
Task63 | ReqTPS: 4563 | RespTPS: 4561 | RT: 8 | TotalSend: 1685203 | TotalPass: 1685167 | TotalFail: 0 | Thread: 40 | 2019-08-01 18:58:52
Task63 | ReqTPS: 4573 | RespTPS: 4575 | RT: 8 | TotalSend: 1680686 | TotalPass: 1680652 | TotalFail: 0 | Thread: 40 | 2019-08-01 18:58:51
Task63 | ReqTPS: 4555 | RespTPS: 4555 | RT: 8 | TotalSend: 1676159 | TotalPass: 1676123 | TotalFail: 0 | Thread: 40 | 2019-08-01 18:58:50
总的来说,使用k8s集群的优势在于使用镜像,方便快速部署,以及集群的资源控制等方面,性能相对裸机会有一些损耗,不过这些损耗对于绝大多数服务是没有任何影响的 。
代码语言:javascript复制