1. 前言

自动缩扩容是现代化的容器调度平台带给我们的最激动人心的一项能力。在上规模的业务系统中我们无时无刻不面临着这样的难题:用户的流量往往随着时间波动,甚至偶尔出现不可预测的峰值(毛刺流量),每当流量增加时都需要手工的对应用进行扩容,峰值流量消失后又需要将扩容的机器回收,运维起来费时费力。

幸运的是,k8s这样的容器调度平台正在逐渐帮助我们解决这样的问题,它带来的AutoScaler功能目前已经支持在多个不同维度上的弹性缩扩容,可以根据应用的负载情况进行自适应。尽管在一些较为苛刻的场景下,由于容器启动速度等原因的限制,AutoScaler的效果还不尽人意,但相信在不久的将来,自动缩扩容方案将会完全成熟,届时我们将轻松获取具有强大弹性能力的服务集群。

现在来试着使用一下k8s的Scale相关功能吧。

2. 手动调整服务规模

我们可以使用kubectl提供的命令来手动调整某个Deployment的规模,也就是其包含的Pod数量,这里拿上一节里创建的HelloWorld服务来作为例子,当前的deployment状态如下:

  • DISIRED 表示配置时声明的期望副本数
  • CURRENT 表示当前正在运行的副本数
  • UP-TO-DATE 表示符合预期状态的副本数(比如某个副本宕机了,这里就不会计算那个副本)
  • AVAILABLE 表示目前可用的副本数

我们可以使用kubectl scale命令来手动调整deployment的规模,现在尝试把helloworld服务的副本数量扩充到4个:

执行命令后,k8s很快就为我们创建了另外3个helloworld的副本,这时候整个服务就有多个实例在运行了,那么对应Service的负载均衡功能便会生效,可以看到Service的状态里已经侦测到多个EndPoint:

当我们连续调用service时,可以看到每次实际调用的pod都不同(这里对服务的源码做了一些修改,打印出了hostname):

同理,我们也可以用同样的方式把服务缩容,比如把副本集的数量下调到两个:

3. 自动缩扩容:极致弹性?

参考好文

刚才的例子中,我们是通过命令行的方式来手动调整服务规模的,显然在面对线上真实流量时是不能这么做的,我们希望调度平台能够根据服务的负载来智能地调控规模,进行弹性缩扩容。这时候就轮到k8s中的AutoScaler出场了。

到目前为止,k8s一共提供了3个不同维度的AutoScaler,如下图:

k8s把弹性伸缩分为两类:

  • 资源维度:保障集群资源池大小满足整体规划,当集群内的资源不足以支撑产出新的pod时,就会触发边界进行扩容
  • 应用维度:保障应用的负载处在预期的容量规划内

对应两种伸缩策略:

  1. 水平伸缩

    • 集群维度:自动调整资源池规模(新增/删除Worker节点)
    • Pod维度:自动调整Pod的副本集数量
  2. 垂直伸缩

    • 集群维度:不支持
    • Pod维度:自动调整应用的资源分配(增大/减少pod的cpu、内存占用)

其中最为成熟也是最为常用的伸缩策略就是HPA(水平Pod伸缩),所以下面以它为例来重点分析,官方文档在此:kubernetes.io/docs/tasks/…

3.1 基本流程

任何弹性系统的缩扩容都无外乎于以下几个步骤:

  1. 采集监控指标
  2. 聚合监控指标,判断是否需要执行缩扩容
  3. 执行缩扩容动作

下面就按照这个顺序来分析HPA的工作方式,这里先给出一个HPA大体的架构图:

3.2 监控指标

根据官方文档的描述,HPA是使用巡检(Control Loop)的机制来采集Pod资源使用情况的,默认采集间隔为15s,可以通过Controller Manager(Master节点上的一个进程)的–horizontal-pod-autoscaler-sync-period参数来手动控制。

目前HPA默认采集指标的实现是Heapster,它主要采集CPU的使用率;beta版本也支持自定义的监控指标采集,但尚不稳定,不推荐使用。

因此可以简单认为,HPA就是通过CPU的使用率作为监控指标的。

3.3 聚合算法

采集到CPU指标后,k8s通过下面的公式来判断需要扩容多少个pod:

desiredReplicas = ceil[currentReplicas * ( currentMetricValue / desiredMetricValue )]

复制代码ceil表示向上取整,举个实际例子,假设某个服务运行了4个Pod,当前的CPU使用率为50%,预期的CPU使用率为25%,那么满足预期的实际Pod数量就是4 * (50% / 25%) = 8个,即需要将Pod容量扩大一倍,增加4个Pod来满足需求。

当然上述的指标并不是绝对精确的,首先,k8s会尽可能的让指标往期望值靠近,而不是完全相等,其次HPA设置了一个容忍度(tolerance)的概念,允许指标在一定范围内偏离期望值,默认是0.1,这就意味着如果你设置调度策略为CPU预期使用率 = 50%,实际的调度策略会是小于45%或者大于55%进行缩扩容,HPA会尽力把指标控制在这个范围内(容忍度可以通过–horizontal-pod-autoscaler-tolerance来调整)。

