第1章-kubernetes-Pod自动扩缩容
本章所讲内容:
1.1 深入剖析 k8s 应用自动扩缩容的方案
1.2 自动扩缩容的方案有哪些?
1.3 如何实现 k8s 中的应用自动扩缩容?
1.4 利用 HPA 基于 CPU 指标实现 pod 自动扩缩容
1.5 利用 HPA 基于内存指标实现 pod 自动扩缩容
1.6 kubernetes cluster-autoscaler
1.7 VPA 实现 Pod 自动调度
实验环境:
[root@k8s-master01 ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
k8s-master01 Ready master 142d v1.16.0
k8s-master02 Ready master 142d v1.16.0
k8s-master03 Ready master 142d v1.16.0
k8s-node01 Ready <none> 142d v1.16.0
k8s-node02 Ready <none> 142d v1.16.0
自动扩缩容:对pod(HPA VPA)、node(CA)实现自动扩缩容
HPA:根据资源监控对pod实现自动扩缩容(增加pod数量)
VPA:根据pod资源使用情况,对pod更改request值(扩容pod容量,删除之前的pod,重新创建大容量的pod)(容器无法超过设置的limit值)
KPA:基于请求参数,自动扩缩容pod(不常用)
资源使用率:metric server
HPA仅能对deployment管理的pod实现自动扩缩容,statefulset、daemonsets管理的pod无法实现HPA(除非二次开发)
实验:
安装metric-server服务:
导入镜像
修改apiserver配置文件(1.23以后的版本)
- --enable-aggregator-routing=true
每个节点重启kubelet服务
基于components.yaml文件部署metric-server
验证安装是否成功(kubectl top nodes)
利用HPA进行自动扩缩容(基于CPU)
导入基础镜像php
基于基础镜像构建新镜像,并到处镜像到每一个工作节点
php-apache.yaml创建pod
命令创建HPA,作用在php-apache的deployment控制器上(维持pod的CPU使用率在59%,若超过则增加pod,若减少则减少pod,最大10.最小1)
测试自动扩缩容
导入busybox、nginx镜像到工作节点
基于busybox镜像创建pod,并进入,批量访问php-apache的pod
实时查看hpa和pod数量(一段时间后会自动扩容,若停止批量访问,则一段时间后会缩容)
利用HPA进行自动扩缩容(基于MEM)(若CPU,MEM同时设置,两者为 “或” 关系)
nginx.yaml创建pod
hpa-v1.yaml创建hpa
测试自动扩缩容
进入nginx-pod中,使用dd命令增加内存使用率
实时查看hpa和pod数量(一段时间后自动扩容,若停止访问,则一段时间后会缩容)
CA:节点自动扩缩容(云服务能实现)
VPA实现pod垂直扩缩容
安装VPA
工作节点导入镜像(vpa-admission vpa-recommand vpa-updater)
master节点导入autoscaler-master压缩包,解压
每个节点升级openssl(编译安装时,可用 "-j 8" 多线程进行)
进入autoscaler-master目录下,执行vpa-up.sh(安装vpa)
测试VPA实现pod自动调度
自动更新关闭(updateMode: "off")
创建名字空间vpa
vpa-1.yaml创建deployment(app=nginx)
vpa-service-1.yaml创建service
vpa-nginx.yaml创建VPA(作用于vpa名字空间中app=nginx的pod)
查看vpa详细信息,验证
lower bound:容器可用资源最小的资源限制
target:期望目标
uncapped target:若没有限制目标时
upper bound:最大资源限制
自动更新开启(updateMode: "Auto")
vpa-nginx-1.yaml创建deployment
vpa-nginx.yaml更改限制值后重新创建vpa(等待pod删除后,重新创建)
1.1 深入剖析 k8s 应用自动扩缩容的方案
为什么要自动扩缩容?
在实际的业务场景中,我们经常会遇到某个服务需要扩容的场景(例如:测试对服务压测、电商平台秒杀、大促活动、或由于资源紧张、工作负载降低等都需要对服务实例数进行扩缩容操作)。
在 k8s 中扩缩容分为两种:
1、Node 层面:
在使用 kubernetes 集群经常遇到的一个问题是,我应该保持多大的节点规模来满足应用需求呢? cluster-autoscaler 的出现解决了这个问题, 可以通过 cluster-autoscaler 实现节点级别的动态添加与删除,动态调整容器资源池,应对峰值流量
2、Pod 层面:
我们一般会使用 Deployment 中的 replicas 参数,设置多个副本集来保证服务的高可用,但是这是一个固定的值,比如我们设置 10 个副本,就会启 10 个 pod 同时 running 来提供服务。
如果这个服务平时流量很少的时候,也是 10 个 pod 同时在running,而流量突然暴增时,又可能出现 10 个 pod 不够用的情况。针对这种情况怎么办?就需要自动扩缩容:
Kubernetes 对 Pod 的扩缩容分为:
手动和自动两种
1、手动模式:通过 kubectl scale 命令,这样需要每次去手工操作一次,而且不确定什么时候业务请求量就很大了,所以如果不能做到自动化的去扩缩容的话,这也是一个很麻烦的事情
2、自动模式:如果 Kubernetes 系统能够根据 Pod 当前的负载的变化情况来自动的进行扩缩容就
好了,因为这个过程本来就是不固定的,频繁发生的,所以纯手工的方式不是很现实
1.2 自动扩缩容的方案有哪些?
kubernetes HPA(Horizontal Pod Autoscaling)
通过此功能,只需简单的配置,便可以利用监控指标(cpu 使用率、内存使用率)自动的扩容或缩容服务中 Pod 数量,当业务需求增加时,系统将无缝地自动增加适量 pod 容器,提高系统稳定性。
kubernetes KPA(Knative Pod Autoscaler)
基于请求数对 Pod 自动扩缩容,KPA 的主要限制在于它不支持基于 CPU 的自动扩缩容。
kubernetes VPA(Vertical Pod Autoscaler)
垂直 Pod 自动扩缩容,VPA 会基于 Pod 的资源使用情况自动为集群设置资源占用的限制,从而让集群将 Pod 调度到有足够资源的最佳节点上。VPA 也会保持最初容器定义中资源 request 和 limit 的占比。
它会根据容器资源使用率自动设置 pod 的 CPU 和内存的requests,从而允许在节点上进行适当的调度,以便为每个 Pod 提供适当的可用的节点。它既可以缩小过度请求资源的容器,也可以根据其使用情况随时提升资源不足的容量。
1.3 如何实现 k8s 中的应用自动扩缩容?
1.3.1 基于 HPA
水平pod自动扩缩容
要想实现自动扩缩容,需要先考虑如下几点:
1. 通过哪些指标决定扩缩容?
HPA v1 版本可以根据 CPU 使用率来进行自动扩缩容:
但是并非所有的系统都可以仅依靠 CPU 或者 Memory 指标来扩容,对于大多数 Web 应用的后端来说,基于每秒的请求数量进行弹性伸缩来处理突发流量会更加的靠谱,所以对于一个自动扩缩容系统来说,我们不能局限于 CPU、Memory 基础监控数据,每秒请求数 RPS 等自定义指标也是十分重要。
HPA v2 版本可以根据自定义的指标进行自动扩缩容
2. 如何采集资源指标?
如果我们的系统默认依赖 Prometheus,自定义的 Metrics 指标则可以从各种数据源或者exporter 中获取,基于拉模型的 Prometheus 会定期从数据源中拉取数据。 也可以基于 metrics- server 自动获取节点和 pod 的资源指标
1.3.2 基于 KPA
1、根据并发请求数实现自动扩缩容
2、设置扩缩容边界实现自动扩缩容
扩缩容边界:应用程序提供服务的最小和最大的pod数量。通过设置应用程序提供服务的最小和最大pod数量实现自动扩缩容
相比HPA,KPA会考虑更多的场景,其中一个比较中要的是流量突发的时候
1.3.3 基于 VPA
当目前运行pod的节点资源达不到VPA的推荐值,就会执行pod驱逐,重新部署新的足够资源的服务。VPA是K8S比较新的功能,还没有在生产环境大规模实践过,不建议在线上环境使用自动更新模式,但是使用推荐模式你可以更好了解服务的资源使用情况。
官网:kubernetes/autoscaler · GitHub
1.4 利用 HPA 基于 CPU 指标实现 pod 自动扩缩容
HPA 全称是 Horizontal Pod Autoscaler,翻译成中文是 POD 水平自动伸缩, HPA 可以基于CPU 利用率对 deployment 中的 pod 数量进行自动扩缩容(除了 CPU 也可以基于自定义的指标进行自动扩缩容)。pod 自动缩放不适用于无法缩放的对象,比如 DaemonSets。
HPA 由 Kubernetes API 资源和控制器实现。控制器会周期性的获取平均 CPU 利用率,并与目标值相比较后调整 deployment 中的副本数量。
statefulset 创建 pod 能用HPA? 不能
1.4.1 HPA 工作原理
pod资源使用率:pod中的服务占用pod中总资源的百分比
HPA 是根据指标来进行自动伸缩的,目前 HPA 有四个版本:
HPA 的 API 有四个版本,通过 kubectl api-versions | grep autoscal 可看到
[root@k8s-master01 ~]# kubectl api-versions | grep autoscal
autoscaling/v1
autoscaling/v2
autoscaling/v2beta1
autoscaling/v2beta2
autoscaling/v1 支持基于 CPU 指标的缩放。
autoscaling/v2:支持基于内存指标扩容缩容。
指标从哪里来?
K8S 从 1.8 版本开始,CPU、内存等资源的 metrics 信息可以通过 Metrics API 来获取,用户可以直接获取这些 metrics 信息(例如通过执行 kubect top 命令),HPA 使用这些 metics 信息来实现动态伸缩。
Metrics server:
1、Metrics server 是 K8S 集群资源使用情况的聚合器
2、从 1.8 版本开始,Metrics server 可以通过 yaml 文件的方式进行部署
3、Metrics server 收集所有 node 节点的 metrics 信息
1.4.2 安装数据采集组件 metrics-server
metrics-server 是一个集群范围内的资源数据集和工具,同样的,metrics-server 也只是显示数据,并不提供数据存储服务,主要关注的是资源度量 API 的实现,比如 CPU、文件描述符、内存、请求延时等指标,metric-server 收集数据给 k8s 集群内使用,如 kubectl,hpa,scheduler 等。
1. 部署 metrics-server 组件
#通过离线方式获取镜像
需要的镜像是:docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server:v0.6.1,镜像所在地址在课件,可自行下载,如果大家机器不能访问外部网络,可以把镜像上传到 k8s 的各个节点,按如下方法手动解压:
导入镜像:
[root@k8s-master01 ~]# docker load -i metrics-server-0.6.1.tar.gz
[root@k8s-node01 ~]# docker load -i metrics-server-0.6.1.tar.gz
或者
[root@k8s-master01 ~]# docker pull registry.cn-hangzhou.aliyuncs.com/google_containers/metrics-server:v0.6.1
部署 metrics-server 服务
#在/etc/kubernetes/manifests 里面改一下 apiserver 的配置
注意:这个是 k8s 在 1.17 的新特性,如果是 1.16 版本的可以不用添加,1.17 以后要添加。这个参数的作用是 Aggregation 允许在不修改 Kubernetes 核心代码的同时扩展 Kubernetes API。
[root@k8s-master01 ~]# vim /etc/kubernetes/manifests/kube-apiserver.yaml
增加如下内容:
- --enable-aggregator-routing=true
#重新更新 apiserver 配置:
[root@k8s-master01 ~]# systemctl restart kubelet
[root@k8s-master02 ~]# systemctl restart kubelet
[root@k8s-master03 ~]# systemctl restart kubelet
#部署 metrics-server 服务
[root@k8s-master01 ~]# mkdir metrics
[root@k8s-master01 ~]# cd !$
cd metrics
[root@k8s-master01 metrics]# vim components.yaml
[root@k8s-master01 ~]# kubectl apply -f components.yaml
#验证 metrics-server 是否部署成功
[root@k8s-master01 ~]# kubectl get pods -n kube-system | grep metrics
[root@k8s-master01 ~]# kubectl get pod -n kube-system |grep metrics
metrics-server-79dd7fc689-qfsb6 1/1 Running 0 25s
[root@k8s-master01 ~]# kubectl top nodes
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
k8s-master01 222m 5% 936Mi 25%
k8s-master02 209m 5% 937Mi 25%
k8s-master03 165m 4% 972Mi 26%
k8s-node01 57m 2% 507Mi 29%
k8s-node02 55m 2% 439Mi 25%
[root@k8s-master01 ~]# kubectl top pods -n kube-system
NAME CPU(cores) MEMORY(bytes)
calico-kube-controllers-677cd97c8d-8vb5b 1m 12Mi
calico-node-2ntkd 34m 99Mi
calico-node-6j6sk 30m 91Mi
calico-node-h9z5f 30m 97Mi
calico-node-n5895 22m 94Mi
calico-node-vj8sj 19m 93Mi
coredns-65c54cc984-bwl5c 1m 12Mi
coredns-65c54cc984-x2wtk 1m 16Mi
etcd-k8s-master01 36m 129Mi
etcd-k8s-master02 30m 125Mi
etcd-k8s-master03 31m 126Mi
kube-apiserver-k8s-master01 40m 290Mi
kube-apiserver-k8s-master02 37m 320Mi
kube-apiserver-k8s-master03 40m 298Mi
kube-controller-manager-k8s-master01 2m 20Mi
kube-controller-manager-k8s-master02 2m 23Mi
kube-controller-manager-k8s-master03 18m 56Mi
kube-proxy-57wpj 5m 16Mi
kube-proxy-fm5lx 6m 18Mi
kube-proxy-lqn7n 5m 18Mi
kube-proxy-rrtxh 12m 18Mi
kube-proxy-zrks5 8m 16Mi
kube-scheduler-k8s-master01 2m 20Mi
kube-scheduler-k8s-master02 2m 18Mi
kube-scheduler-k8s-master03 3m 19Mi
metrics-server-79dd7fc689-qfsb6 3m 19Mi
1.4.3 创建 php-apache 服务,利用 HPA 进行自动扩缩容。
基于 dockerfile 构建一个 PHP-apache 项目
1)创建并运行一个 php-apache 服务 使用 dockerfile 构建一个新的镜像,在 k8s 的 xuegod63 节点构建
[root@k8s-master01 ~]# ctr -n=k8s.io images import php.tar.gz
或者
[root@k8s-master01 ~]# docker load -i php.tar.gz
[root@k8s-master01 ~]# mkdir php
[root@k8s-master01 ~]# cd php/
[root@k8s-master01 ~]# cat dockerfile
FROM php:5-apache
ADD index.php /var/www/html/index.php
RUN chmod a+rx index.php
[root@k8s-master01 php]# vim index.ph
<?php
$x = 0.0001;
for ($i = 0; $i <= 1000000;$i++) {
$x += sqrt($x);
}
echo "OK!";
?>
#构建镜像
#打包镜像
#解压镜像
可以把镜像传到 k8s 的各个工作节点,通过 docker load -i hpa-example.tar.gz 进行解压:
[root@xuegod63 php]# scp hpa-example.tar.gz xuegod64:/root/
[root@k8s-master01 php]# for i in n1 n2
do scp hpa-example.tar.gz $i:/root/
ssh $i "docker load -i /root/hpa-example.tar.gz ; rm -rf /root/hpa-example.tar.gz"
done
通过 deployment 部署一个 php-apache 服务
[root@k8s-master01 php]# vim php-apache.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: php-apache
spec:
selector:
matchLabels:
run: php-apache
replicas: 1
template:
metadata:
labels:
run: php-apache
spec:
containers:
- name: php-apache
image: k8s.gcr.io/hpa-example:v1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
resources:
limits:
cpu: 500m
requests:
cpu: 200m
---
apiVersion: v1
kind: Service
metadata:
name: php-apache
labels:
run: php-apache
spec:
ports:
- port: 80
selector:
run: php-apache
#更新资源清单文件
kubectl apply -f php-apache.yaml
deployment.apps/php-apache created
service/php-apache created #验证 php 是否部署成功
[root@xuegod63 ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
php-apache-7d8fdb687c-bq8c7 1/1 Running 0 31s
1.4.4 创建 HPA
php-apache 服务正在运行,使用 kubectl autoscale 创建自动缩放器,实现对 php-apache 这个deployment 创建的 pod 自动扩缩容,下面的命令将会创建一个 HPA,HPA 将会根据 CPU,内存等资源指标增加或减少副本数,创建一个可以实现如下目的的 hpa:
1) 让副本数维持在 1-10 个之间(这里副本数指的是通过 deployment 部署的 pod 的副本数)
2) 将所有 Pod 的平均 CPU 使用率维持在 50%(通过 kubectl run 运行的每个 pod 如果是 200毫核,这意味着平均 CPU 利用率为 100 毫核)
#给上面 php-apache 这个 deployment 创建 HPA
#上面命令解释说明
kubectl autoscale deployment php-apache (php-apache 表示 deployment 的名字)
-- cpu-percent=50(表示 cpu 使用率不超过 50%)
--min=1(最少一个 pod)
--max=10(最多 10 个 pod) #验证 HPA 是否创建成功
[root@k8s-master01 php]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
php-apache Deployment/php-apache 0%/50% 1 10 1 19s
注:由于我们没有向服务器发送任何请求,因此当前 CPU 消耗为 0%(TARGET 列显示了由相应的
deployment 控制的所有Pod 的平均值)。
1.4.5 压测 php-apache 服务,只是针对 CPU 做压测
#把 busybox.tar.gz 和 nginx-1-9-1.tar.gz 上传到 xuegod64 上,手动解压:
[root@k8s-master01 php]# for i in n1 n2
do scp busybox.tar.gz $i:/root/
scp nginx-1-9-1.tar.gz $i:/root/
ssh $i "docker load -i /root/busybox.tar.gz;rm -rf /root/busybox.tar.gz"
ssh $i "docker load -i /root/nginx-1-9-1.tar.gz; rm -rf /root/nginx-1-9-1.tar.gz"
done
启动一个容器,并将无限查询循环发送到 php-apache 服务(复制 k8s 的 master 节点的终端,也就是打开一个新的终端窗口):
[root@k8s-master01 php]# kubectl run v1 -it --image=busybox --image-pull-policy=IfNotPresent /bin/sh
登录到容器之后,执行如下命令
在一分钟左右的时间内,我们通过执行以下命令来看到更高的 CPU 负载
[root@k8s-master01 ~]# kubectl get hpa
显示如下:
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS
php-apache Deployment/php-apache 231%/50% 1 10 4
上面可以看到,CPU 消耗已经达到 256%,每个 pod 的目标 cpu 使用率是 50%,所以,php- apache 这个 deployment 创建的 pod 副本数将调整为 5 个副本,为什么是 5 个副 本,因为256/50=5
显示如下:
NAME READY STATUS RESTARTS AGE
php-apache-5694767d56-b2kd7 1/1 Running 0 18s php-apache-5694767d56-f9vzm 1/1 Running 0 2s php-apache-5694767d56-hpgb5 1/1 Running 0 18s
php-apache-5694767d56-mmr88 1/1 Running 0 4h13m php-apache-5694767d56-zljkd 1/1 Running 0 18s
显示如下:
注意:可能需要几分钟来稳定副本数。由于不以任何方式控制负载量,因此最终副本数可能会与此示例不同。
停止对 php-apache 服务压测,HPA 会自动对 php-apache 这个 deployment 创建的 pod 做缩
容
停止向 php-apache 这个服务发送查询请求,在 busybox 镜像创建容器的终端中,通过
C 把刚才 while 请求停止,然后,我们将验证结果状态:
显示如下:
显示如下:
通过上面可以看到,CPU 利用率下降到 0,因此 HPA 自动将副本数缩减到 1。注意:自动缩放副本可能需要几分钟。
1.5利用HPA 基于内存指标实现 pod 自动扩缩容
1、创建一个 nginx 的 pod
[root@k8s-master01 ~]# mkdir memory
[root@k8s-master01 ~]# cd memory/
[root@k8s-master01 memory]# cat nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-hpa
spec:
selector:
matchLabels:
app: nginx
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.9.1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
name: http
protocol: TCP
resources:
requests:
cpu: 0.01
memory: 25Mi
limits:
cpu: 0.05
memory: 60Mi
---
apiVersion: v1
kind: Service
metadata:
name: nginx
labels:
app: nginx
spec:
selector:
app: nginx
type: NodePort
ports:
- name: http
protocol: TCP
port: 80
targetPort: 80
nodePort: 30080
2、验证 nginx 是否运行
[root@k8s-master01 memory]# kubectl get pod -l app=nginx
NAME READY STATUS RESTARTS AGE
nginx-hpa-7f5d6fbfd9-fgcz5 1/1 Running 0 74s
nginx 的 pod 里需要有如下字段,否则 hpa 会采集不到内存指标
resources:
requests:
cpu: 0.01 memory: 25Mi limits:
cpu: 0.05 memory: 60Mi
3、创建一个 hpa
[root@k8s-master01 memory]# cat hpa-v1.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa
spec:
maxReplicas: 10
minReplicas: 1
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-hpa
metrics:
- type: Resource
resource:
name: memory
target:
averageUtilization: 60
type: Utilization
备注,如何把 cpu 指标也加进去?
[root@k8s-master01 memory]# cat hpa-v1.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa
spec:
maxReplicas: 10
minReplicas: 1
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-hpa
metrics:
- type: Resource
resource:
name: memory
target:
averageUtilization: 60
type: Utilization
- type: Resource
resource:
name: cpu
target:
averageUtilization: 50
type: Utilization
#更新资源清单文件
查看创建的 hpa
[root@k8s-master01 memory]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
nginx-hpa Deployment/nginx-hpa 5%/60%, 0%/50% 1 10 1 19s
php-apache Deployment/php-apache 0%/50% 1 10 1 21m
4、压测 nginx 的内存,hpa 会对 pod 自动扩缩容
登录到上面通过 pod 创建的 nginx,并生成一个文件,增加内存
[root@k8s-master01 memory]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-hpa-7f5d6fbfd9-fgcz5 1/1 Running 0 11m
php-apache-74895944c9-qqgzp 1/1 Running 0 27m
v1 1/1 Running 0 20m
[root@k8s-master01 memory]# kubectl exec -it nginx-hpa-7f5d6fbfd9-fgcz5 -- /bin/sh
#
# dd if=/dev/zero of=/tmp/a
[root@k8s-master01 php]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
nginx-hpa Deployment/nginx-hpa 200%/60%, 220%/50% 1 10 4 5m31s
上面的 targets 列可看到 200%/60%,200%表示当前 cpu 使用率,60%表示所有 pod 的 cpu 使用率维持在 60%,现在 cpu 使用率达到 200%,所以 pod 增加到 4 个
[root@k8s-master01 php]# kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-hpa 5/5 5 5 14m
[root@k8s-master01 php]# kubectl get pod |grep nginx
nginx-hpa-7f5d6fbfd9-924mh 1/1 Running 0 92s
nginx-hpa-7f5d6fbfd9-fgcz5 1/1 Running 0 15m
nginx-hpa-7f5d6fbfd9-jdcsd 1/1 Running 0 92s
nginx-hpa-7f5d6fbfd9-tmw2w 1/1 Running 0 92s
nginx-hpa-7f5d6fbfd9-wfh4x 1/1 Running 0 77s
5、取消对 nginx 内存的压测,hpa 会对 pod 自动缩容
删除/tmp/a 这个文件
显示如下,可看到内存使用率已经下降:
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
nginx-hpa Deployment/nginx-hpa 28%/60%, 2%/50% 1 10 5 7m55s
显示如下,deployment 的pod 又恢复到 1 个了:
1.6 kubernetes cluster-autoscaler
1、什么是 cluster-autoscaler
Cluster Autoscaler (CA)是一个独立程序,是用来弹性伸缩 kubernetes 集群的。它可以自动根据部署应用所请求的资源量来动态的伸缩集群。当集群容量不足时,它会自动去 Cloud Provider (支持GCE、GKE 和 AWS)创建新的 Node,而在 Node 长时间资源利用率很低时自动将其删除以节省开支。
项目地址:https://github.com/kubernetes/autoscaler
2、Cluster Autoscaler 什么时候伸缩集群?
在以下情况下,集群自动扩容或者缩放:
扩容:由于资源不足,某些 Pod 无法在任何当前节点上进行调度
缩容: Node 节点资源利用率较低时,且此 node 节点上存在的 pod 都能被重新调度到其他 node
节点上运行
3、什么时候集群节点不会被 CA 删除?
1) 节点上有 pod 被 PodDisruptionBudget 控制器限制。
2) 节点上有命名空间是 kube-system 的 pods。
3) 节点上的 pod 不是被控制器创建,例如不是被 deployment, replica set, job, stateful set 创建。
4) 节点上有 pod 使用了本地存储
5) 节点上 pod 驱逐后无处可去,即没有其他 node 能调度这个 pod
6) 节点有注解:"cluster-autoscaler.kubernetes.io/scale-down-disabled": "true"(在 CA
1.0.3 或更高版本中受支持)
扩展:什么是 PodDisruptionBudget?
通过 PodDisruptionBudget 控制器可以设置应用 POD 集群处于运行状态最低个数,也可以设置应用 POD 集群处于运行状态的最低百分比,这样可以保证在主动销毁应用 POD 的时候,不会一次性销毁太多的应用 POD,从而保证业务不中断
4、Horizontal Pod Autoscaler 如何与 Cluster Autoscaler 一起使用?
Horizontal Pod Autoscaler 会根据当前 CPU 负载更改部署或副本集的副本数。如果负载增加, 则 HPA 将创建新的副本,集群中可能有足够的空间,也可能没有足够的空间。如果没有足够的资源,CA 将尝试启动一些节点,以便 HPA 创建的 Pod 可以运行。如果负载减少,则 HPA 将停止某些副本。结
果,某些节点可能变得利用率过低或完全为空,然后 CA 将终止这些不需要的节点。
扩展:如何防止节点被 CA 删除? 节点可以打上以下标签:
"cluster-autoscaler.kubernetes.io/scale-down-disabled": "true"
可以使用 kubectl 将其添加到节点(或从节点删除):
$ kubectl annotate node
5、Cluster Autoscaler 支持那些云厂商?
GCE https://kubernetes.io/docs/concepts/cluster-administration/cluster-management/
GKE https://cloud.google.com/container-engine/docs/cluster-autoscaler
AWS(亚马逊) https://github.com/kubernetes/autoscaler/blob/master/cluster- autoscaler/cloudprovider/aws/README.md
Azure(微软) https://github.com/kubernetes/autoscaler/blob/master/cluster- autoscaler/cloudprovider/azure/README.md
Alibaba Cloud https://github.com/kubernetes/autoscaler/blob/master/cluster- autoscaler/cloudprovider/alicloud/README.md
OpenStack Magnum https://github.com/kubernetes/autoscaler/blob/master/cluster- autoscaler/cloudprovider/magnum/README.md
DigitalOcean https://github.com/kubernetes/autoscaler/blob/master/cluster- autoscaler/cloudprovider/digitalocean/README.md
CloudStack https://github.com/kubernetes/autoscaler/blob/master/cluster- autoscaler/cloudprovider/cloudstack/README.md
Exoscale https://github.com/kubernetes/autoscaler/blob/master/cluster- autoscaler/cloudprovider/exoscale/README.md
Packet https://github.com/kubernetes/autoscaler/blob/master/cluster- autoscaler/cloudprovider/packet/README.md
OVHcloud https://github.com/kubernetes/autoscaler/blob/master/cluster- autoscaler/cloudprovider/ovhcloud/README.md
Linode https://github.com/kubernetes/autoscaler/blob/master/cluster- autoscaler/cloudprovider/linode/README.md
Hetzner https://github.com/kubernetes/autoscaler/blob/master/cluster- autoscaler/cloudprovider/hetzner/README.md
Cluster API https://github.com/kubernetes/autoscaler/blob/master/cluster- autoscaler/cloudprovider/clusterapi/README.md
1.7 、VPA 实现 Pod 自动扩缩容
Vertical Pod Autoscaler(VPA):垂直 Pod 自动扩缩容,用户无需为其 pods 中的容器设置最新的资源 request。配置后,它将根据使用情况自动设置 request,从而允许在节点上进行适当的调度,以便为每个 pod 提供适当的资源量。
1.1 、安装 vpa
[root@k8s-master01 vpa]# for i in n1 n2
do scp vpa-admission_0.10.0.tar.gz $i:/root/; ssh $i "docker load -i /root/vpa-admission_0.10.0.tar.gz;rm -rf /root/vpa-admission_0.10.0.tar.gz"
scp vpa-updater_0.10.0.tar.gz $i:/root/; ssh $i "docker load -i /root/vpa-updater_0.10.0.tar.gz;rm -rf /root/vpa-updater_0.10.0.tar.gz"
scp vpa-recommender_0.10.0.tar.gz $i:/root/; ssh $i "docker load -i /root/vpa-recommender_0.10.0.tar.gz;rm -rf /root/vpa-recommender_0.10.0.tar.gz"
done
升级下 openssl:
yum install gcc gcc-c++ -y
wget http://www.openssl.org/source/openssl-1.1.1k.tar.gz --no-check-certificate && tar -xf openssl-1.1.1k.tar.gz && cd openssl-1.1.1k
./config && make -j 8 && make install
mv /usr/local/bin/openssl /usr/local/bin/openssl.bak
mv apps/openssl /usr/local/bin
ln -s /usr/local/lib64/libssl.so.1.1 /usr/lib64/libssl.so.1.1
ln -s /usr/local/lib64/libcrypto.so.1.1 /usr/lib64/libcrypto.so.1.1
node升级下 openssl:
yum install gcc gcc-c++ -y
wget http://www.openssl.org/source/openssl-1.1.1k.tar.gz --no-check-certificate && tar -xf openssl-1.1.1k.tar.gz && cd openssl-1.1.1k
./config && make -j 8 && make install
mv /usr/local/bin/openssl /usr/local/bin/openssl.bak
mv apps/openssl /usr/local/bin
ln -s /usr/local/lib64/libssl.so.1.1 /usr/lib64/libssl.so.1.1
ln -s /usr/local/lib64/libcrypto.so.1.1 /usr/lib64/libcrypto.so.1.1
[root@k8s-master01 ~]# cd /root/vpa/autoscaler-master/vertical-pod-autoscaler/hack/
[root@k8s-master01 hack]# ./vpa-up.sh
[root@k8s-master01 hack]# kubectl get pod -n kube-system|grep vpa
vpa-admission-controller-69b85fdbcc-6z98g 1/1 Running 0 15s
vpa-recommender-5d5459bbf8-9cfln 1/1 Running 0 15s
vpa-updater-54cd9cb647-m8npk 1/1 Running 0 16s
1.2 测试 VPA 实现 pod 自动调度
1.1.1 、updateMode: "Off"
1、部署一个 nginx 服务,部署到 namespace: vpa 名称空间下:
[root@k8s-master01 vpa]# kubectl create ns vpa
[root@k8s-master01 vpa]# cat vpa-1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
namespace: vpa
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: nginx
resources:
requests:
cpu: 200m
memory: 300Mi
[root@k8s-master01 vpa]# kubectl delete deployment nginx-hpa
[root@k8s-master01 vpa]# kubectl delete deployment php-apache
[root@k8s-master01 vpa]# kubectl apply -f vpa-1.yaml
[root@k8s-master01 vpa]# kubectl get pod -n vpa
NAME READY STATUS RESTARTS AGE
nginx-58df6f4d74-58tkp 1/1 Running 0 55s
nginx-58df6f4d74-g7m68 1/1 Running 0 55s
2、在 nginx 管理的 pod 前端创建四层代理 Service
[root@k8s-master01 vpa]# cat vpa-service-1.yaml
apiVersion: v1
kind: Service
metadata:
name: nginx
namespace: vpa
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
selector:
app: nginx
[root@k8s-master01 vpa]# kubectl apply -f vpa-service-1.yaml
[root@k8s-master01 vpa]# kubectl get svc -n vpa
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx NodePort 10.97.163.127 <none> 80:32205/TCP 7s
[root@k8s-master01 vpa]# curl -I 10.97.163.127
HTTP/1.1 200 OK #显示 200 说明代理没问题
Server: nginx/1.21.5
Date: Sat, 08 Jul 2023 15:55:15 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 28 Dec 2021 15:28:38 GMT
Connection: keep-alive
ETag: "61cb2d26-267"
Accept-Ranges: bytes
#显示 200 说明代理没问题
3、创建 VPA
先使用 updateMode: "Off"模式,这种模式仅获取资源推荐值,但是不更新 Pod
[root@k8s-master01 vpa]# cat vpa-nginx.yaml
apiVersion: autoscaling.k8s.io/v1beta2
kind: VerticalPodAutoscaler
metadata:
name: nginx-vpa
namespace: vpa
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: nginx
updatePolicy:
updateMode: "Off"
resourcePolicy:
containerPolicies:
- containerName: "nginx"
minAllowed:
cpu: "500m"
memory: "100Mi"
maxAllowed:
cpu: "2000m"
memory: "2600Mi"
备注:
minAllowed (最小允许):这是容器可以使用的资源的下限限制。在这个例子中,有两个资源被限制了:CPU(以 m 为单位的毫核)和内存(以 Mi 为单位的兆字节)。
cpu: "500m" :这表示容器的 CPU 限制为 500 毫核。这意味着容器最少需要使用 0.5个 CPU 核心。 · memory: "100Mi":这表示容器的内存限制为 100 兆字节。这是容器最少可以使用的内存量。
maxAllowed (最大允许):这是容器可以使用的资源的上限限制。同样,这个例子中有两个资源被限制了:CPU 和内存。
cpu: "2000m":这表示容器的 CPU 限制为 2000 毫核。这意味着容器最多可以使用2 个 CPU 核心。
memory: "2600Mi" :这表示容器的内存限制为 2600 兆字节。这是容器最多可以使用的内存量。
[root@k8s-master01 vpa]# kubectl apply -f vpa-nginx.yaml
[root@k8s-master01 vpa]# kubectl get vpa -n vpa
NAME MODE CPU MEM PROVIDED AGE
nginx-vpa Off 500m 262144k True 17s
查看 vpa 详细信息:
[root@k8s-master01 vpa]# kubectl describe vpa nginx-vpa -n vpa
Name: nginx-vpa
Namespace: vpa
Labels: <none>
Annotations: <none>
API Version: autoscaling.k8s.io/v1
Kind: VerticalPodAutoscaler
Metadata:
Creation Timestamp: 2023-07-12T13:10:33Z
Generation: 2
Managed Fields:
API Version: autoscaling.k8s.io/v1beta2
Fields Type: FieldsV1
fieldsV1:
f:metadata:
f:annotations:
.:
f:kubectl.kubernetes.io/last-applied-configuration:
f:spec:
.:
f:resourcePolicy:
.:
f:containerPolicies:
f:targetRef:
.:
f:apiVersion:
f:kind:
f:name:
f:updatePolicy:
.:
f:updateMode:
Manager: kubectl-client-side-apply
Operation: Update
Time: 2023-07-12T13:10:33Z
API Version: autoscaling.k8s.io/v1
Fields Type: FieldsV1
fieldsV1:
f:status:
.:
f:conditions:
f:recommendation:
.:
f:containerRecommendations:
Manager: recommender
Operation: Update
Time: 2023-07-12T13:10:45Z
Resource Version: 601710
UID: 9d73f8bc-f1af-49fb-ac59-13d40834715d
Spec:
Resource Policy:
Container Policies:
Container Name: nginx
Max Allowed:
Cpu: 2000m
Memory: 2600Mi
Min Allowed:
Cpu: 500m
Memory: 100Mi
Target Ref:
API Version: apps/v1
Kind: Deployment
Name: nginx
Update Policy:
Update Mode: Off
Status:
Conditions:
Last Transition Time: 2023-07-12T13:10:45Z
Status: True
Type: RecommendationProvided
Recommendation:
Container Recommendations:
Container Name: nginx
Lower Bound:
Cpu: 500m
Memory: 262144k
Target:
Cpu: 500m
Memory: 262144k
Uncapped Target:
Cpu: 25m
Memory: 262144k
Upper Bound:
Cpu: 536m
Memory: 561361649
Events: <none>
备注:
Lower Bound(下限):这是容器可以使用的资源的最低限制。在这个例子中,有两个资源被限制了:CPU(以 m 为单位的毫核)和内存(以 k 为单位的千字节)。
Cpu: 500m:这表示容器的 CPU 限制为 500 毫核。这意味着容器最少需要使用 0.5个 CPU 核心。 · Memory: 262144k:这表示容器的内存限制为 262144 千字节,即 256 兆字节。
Target(目标):这是容器希望使用的资源目标。同样,这个例子中有两个资源被限制了:CPU 和内存。
Cpu: 100m :这表示容器希望使用的 CPU 限制为 100 毫核。
Memory: 262144k:这表示容器希望使用的内存限制为 262144 千字节,即 256 兆字节。
Uncapped Target(未限制的目标):这是容器在没有资源限制的情况下希望使用的资源目标。同样,这个例子中有两个资源被限制了:CPU 和内存。
Cpu: 25m:这表示容器在未限制的情况下希望使用的 CPU 限制为 25 毫核。
Memory: 262144k:这表示容器在未限制的情况下希望使用的内存限制为 262144 千字节,即 256 兆字节。
Upper Bound(上限):这是容器可以使用的资源的最高限制。同样,这个例子中有两个资源被限制了:CPU 和内存。
Cpu: 1349m:这表示容器的 CPU 限制为 1349 毫核。
Memory: 1410936619:这表示容器的内存限制为 1410936619 字节,即约1.41 兆字节。
上面结果表示,推荐的 Pod 的 CPU 请求为 100m,推荐的内存请求为 262144k 字节。
#压测 nginx
[root@k8s-master01 ~]# yum -y install httpd-tools
[root@k8s-master01 ~]# ab -c 100 -n 10000000 http://10.97.163.127:32205/
#过几分钟后观察 VPA Recommendation 变化
[root@k8s-master01 ~]# kubectl describe vpa nginx-vpa -n vpa
Name: nginx-vpa
Namespace: vpa
Labels: <none>
Annotations: <none>
API Version: autoscaling.k8s.io/v1
Kind: VerticalPodAutoscaler
Metadata:
Creation Timestamp: 2023-07-12T13:10:33Z
Generation: 12
Managed Fields:
API Version: autoscaling.k8s.io/v1beta2
Fields Type: FieldsV1
fieldsV1:
f:metadata:
f:annotations:
.:
f:kubectl.kubernetes.io/last-applied-configuration:
f:spec:
.:
f:resourcePolicy:
.:
f:containerPolicies:
f:targetRef:
.:
f:apiVersion:
f:kind:
f:name:
f:updatePolicy:
.:
f:updateMode:
Manager: kubectl-client-side-apply
Operation: Update
Time: 2023-07-12T13:10:33Z
API Version: autoscaling.k8s.io/v1
Fields Type: FieldsV1
fieldsV1:
f:status:
.:
f:conditions:
f:recommendation:
.:
f:containerRecommendations:
Manager: recommender
Operation: Update
Time: 2023-07-12T13:10:45Z
Resource Version: 603615
UID: 9d73f8bc-f1af-49fb-ac59-13d40834715d
Spec:
Resource Policy:
Container Policies:
Container Name: nginx
Max Allowed:
Cpu: 2000m
Memory: 2600Mi
Min Allowed:
Cpu: 500m
Memory: 100Mi
Target Ref:
API Version: apps/v1
Kind: Deployment
Name: nginx
Update Policy:
Update Mode: Off
Status:
Conditions:
Last Transition Time: 2023-07-12T13:10:45Z
Status: True
Type: RecommendationProvided
Recommendation:
Container Recommendations:
Container Name: nginx
Lower Bound:
Cpu: 500m
Memory: 262144k
Target:
Cpu: 500m
Memory: 262144k
Uncapped Target:
Cpu: 25m
Memory: 262144k
Upper Bound:
Cpu: 500m
Memory: 262144k
Events: <none>
从以上信息可以看出,VPA 对 Pod 给出了推荐值:Cpu: 763m,因为我们这里设置了updateMode: "Off",所以不会更新 Pod
[root@k8s-master01 ~]# kubectl get pod -n vpa
NAME READY STATUS RESTARTS AGE
nginx-58df6f4d74-58tkp 1/1 Running 2 (26h ago) 5d
nginx-58df6f4d74-g7m68 1/1 Running 2 (26h ago) 5d
1.1.2 、updateMode: "Auto"
1、现在我把 updateMode: "Auto",看看 VPA 会有什么动作这里我把 resources 改为:memory: 50Mi,cpu: 100m
[root@k8s-master01 vpa]# cat vpa-nginx-1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx
name: nginx
namespace: vpa
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: nginx
resources:
requests:
cpu: 100m
memory: 50Mi
[root@k8s-master01 vpa]# kubectl apply -f vpa-nginx-1.yaml
deployment.apps/nginx created
[root@k8s-master01 vpa]# kubectl get pod -n vpa
NAME READY STATUS RESTARTS AGE
nginx-6c669947c9-424m8 1/1 Running 0 5s
nginx-6c669947c9-5gwzq 1/1 Running 0 5s
2、再次部署 vpa
[root@k8s-master01 vpa]# kubectl delete -f vpa-nginx.yaml
[root@k8s-master01 vpa]# cat vpa-nginx.yaml
apiVersion: autoscaling.k8s.io/v1beta2
kind: VerticalPodAutoscaler
metadata:
name: nginx-vpa
namespace: vpa
spec:
targetRef:
apiVersion: "apps/v1"
kind: Deployment
name: nginx
updatePolicy:
updateMode: "Auto"
resourcePolicy:
containerPolicies:
- containerName: "nginx"
minAllowed:
cpu: "500m"
memory: "100Mi"
maxAllowed:
cpu: "2000m"
memory: "2600Mi"
[root@k8s-master01 vpa]# kubectl apply -f vpa-nginx.yaml
[root@k8s-master01 vpa]# kubectl get vpa -n vpa
NAME MODE CPU MEM PROVIDED AGE
nginx-vpa Auto 500m 262144k True 31s
4、几分钟后,使用 describe 查看 vpa 详情,只关注 Container Recommendations
[root@k8s-master01 vpa]# kubectl describe vpa nginx-vpa -n vpa |tail -n20
Conditions:
Last Transition Time: 2023-07-13T15:47:33Z
Status: True
Type: RecommendationProvided
Recommendation:
Container Recommendations:
Container Name: nginx
Lower Bound:
Cpu: 500m
Memory: 262144k
Target:
Cpu: 500m
Memory: 262144k
Uncapped Target:
Cpu: 25m
Memory: 262144k
Upper Bound:
Cpu: 2
Memory: 795714680
Events: <none>
Target 变成了Cpu: 500m ,Memory: 262144k
5、来看下 event 事件
从输出信息可以看到,vpa 执行了 EvictedByVPA,自动停掉了 nginx,然后使用 VPA 推荐的资源启动了新的 nginx,我们查看下 nginx 的 pod 可以得到确认
[root@k8s-master01 vpa]# kubectl get pod -n vpa
NAME READY STATUS RESTARTS AGE
nginx-6c669947c9-6gbbq 1/1 Running 0 82s
nginx-6c669947c9-7dg6t 1/1 Running 0 2m22s
[root@k8s-master01 vpa]# kubectl describe pod nginx-6c669947c9-6gbbq -n vpa
Name: nginx-6c669947c9-6gbbq
Namespace: vpa
Priority: 0
Node: k8s-node02/192.168.20.205
Start Time: Thu, 13 Jul 2023 23:49:33 +0800
Labels: app=nginx
pod-template-hash=6c669947c9
Annotations: cni.projectcalico.org/podIP: 10.244.58.215/32
cni.projectcalico.org/podIPs: 10.244.58.215/32
vpaObservedContainers: nginx
vpaUpdates: Pod resources updated by nginx-vpa: container 0: cpu request, memory request
Status: Running
IP: 10.244.58.215
IPs:
IP: 10.244.58.215
Controlled By: ReplicaSet/nginx-6c669947c9
Containers:
nginx:
Container ID: docker://1dd6497a201a73bda4b33117cd623f33f727a6002335e264b398c0f7c24392eb
Image: nginx
Image ID: docker-pullable://nginx@sha256:0d17b565c37bcbd895e9d92315a05c1c3c9a29f762b011a10c54a66cd53c9b31
Port: <none>
Host Port: <none>
State: Running
Started: Thu, 13 Jul 2023 23:49:34 +0800
Ready: True
Restart Count: 0
Requests:
cpu: 500m
memory: 262144k
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-lhbjh (ro)
Conditions:
Type Status
Initialized True
Ready True
ContainersReady True
PodScheduled True
Volumes:
kube-api-access-lhbjh:
Type: Projected (a volume that contains injected data from multiple sources)
TokenExpirationSeconds: 3607
ConfigMapName: kube-root-ca.crt
ConfigMapOptional: <nil>
DownwardAPI: true
QoS Class: Burstable
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300s
node.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 109s default-scheduler Successfully assigned vpa/nginx-6c669947c9-6gbbq to k8s-node02
Normal Pulled 108s kubelet Container image "nginx" already present on machine
Normal Created 108s kubelet Created container nginx
Normal Started 108s kubelet Started container nginx
现在可以知道 VPA 做了哪些事了吧。当然,随着服务的负载的变化,VPA 的推荐值也会不断变化。当目前运行的 pod 的资源达不到 VPA 的推荐值,就会执行 pod 驱逐,重新部署新的足够资源的服务。
总结:
1.1 深入剖析 k8s 应用自动扩缩容的方案
1.2 自动扩缩容的方案有哪些?
1.3 如何实现 k8s 中的应用自动扩缩容?
1.4 利用 HPA 基于 CPU 指标实现 pod 自动扩缩容
1.5 利用 HPA 基于内存指标实现 pod 自动扩缩容
1.6 kubernetes cluster-autoscaler
1.7 VPA 实现 Pod 自动调度



