智慧印刷工坊

智慧印刷工坊

kubernetes 弹性伸缩之 Node自动扩容/缩容

admin 124 27
弹性伸缩概述:

从传统意义上,弹性伸缩主要解决的问题是容量规划与实际负载的矛盾。蓝色水位线表示可用资源容量负载的增量不断扩大容差,红色曲线表示可用资源实际负载变化。弹性伸缩就是要解决当实际负载增加,而更多资源容量没来得及反应的问题。


Kubernetes弹性伸缩布局:

在Kubernetes平台中,资源分为两个维度:

node级别:K8s将多台服务器抽象一个积累资源池,每个Node提供这些资源

Pod级别:Pod是K8s最小部署单元,运行实际的应用程序,使用request和limit为Pod配额因此,K8s实现弹性伸缩也是这两个级别,当Node资源充裕情况下,Pod可任意弹性,当不足情况下需要弹性增加节点来扩容资源池。

针对Pod负载:当Pod资源不足时,使用HPA(HorizontalPodAutoscaler自动增加Pod副本数量

针对Node负载:当集群资源池不足时,使用CA(ClusterAutoscaler)自动增加Node(目前ClusterAutoscaler只适用于公有云)

Node自动扩容/缩容:

Node弹性伸缩有两种方案:

ClusterAutoscaler:是一个自动调整Kubernetes集群大小的组件,需要与公有云一起使用,例如AWS、Azure、Aliyun,项目地址:

自研发:根据Node监控指标或者Pod调度状态判断是否增加Node,需要一定开发成本

Node自动扩容/缩容:实现思路:


Node自动扩容/缩容:ClusterAutoscaler

ClusterAutoscaler支持的云提供商:

阿里云:

AWS:

Azure:

GCE:

GKE:

Node自动扩容/缩容:自研发【大概思路】

小编把他们分为两个场景:

公司资源充足,有闲置的机器,当发现node资源不足时,随时扩容(可以提前先部署好node,打上污点,这样pod就不会分配过来)

将要有活动上线,预估范围量比较大,同时公司资源紧张,没有空闲机器,需要申请机器,再自动化部署node,加入到k8s集群中

自研,新增Node大概思路:

申请一台服务器

调用Ansible脚本部署Node组件并自动加入集群

检查服务是否可用,加入监控(prometheus)

完成Node扩容,接收新Pod


本文基于ansible快速的增加部署node:

项目参考:

执行ansible命令自动化增加Node:

说明:[本实验所用的K8S集群也是基于这个项目自动化搭建的]

环境声明:


为了直观的看见效果,我们先创建一个下POD的资源,因为K8s集群的机器都为4C6G配置,

那我们的POD资源,最小内存和最大内存限制在5000M,副本数为4

先查看下当前K8S集群有几个node

[root@master-1yaml]:apps/v1kind:Deploymentmetadata:creationTimestamp:nulllabels:app:web-testname:web-testspec:replicas:3selector:matchLabels:app:web-teststrategy:{}template:metadata:creationTimestamp:nulllabels:app:web-testspec:containers:-image:nginxname:nginxresources:requests:memory:"5000Mi"limits:memory:"5050Mi"

[root@master-1yaml]可以看到一个POD是没有创建成功的,显示为Ping状态

[root@master-1yaml]仔细查看下这个没有启动成功的POD的状态:
[root@master-1yaml]kubectldescribepodweb-test-c8c599597-6gzksName:web-test-c8c599597-6gzksNamespace:defaultPriority:0Node:noneLabels:app=web-testpod-template-hash=c8c599597Annotations:noneStatus:PingIP:IPs:noneControlledBy:ReplicaSet/web-test-c8c599597Containers:nginx:Image:nginxPort:noneHostPort:noneLimits:memory:5050MiRequests:memory:5000MiEnvironment:noneMounts:/var/run/secrets//serviceaccountfromdefault-token-pz842(ro)Conditions:TypeStatusPodScheduledFalseVolumes:default-token-pz842:Type:Secret(avolumepopulatedbyaSecret)SecretName:default-token-pz842Optional:falseQoSClass:BurstableNode-Selectors:noneTolerations:/not-ready:/unreachable:NoExecutefor300sEvents:TypeReasonAgeFromMessage-------------------------WarningFailedSchedulingunknowndefault-scheduler0/3nodesareavailable:3/3nodesareavailable:3Insufficientmemory

gitclone

Cloninginto'ansible-install-k8s'

remote:Enumeratingobjects:349,done.

remote:Countingobjects:100%(349/349),done.

remote:Compressingobjects:100%(303/303),done.

remote:Total349(delta172),reused102(delta21),pack-reused0

Receivingobjects:100%(349/349),152.26KiB|0bytes/s,done.

Resolvingdeltas:100%(172/172),done.

mkdir/root/binary_pkg

[root@ansible~]ls-l

total0

drwxr-xr-x5rootroot230Dec2916:19ansible-install-k8s

drwxr-xr-x2rootroot280Dec2916:18binary_pkg

vimansible-install-k8s/hosts

[newnode]

192.168.31.67node_name=node3

..

使用ansible-playbook去部署【效果因人而异,无非就是主机的环境不一样导致的,自己慢慢调整还是可以自动化去部署的】

PLAY[0.系统初始化]********************************************************************************************************************************************************************************************TASK[common:添加hosts]***********************************************************************************************************************************************************************************changed:[192.168.31.67]PLAY[1.部署Docker]*****************************************************************************************************************************************************************************************TASK[docker:创建临时目录]************************************************************************************************************************************************************************************changed:[192.168.31.67]TASK[分发并解压docker二进制包]************************************************************************************************************************************************************************************changed:[192.168.31.67]=(item=/root/binary_pkg/)TASK[移动docker二进制文件]**************************************************************************************************************************************************************************************changed:[192.168.31.67]TASK[docker:分发service文件]*******************************************************************************************************************************************************************************changed:[192.168.31.67]TASK[docker:创建目录]**************************************************************************************************************************************************************************************changed:[192.168.31.67]TASK[配置docker]*******************************************************************************************************************************************************************************************changed:[192.168.31.67]TASK[启动docker]*******************************************************************************************************************************************************************************************changed:[192.168.31.67]TASK[docker:查看状态]**************************************************************************************************************************************************************************************changed:[192.168.31.67]TASK[docker:debug]*************************************************************************************************************************************************************************************ok:[192.168.31.67]={"_lines":["Client:","DebugMode:false","","Server:","Containers:0","Running:0","Paused:0","Stopped:0","Images:0","ServerVersion:19.03.9","StorageDriver:overlay2","BackingFilesystem:xfs","Supportsd_type:true","NativeOverlayDiff:true","LoggingDriver:json-file","CgroupDriver:cgroupfs","Plugins:","Volume:local","Network:bridgehostipvlanmacvlannulloverlay","Log:awslogsfluentdgcplogsgelfjournaldjson-filelocallogentriessplunksyslog","Swarm:inactive","Runtimes:runc","DefaultRuntime:runc","InitBinary:docker-init","containerdversion:7ad184331fa3e55e52b890ea95e65ba581ae3429","runcversion:dc9208a3303feef5b3839f4323d9beb36df0a9dd","initversion:fec3683","SecurityOptions:","seccomp","Profile:default","KernelVersion:3.10.0-957._64","OperatingSystem:CentOSLinux7(Core)","OSType:linux","Architecture:x86_64","CPUs:4","TotalMemory:5.651GiB","Name:","ID:DASE:GZTC:3KCB:5LWP:UT6D:ITEI:OAR4:QLDK:NBJ5:ZGK4:7UZL:BPK2","DockerRootDir:/var/lib/docker","DebugMode:false","Registry:","Labels:","Experimental:false","InsecureRegistries:","192.168.31.70","127.0.0.0/8","RegistryMirrors:","","LiveRestoreEnabled:false","ProductLicense:CommunityEngine"]}PLAY[2.部署K8SNode]***************************************************************************************************************************************************************************************TASK[node:创建工作目录]**************************************************************************************************************************************************************************************changed:[192.168.31.67]=(item=bin)changed:[192.168.31.67]=(item=cfg)changed:[192.168.31.67]=(item=ssl)changed:[192.168.31.67]=(item=logs)TASK[node:创建cni插件目录]***********************************************************************************************************************************************************************************changed:[192.168.31.67]=(item=/opt/cni/bin)changed:[192.168.31.67]=(item=/etc/cni/)TASK[node:创建临时目录]**************************************************************************************************************************************************************************************ok:[192.168.31.67]TASK[node:分发并解压k8s二进制包]********************************************************************************************************************************************************************************changed:[192.168.31.67]=(item=/root/binary_pkg/)TASK[node:分发并解压cni插件二进制包]******************************************************************************************************************************************************************************changed:[192.168.31.67]=(item=/root/binary_pkg/)TASK[移动k8snode二进制文件]************************************************************************************************************************************************************************************changed:[192.168.31.67]TASK[node:分发k8s证书]*************************************************************************************************************************************************************************************changed:[192.168.31.67]=(item=)changed:[192.168.31.67]=(item=)changed:[192.168.31.67]=(item=)TASK[node:分发k8s配置文件]***********************************************************************************************************************************************************************************changed:[192.168.31.67]=(item=)changed:[192.168.31.67]=(item=)changed:[192.168.31.67]=(item=)changed:[192.168.31.67]=(item=)changed:[192.168.31.67]=(item=)changed:[192.168.31.67]=(item=)TASK[node:分发service文件]*********************************************************************************************************************************************************************************changed:[192.168.31.67]=(item=)changed:[192.168.31.67]=(item=)TASK[启动k8snode组件]***************************************************************************************************************************************************************************************changed:[192.168.31.67]=(item=kubelet)changed:[192.168.31.67]=(item=kube-proxy)TASK[node:分发预准备镜像]*************************************************************************************************************************************************************************************changed:[192.168.31.67]TASK[node:导入镜像]****************************************************************************************************************************************************************************************changed:[192.168.31.67]PLAYRECAP************************************************************************************************************************************************************************************************192.168.31.67:ok=22changed=20unreachable=0failed=0skipped=0rescued=0ignored=0
kubectlgetcsr

NAMEAGESIGNERNAMEREQUESTORCONDITION

node-csr--W_LjdS8pWW3h18Z_/kube-apiserver-client-kubeletkubelet-bootstrapPing

[root@master-1~]可以看到新部署的node-3节点已经成功加入到k8s集群中了

[root@master-1~]增加Node后,查看下pod在node的运行情况

[root@master-1yaml]可以看到刚刚没有启动的POD自动运行在Node-3上,这个就是Node资源的扩容

下面我们再来看看,自动减少Node

自动减少node:

如果你想从Kubernetes集群中删除节点,正确流程如下:

1、获取节点列表

kubectlgetnode

2、设置不可调度(uncordon则表示取消不可被调度)

kubectlcordonnode_name

3、驱逐节点上的Pod

kubectldrainnode_name--ignore-daemonsets

4、移除节点

kubectldeletenodenode_name

或者:

1、获取节点列表

kubectlgetnode

2、给Node打上污点,并且设置为NoExecute,驱逐节点上的Pod

kubectltaintnodenode_namekey=value:NoExecute

3、移除节点

kubectldeletenodenode_name

如果这块自动化的话,前提要获取长期空闲的Node,然后执行这个步骤。

案例:

某电商公司,促销活动结束后,资源使用率降低,需要把闲置节点从集群中踢出来,恢复原先

(1)方法一:

kubectlgetpods-owide

NAMEREADYSTATUSRESTARTSAGEIPNODENOMINATEDNODEREADINESSGATESweb-test-5cdbd79b55-6xtnt1/1/1/1/1

kubectltaintnodenode-3repair=yes:NoExecute

node/node-3tainted

kubectldescribenodesnode-3|grep-itaint

Taints:repair=yes:NoExecute

kubectlgetpods-owide

NAMEREADYSTATUSRESTARTSAGEIPNODENOMINATEDNODEREADINESSGATES

web-test-5cdbd79b55-6xtnt1/1

web-test-5cdbd79b55-87pqt1/1

web-test-5cdbd79b55-p54nq1/1

web-test-5cdbd79b55-t8pcx1/1

kubectldeletenodenode-3

kubectlgetnodes

[root@master-1yaml]先看下当前pod运行在哪些Node主机上

[root@master-1yaml]当前集群中的Node主机

[root@master-1yaml]设置node-2节点不可调度

[root@master-1yaml]可以看到node-1的status状态变为了SchedulingDisabled

[root@master-1yaml]驱逐node-2节点上的Pod

[root@master-1yaml]看下驱逐后的POD

可以看到web-test-5cdbd79b55-6xtntPod已经不在node-2上了

[root@master-1yaml]移除节点,将node-2移出集群

[root@master-1yaml]kubectlgetnodes

[root@master-1yaml]#kubectlgetpods-owide

NAMEREADYSTATUSRESTARTSAGEIPNODENOMINATEDNODEREADINESSGATESweb-test-5cdbd79b55-6xtnt1/1/1/1/1

到此,本篇结束,下篇和大家分享下kubernetes弹性伸缩之Pod自动扩容/缩容