另外有两点需要说明的细节:

  • k8s做出决策的间隔,它不会连续地执行扩缩容动作,而是存在一定的cd,目前扩容动作的cd为3分钟,缩容则为5分钟。
  • k8s针对扩容做了一个最大限制,每次扩容的pod数量不会大于当前副本数量的2倍。

3.4 HPA实践

最后我们来尝试实际使用一下HPA,依然是使用kubectl命令行的方式来创建:

kubectl autoscale deployment helloworld --cpu-percent=10 --min=1 --max=5

复制代码运行上面的命令后,可以在dashboard看到HPA已经被创建,策略是以CPU使用率10%为临界值,最少副本集数量为1,最大为5:

使用kubectl get hpa也可以看到:

但是这里出现了异常,targets的当前CPU使用率始终显示为unknown,网上说是因为副本集里没有配置resources导致的。我们需要在dashboard里找到对应的副本集,然后在spec.containers.resources里声明requestslimits值:

其中requests表示pod所需要分配的资源配额,limits表示单个pod最大能够获取到的资源配额。

配置完之后还是没有出现指标,继续百度,发现没有安装heapster支持,那就安装,具体方法可见此文,注意需要把国外gcr的镜像通过阿里云代理一把才能安装(如果你不太会搞,可以用我转好的,见github),influxDBgrafanaheapster三个组件都装好后,记得再装一把heapster rbac(在kubeconfig/rbac目录下),最后重启一波minikube,打开控制台,可以看到节点页面已经有了指标图像:

kubectl top命令也能正常返回数值了:

然而,kubectl get hpa显示cpu的当前指标还是unknown,郁闷,进到deployment里看一把日志:

可以看到HPA一直在报无法从metrics API获取请求资源的错误,github走一波,找到一个类似的issue,原因是1.9版本以后的k8s默认的监控指标来源从heapster变成了metrics-server(我用的1.0,坑),不过要再安装一套metrics-server实在太麻烦了,可以通过修改kube-controller-manager的启动参数来禁用这个新特性。
minikube ssh进入到vm内部,然后找到/etc/kubernetes/manifests/kube-controller-manager.yaml这个文件,在启动参数里加上–horizontal-pod-autoscaler-use-rest-clients=false,这时候对应的容器组会自动重启更新,再执行kubectl get hpa,可以看到cpu的指标终于Ok了:


留下了感动的泪水,终于可以开始压测试水了,赶紧搞个buzybox压起来:

kubectl run -i --tty load-generator --image=busybox /bin/sh

写个循环去访问我们的helloworld服务(为了更快的出效果,我把服务的scale缩减到只有一个副本集,直接压这个pod的ip)

/ # while true; do wget -q -O- http://172.17.0.5:8080; done

大概2,3分钟后就能看到结果,此时查看hpa的状态,可以看到已经触发水平扩容,副本集的数量由1个追加到4个:

dashboard上也能看到效果:

关掉压测脚本,静置一会儿,再看HPA的状态:

自动缩容到了1个副本集,那么HPA的实践使用到这里就算是结束了。

4. 更新、发布、回滚

服务代码必然是会经常修改的,当代码发生变动时,就需要重新打包生成镜像,然后进行发布和部署,来看看在k8s中是如何对这些步骤进行处理的。

现在我们对代码做了一些改动,加上了hostname的输出,然后打包形成了一个2.0版本的新镜像,下面需要把这个新版本的镜像部署到k8s的容器集群上,使用kubectl set imagedeployment上指定新的镜像:

kubectl set image deployments/helloworld helloworld=registry.cn-qingdao.aliyuncs.com/gold-faas/gold-demo-service:2.0

执行该命令后,可以从kubectldashboard中看到,新的容器组正在被创建,同时旧的容器组也在被回收:

最终所有的旧版本pod都会被回收,只留下新发布版本的容器组副本集:

来测试一下服务是否更新:

假设我们的发布到线上的版本出现了致命的问题,需要紧急将服务回退到上一个版本,该怎么做呢?使用kubectl rollout undo即可,来看看效果:

可以看到执行回滚命令后,新版本的pod开始被回收,同时上一个版本镜像所对应的pod被唤醒(这里速度非常快,我感觉k8s在发布完新服务后可能并不会立刻销毁历史版本的pod实例,而是会缓存一段时间,这样非常快速的回滚,只要把service的负载均衡指回历史版本的pod就可以了)

回滚完成后再度请求服务,可以发现服务已经变回了上一个版本的内容:

上面这些发布和回滚的特性在k8s中被称为滚动更新,它允许我们按照一定的比例逐步(可以手工设置百分比)更新pod,从而实现平滑更新和回滚,也可以借此实现类似蓝绿发布金丝雀发布的功能。

5. 小结

通过实际操作体验了k8s的缩扩容以及发布机制,虽然遇到了几个坑,但整体上用起来还是非常丝滑的,到这里k8s的基本功能就探索的差不多了,从下一篇开始将会继续深入分析k8s的原理,敬请期待!

