K8s扩容

https://blog.csdn.net/lijingjingchn/article/details/115248195

手动:

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):

在这里插入图片描述

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

在这里插入图片描述

自动缩扩容:极致弹性?

参考好文

刚才的例子中,我们是通过命令行的方式来手动调整服务规模的,显然在面对线上真实流量时是不能这么做的,我们希望调度平台能够根据服务的负载来智能地调控规模,进行弹性缩扩容。这时候就轮到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 )]
  • 1

复制代码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
  • 1

复制代码运行上面的命令后,可以在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
  • 1

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

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

大概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
  • 1

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

在这里插入图片描述

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

5. 小结

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

你可能感兴趣的