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

在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自动扩容/缩容:实现思路:
ClusterAutoscaler支持的云提供商:
阿里云:
AWS:
Azure:
GCE:
GKE:
Node自动扩容/缩容:自研发【大概思路】
小编把他们分为两个场景:
公司资源充足,有闲置的机器,当发现node资源不足时,随时扩容(可以提前先部署好node,打上污点,这样pod就不会分配过来)
将要有活动上线,预估范围量比较大,同时公司资源紧张,没有空闲机器,需要申请机器,再自动化部署node,加入到k8s集群中
自研,新增Node大概思路:申请一台服务器
调用Ansible脚本部署Node组件并自动加入集群
检查服务是否可用,加入监控(prometheus)
完成Node扩容,接收新Pod

项目参考:
执行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:3Insufficientmemorygitclone
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=0kubectlgetcsrNAMEAGESIGNERNAMEREQUESTORCONDITION
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/1kubectltaintnodenode-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自动扩容/缩容