k8s学习笔记:缩扩容更新相关推荐

  1. K8S 学习笔记三 核心技术 Helm nfs prometheus grafana 高可用集群部署 容器部署流程

    K8S 学习笔记三 核心技术 2.13 Helm 2.13.1 Helm 引入 2.13.2 使用 Helm 可以解决哪些问题 2.13.3 Helm 概述 2.13.4 Helm 的 3 个重要概念 ...

  2. Java开发面试高频考点学习笔记(每日更新)

    Java开发面试高频考点学习笔记(每日更新) 1.深拷贝和浅拷贝 2.接口和抽象类的区别 3.java的内存是怎么分配的 4.java中的泛型是什么?类型擦除是什么? 5.Java中的反射是什么 6. ...

  3. Go语言开发学习笔记(持续更新中)

    Go语言开发学习笔记(持续更新中) 仅供自我学习 更好的文档请选择下方 https://studygolang.com/pkgdoc https://www.topgoer.com/go%E5%9F% ...

  4. JavaSE学习笔记(持续更新)

    这里写目录标题 JavaSE学习笔记(持续更新) Java跨平台原理与核心机制 1.跨平台原理: 2.两种核心机制: JDK11的安装流程 Java程序开发的三个步骤(无编辑器版) Eclipse安装 ...

  5. NetworkX学习笔记【持续更新】

    NetworkX学习笔记[持续更新] 写在前面的话 学习资料 关于安装 写在前面的话 networkx是一个python包,用于创建.操作和研究复杂网络的结构.动态和功能.我最初是想找一找SDN路由算 ...

  6. CUDA学习笔记(持续更新——蜗速)

    CUDA学习笔记(持续更新--蜗速) 1.CUDA 程序实现流程如下 2.内存管理 3.核函数 4.全局数据访问唯一索引 5.设备管理 附录代码 1.CUDA 程序实现流程如下 将数据从CPU内存拷贝 ...

  7. 微服务基础知识点学习笔记(持续更新)

    微服务基础知识点学习笔记(持续更新) Conrtoller层 整体包括:HTTP协议,JavaWeb三大组件(filter.servlet.listener).SpringMVC(SpringMVC的 ...

  8. NumPy个人学习笔记【持续更新】

    NumPy个人学习笔记[持续更新] 来源:快速入门教程 - NumPy中文文档 目录 基础知识 数组的创建 打印数组 基本操作 通用函数 索引.切片和迭代 形状操作 更改数组的形状 将不同数组堆叠在一 ...

  9. ① ESP8266 开发学习笔记_By_GYC 【更新 ets_printf 函数 使ESP_IDF 能够支持浮点数打印】

    ① ESP8266 开发学习笔记_By_GYC [更新 ets_printf 函数 使ESP_IDF 能够支持浮点数打印] 在我们日常的开发过程中,经常使用到的一个功能就是串口打印功能.在ESP826 ...

  10. C语言学习笔记Day3——持续更新中... ...

    上一篇文章C语言学习笔记Day2--持续更新中- - 八. 容器 1. 一维数组 1.1 什么是一维数组 当数组中每个元素都只带有一个下标(第一个元素的下标为0, 第二个元素的下标为1, 以此类推)时 ...

最新文章

  1. Fallout 3完结
  2. 在Linux执行命令报错”Arg list too long”的原因分析
  3. 机器学习:怎样才能做到从入门到不放弃?
  4. java线程的创建线程_多线程(Thread、线程创建、线程池)
  5. 1-9其他数据库注入
  6. iangularjs 模板_2018-web前端的自我介绍-优秀word范文 (5页)
  7. div 隐藏_div的position属性
  8. Quartz + Oracle 分布式Job实现
  9. 设计一个60T数据仓库及大数据分析平台,医院数字化该怎么做?
  10. 基于比较的排序算法集
  11. 10.RabbitMQ实战 --- 监控
  12. 3. Ubuntu LAMP 环境搭建
  13. mysql 5.1 到 mysql 5.2的出现的索引BTREE问题 use near 'USING BTREE
  14. 用iptables实现NAT
  15. 2022年05月系统集成项目管理工程师考试知识点分布
  16. 企业IT架构转型之道(书)总结以及反思
  17. 计算机毕业设计JAVA‘大学生心理健康咨询管理系统mybatis+源码+调试部署+系统+数据库+lw
  18. python移动文件,将一个文件夹里面的文件移动到另一个文件夹
  19. PLC和变频器通讯方式
  20. 基于HostLink协议的Fins命令读写

热门文章

  1. 计算机抓桌面图用,图片——要抓就抓最清晰的 -电脑资料
  2. 全国计算机奥林匹克竞赛试题及答案,奥林匹克物理竞赛试题及答案
  3. VS2017中自用部分插件的设置的翻译或功能介绍——Word Highlight With Margin
  4. jpg和png的区别
  5. Mysql 中 “必知” 的单行处理函数
  6. linux中fork函数及子进程父进程执行顺序
  7. 匹配追踪和正交匹配追踪
  8. 第二章 学生指导(01 小学生身心发展的规律 02 学生心理发展与教育 03 小学生的学习)
  9. 移动鼠标(动态)改变svg图标的颜色
  10. 学习Linux的常见故障(待更新)