一、自动(弹性)扩缩容背景分析
背景:
弹性伸缩是根据用户的业务需求和策略,自动“调整”其“弹性资源”的管理服务。通过弹 性伸缩功能,用户可设置定时、周期或监控策略,恰到好处地增加或减少“弹性资源”,并完 成实例配置,保证业务平稳健康运行
在实际工作中,我们常常需要做一些扩容缩容操作,如:电商平台在 618 和双十一搞秒 杀活动;由于资源紧张、工作负载降低等都需要对服务实例数进行扩缩容操作。
在 k8s 中扩缩容分为两种:
1、Node 层面:
对 K8s 物理节点扩容和缩容,根据业务规模实现物理节点自动扩缩容
2、Pod 层面:
我们一般会使用Deployment中的replicas参数,设置多个副本集来保证服务的高可用, 但是这是一个固定的值,比如我们设置 10 个副本,就会启 10 个 pod 同时 running 来 提供服务。如果这个服务平时流量很少的时候,也是 10 个 pod 同时在 running,而流 量突然暴增时,又可能出现 10 个 pod 不够用的情况。针对这种情况怎么办?就需要自动扩容和缩容
自动扩缩容对长连接和短连接的影响?
如何解决长连接突然断开问题:例如客户端网络闪断、刷新情况
1.会话粘性(Session stickiness):通过启用会话粘性,可以确保同一客户端的请求始终被路由到同一个Pod。Kubernetes中的IngressController(如NGINX Ingress Controller)和Service可以配置会话粘性。
2.外部会话储存:将会话状态存储在外部存储系统中,例如Redis或数据库,这样即使客户端连接到不同的Pod,依然可以通过会话ID从外部存储中获取会话状态。
3.Graceful Reconnection:在客户端实现优雅重连逻辑,确保在连接断开后能够快速重新连接并恢复会话状态。例如,通过WebSocket的重连机制,客户端可以在断开后尝试重新连接,并在重新连接时携带会话ID或其他标识信息。
二、k8s中自动伸缩的方案
2.1 HPA
Kubernetes HPA(Horizontal Pod Autoscaling):Pod 水平自动伸缩/横向自动收缩
通过此功能,只需简单的配置,便可以利用监控指标(cpu 使用率、磁盘、自定义的等) 自动的扩容或缩容服务中 Pod 数量,当业务需求增加时,系统将无缝地自动增加适量 pod 容器,提高系统稳定性。
要想实现自动扩缩容,需要先考虑如下几点:
1.通过哪些指标决定扩缩容?
HPA v1 版本可以根据 CPU 使用率来进行自动扩缩容: 但是并非所有的系统都可以仅依靠 CPU 或者 Memory 指标来扩容,对于大多数 Web 应用的后端来说,基于每秒的请求数量进行弹性伸缩来处理突发流量会更加的靠谱,所 以对于一个自动扩缩容系统来说,我们不能局限于 CPU、Memory 基础监控数据,每秒 请求数 RPS 等自定义指标也是十分重要。
HPA v2 版本可以根据自定义的指标进行自动扩缩容
注意:hpa v1 只能基于 cpu 做扩容所用
hpa v2 可以基于内存和自定义的指标做扩容和缩容
2.如何采集资源指标?
如果我们的系统默认依赖 Prometheus,自定义的 Metrics 指标则可以从各种数据源或 者 exporter 中获取,基于拉模型的 Prometheus 会定期从数据源中拉取数据。 也可以基于 metrics-server 自动获取节点和 pod 的资源指标
3.如何实现自动扩缩容?
K8s 的 HPA controller 已经实现了一套简单的自动扩缩容逻辑,默认情况下,每 30s 检测一次指标,只要检测到了配置 HPA 的目标值,则会计算出预期的工作负载的副本数, 再进行扩缩容操作。同时,为了避免过于频繁的扩缩容,默认在 5min 内没有重新扩缩容的情况下,才会触发扩缩容。 HPA 本身的算法相对比较保守,可能并不适用于很多场景。例如,一个快速的流量突发场景,如果正处在 5min 内的 HPA 稳定期,这个时候根据 HPA 的策略,会导致无法扩容.
更详细内容:https://zhuanlan.zhihu.com/p/360259459
自动伸缩的过程可以分为三个步骤:
获取被伸缩资源对象所管理的所有pod度量。
计算使度量数值到达(或接近)所指定目标数值所需的pod数量。
更新被伸缩资源的replicas字段。
2.2 KPA
KPA(Knative Pod Autoscaler):基于请求数对 Pod 自动扩缩容,KPA 的主要限制在于 它不支持基于 CPU 的自动扩缩容。
1、根据并发请求数实现自动扩缩容 .
2、设置扩缩容边界实现自动扩缩容
扩缩容边界指应用程序提供服务的最小和最大 Pod 数量。通过设置应用程序提供服务 的最小和最大 Pod 数量实现自动扩缩容。
相比 HPA,KPA 会考虑更多的场景,其中一个比较重要的是流量突发的时候
2.3 VPA
kubernetes VPA(Vertical Pod Autoscaler),垂直 Pod 自动扩缩容,VPA 会基于 Pod 的 资源使用情况自动为集群设置资源占用的限制,从而让集群将 Pod 调度到有足够资源的最佳节点上。VPA 也会保持最初容器定义中资源 request 和 limit 的占比。
它会根据容器资源使用率自动设置 pod 的 CPU 和内存的 requests,从而允许在节点上 进行适当的调度,以便为每个 Pod 提供适当的可用的节点。它既可以缩小过度请求资 源的容器,也可以根据其使用情况随时提升资源不足的容量。
三、利用HPA基于CPU指标实现Pod自动扩缩容
HPA 全称是 Horizontal Pod Autoscaler,翻译成中文是 POD 水平自动伸缩, HPA 可以 基于 CPU 利用率对 deployment 中的 pod 数量进行自动扩缩容(除了 CPU 也可以基于自定义的指标进行自动扩缩容)。pod 自动缩放不适用于无法缩放的对象,比如 DaemonSets。
HPA 由 Kubernetes API 资源和控制器实现。控制器会周期性的获取平均 CPU 利用率, 并与目标值相比较后调整 deployment 中的副本数量
3.1 HPA工作原理
HPA 是根据指标来进行自动伸缩的,目前 HPA 有两个版本–v1 和 v2beta
HPA 的 API 有三个版本,通过 kubectl api-versions | grep autoscal 可看到
[root@master k8s]# kubectl api-versions | grep autoscal autoscaling/v1 autoscaling/v2beta1 autoscaling/v2beta2
autoscaling/v1 只支持基于 CPU 指标的缩放;
autoscaling/v2beta1 支持 Resource Metrics(资源指标,如 pod 内存)和 Custom Metrics (自定义指标)的缩放;
autoscaling/v2beta2 支持 Resource Metrics(资源指标,如 pod 的内存)和 Custom Metrics (自定义指标)和 ExternalMetrics(额外指标)的缩放,但是目前也仅仅是处于 beta 阶段 指标从哪里来?
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 信息
HPA 如何运作?
HPA 的实现是一个控制循环,由 controller manager 的--horizontal-pod-autoscaler-syncperiod 参数指定周期(默认值为 15 秒)。每个周期内,controller manager 根据每个 HorizontalPodAutoscaler 定义中指定的指标查询资源利用率。controller manager 可以从 resource metrics API(pod 资源指标)和 custom metrics API(自定义指标)获取指标。
然后,通过现有 pods 的 CPU 使用率的平均值(计算方式是最近的 pod 使用量(最近一分钟的平均 值,从 metrics-server 中获得)除以设定的每个 Pod 的 CPU 使用率限额)跟目标使用率进行比较, 并且在扩容时,还要遵循预先设定的副本数限制:MinReplicas <= Replicas <= MaxReplicas。
计算扩容后 Pod 的个数:sum(最近一分钟内某个 Pod 的 CPU 使用率的平均值)/CPU 使用上限的 整数+1
流程:
1、创建 HPA 资源,设定目标 CPU 使用率限额,以及最大、最小实例数
2、收集一组中(PodSelector)每个 Pod 最近一分钟内的 CPU 使用率,并计算平均值
3、读取 HPA 中设定的 CPU 使用限额
4、计算:平均值之和/限额,求出目标调整的实例个数
5、目标调整的实例数不能超过 1 中设定的最大、最小实例数,如果没有超过,则扩容;超过,则扩容至最大的实例个数
6、回到 2,不断循环
3.2 安装数据采集组件metrics-server
metrics-server 是一个集群范围内的资源数据集和工具,同样的,metrics-server 也只是显示数据,并不提供数据存储服务,主要关注的是资源度量 API 的实现,比如 CPU、文件描述符、内存、 请求延时等指标,metric-server 收集数据给 k8s 集群内使用,如 kubectl,hpa,scheduler 等
(1) 部署 metrics-server 组件
#通过离线方式获取镜像
需要的镜像是:k8s.gcr.io/metrics-server-amd64:v0.3.6 和 k8s.gcr.io/addon-resizer:1.8.4,把镜像上传 到 k8s 的各个节点,并导入:
docker load -i addon.tar.gz
docker load -i metrics-server-amd64-0-3-6.tar.gz
# 部署metrics-server服务
#在/etc/kubernetes/manifests 里面改一下 apiserver 的配置
注意:这个是 k8s 在 1.7 的新特性,如果是 1.16 版本的可以不用添加,1.17 以后要添加。这个参 数的作用是 Aggregation 允许在不修改 Kubernetes 核心代码的同时扩展 Kubernetes API。
[root@master ~]# vim /etc/kubernetes/manifests/kube-apiserver.yaml
增加如下内容: - --enable-aggregator-routing=true
重新更新 apiserver 配置:
[root@master ~]# kubectl apply -f /etc/kubernetes/manifests/kube-apiserver.yaml
pod/kube-apiserver created
[root@master ~]# kubectl apply -f metrics.yaml clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created serviceaccount/metrics-server created clusterrole.rbac.authorization.k8s.io/system:metrics-server created clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created configmap/metrics-server-config created deployment.apps/metrics-server created service/metrics-server created apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created
#验证 metrics-server 是否部署成功
[root@master ~]# kubectl get pods -n kube-system | grep metrics metrics-server-6595f875d6-bjgrv 2/2 Running 0 31s # 测试kubectl top命令 [root@master ~]# kubectl top nodes NAME CPU(cores) CPU% MEMORY(bytes) MEMORY% master 368m 9% 1641Mi 28% node1 93m 4% 700Mi 19% node3 75m 3% 559Mi 32% [root@master ~]# kubectl top pods -n kube-system NAME CPU(cores) MEMORY(bytes) calico-kube-controllers-56c7cdffc6-n2grp 1m 21Mi calico-node-lcq82 41m 81Mi calico-node-ltnpt 39m 101Mi calico-node-zhvpx 76m 74Mi coredns-7f89b7bc75-bd6k7 10m 15Mi coredns-7f89b7bc75-thkbx 6m 15Mi etcd-master 34m 71Mi kube-apiserver-master 107m 459Mi kube-controller-manager-master 40m 54Mi kube-proxy-gjx9g 1m 18Mi kube-proxy-wmnd4 1m 18Mi kube-proxy-xz4b7 1m 18Mi kube-scheduler-master 6m 23Mi metrics-server-6595f875d6-bjgrv 1m 15Mi
3.3 创建php-apache服务,利用HAP进行自动扩缩容
#基于 dockerfile 构建一个 PHP-apache 项目 1)创建并运行一个 php-apache 服务 使用 dockerfile 构建一个新的镜像,在 k8s 的 master 构建 mkdir /root/php cd php [root@master php]# docker load -i php.tar.gz [root@master php]# cat dockerfile FROM php:5-apache ADD index.php /var/www/html/index.php RUN chmod a+rx index.php [root@master php]# cat index.php <?php $x = 0.0001; for ($i = 0; $i <= 1000000;$i++) { $x += sqrt($x); } echo "OK!"; ?> # 2.构建镜像 [root@master php]# docker build -t 192.168.10.12/test/hap-example:v1 . # 在各节点导入该镜像 docker save 192.168.10.12/test/hap-example:v1 -o hpa-example.tar.gz docker load -i hpa-example.tar.gz # 3.通过deployment部署一个php-apache服务 [root@master php]# cat 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: 192.168.10.12/test/hap-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 [root@master php]# kubectl apply -f php-apache.yaml deployment.apps/php-apache created service/php-apache created [root@master php]# kubectl get pods NAME READY STATUS RESTARTS AGE php-apache-58857b55d7-4sr6m 1/1 Running 0 15s
3.4 创建HPA
php-apache服务正在运行,使用kubectl autoscale创建自动缩放器,实现对php-apache 这个 deployment 创建的 pod 自动扩缩容,下面的命令将会创建一个 HPA,HPA 将会 根据 CPU,内存等资源指标增加或减少副本数,创建一个可以实现如下目的的 hpa:
1)让副本数维持在 1-10 个之间(这里副本数指的是通过 deployment 部署的 pod 的副本数)
2)将所有 Pod 的平均 CPU 使用率维持在 50%(通过 kubectl top 看到的每个 pod 如果 是 200 毫核,这意味着平均 CPU 利用率为 100 毫核)
#给上面 php-apache 这个 deployment 创建 HPA
[root@master php]# kubectl autoscale deployment php-apache --cpu-percent=50 --min=1 --max=10 horizontalpodautoscaler.autoscaling/php-apache autoscaled #上面命令解释说明 kubectl autoscale deployment php-apache (php-apache 表示 deployment 的名字) --cpu-percent=50(表示 cpu 使用率不超过 50%) --min=1(最少一个 pod)--max=10(最多 10 个 pod) # 验证hpa是否创建成功 [root@master php]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE php-apache Deployment/php-apache 0%/50% 1 10 1 38s 注:由于我们没有向服务器发送任何请求,因此当前 CPU 消耗为 0%(TARGET 列显示了由相应的 deployment 控制的所有 Pod 的平均值)。
3.5 HPA基于CPU使用率实现Pod自动扩/缩容
压测php-apache服务,只针对CPU进行压测
# 1.准备好busybox和nginx镜像,并导入到节点中 docker load -i busybox.tar.gz docker load -i nginx-1-9-1.tar.gz # 2.启动一个容器,并将无限查询循环发送到 php-apache 服务(复制 k8s 的 master 节点的终端,也就是打开一个新的终端窗口): [root@master ~]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE php-apache ClusterIP 10.105.167.249 <none> 80/TCP 14m [root@master php]# kubectl run v1 -it --image=busybox:latest --image-pull-policy=IfNotPresent -- /bin/sh # while true; do wget -q -O- http://php-apache.default.svc.cluster.local; done [root@master ~]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE php-apache Deployment/php-apache 194%/50% 1 10 1 22m # 上面可以看到,CPU 消耗已经达到 194%,每个 pod 的目标 cpu 使用率是 50%,所以,php-apache 这个 deployment 创建的 pod 副本数将调整为 5 个副本,为什么是 4 个副本,因为 194/50=3 # 自动扩容到7个副本,满足了需求,直到cpu使用率不超过50% [root@master ~]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE php-apache Deployment/php-apache 48%/50% 1 10 7 24m [root@master ~]# kubectl get pods NAME READY STATUS RESTARTS AGE php-apache-58857b55d7-skr4b 1/1 Running 0 86s php-apache-58857b55d7-smkfp 1/1 Running 0 2m27s php-apache-58857b55d7-vdsdj 1/1 Running 0 3m18s php-apache-58857b55d7-wfvjg 1/1 Running 0 2m27s v1 1/1 Running 0 2m57s 注意:可能需要几分钟来稳定副本数。由于不以任何方式控制负载量,因此最终副本数可能会与此示例不同 # 停止对 php-apache 服务压测,HPA 会自动对 php-apache 这个 deployment 创建的 pod做缩容 [root@master ~]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE php-apache Deployment/php-apache 2%/50% 1 10 7 27m # 需要一段时间检测才进行缩容
3.6 HPA基于内存实现Pod自动扩容
# 1.导入镜像 docker load -i nginx-1-9-1.tar.gz # 2.执行yaml文件 [root@master ~]# 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
nginx 的 pod 里需要有如下字段,否则 hpa 会采集不到内存指标 resources: requests: cpu: 0.01 memory: 25Mi limits: cpu: 0.05 memory: 60Mi
[root@master ~]# kubectl apply -f nginx.yaml deployment.apps/nginx-hpa created service/nginx created [root@master ~]# kubectl get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx NodePort 10.110.32.245 <none> 80:30073/TCP 111s [root@master manifests]# kubectl get pods NAME READY STATUS RESTARTS AGE nginx-hpa-fb74696c-vtgsg 1/1 Running 0 4m40s [root@master ~]# cat hpa-v1.yaml apiVersion: autoscaling/v2beta1 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 targetAverageUtilization: 60 #内存使用率超过60%就扩容 [root@master ~]# kubectl apply -f hpa-v1.yaml horizontalpodautoscaler.autoscaling/nginx-hpa created [root@master ~]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE nginx-hpa Deployment/nginx-hpa 5%/60% 1 10 1 39s
压测nginx-hpa,针对内存使用超过60%就自动扩容
压测nginx-hpa 登录到上面通过 pod 创建的 nginx,并生成一个文件,增加内存 [root@master ~]# kubectl exec -it nginx-hpa-fb74696c-vtgsg -- /bin/sh # dd if=/dev/zero of=/tmp/a # 在新终端里查看 [root@master ~]# kubectl get hpa NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE nginx-hpa Deployment/nginx-hpa 125%/60% 1 10 3 15m 上面的 targets 列可看到 125%/60%,125%表示当前内存使用率,60%表示所有 pod 的内存使用率维持在 60%,现在内存使用率达到 200%,所以 pod 增加到 3个,新增2个 [root@master ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES nginx-hpa-fb74696c-4kmvv 1/1 Running 0 3m21s 10.244.166.156 node1 <none> <none> nginx-hpa-fb74696c-vtgsg 1/1 Running 0 25m 10.244.166.141 node1 <none> <none> nginx-hpa-fb74696c-x4wnx 1/1 Running 0 3m21s 10.244.166.155 node1 <none> <none>
# 当我停止压缩后,hap会对pod自动缩容
如何查看v2版本的hpa如何定义?
[root@master ~]# kubectl get hpa.v2beta2.autoscaling -o yaml > v2.yaml
kubectl explain HorizontalPodAutoscaler
kubectl explain HorizontalPodAutoscaler.spec
四、VPA实现Pod自动扩缩容
Vertical Pod Autoscaler(VPA):垂直 Pod 自动扩缩容,用户无需为其 pods 中的容器设置最 新的资源 request。配置后,它将根据使用情况自动设置 request,从而允许在节点上进行适当的调度,以便为每个 pod 提供适当的资源量。
使用vpa前删除hpa
4.1 安装vpa
# k8s集群节点上导入镜像 [root@node1 data]# docker load -i vpa-admission-controller_0_8_0.tar.gz Loaded image: scofield/vpa-admission-controller:0.8.0 [root@node1 data]# docker load -i vpa-recommender_0_8_0.tar.gz b8cda3fb4e0a: Loading layer [==================================================>] 45.95MB/45.95MB Loaded image: scofield/vpa-recommender:0.8.0 [root@node1 data]# docker load -i vpa-updater_0_8_0.tar.gz 9fe5b61fc509: Loading layer [==================================================>] 47.39MB/47.39MB Loaded image: scofield/vpa-updater:0.8.0 # 控制节点 [root@master vpa]# unzip autoscaler-vertical-pod-autoscaler-0.8.0.zip [root@master vpa]# cd /root/vpa/autoscaler-vertical-pod-autoscaler-0.8.0/vertical-pod-autoscaler/deploy 修改 admission-controller-deployment.yaml 里的 image: image: scofield/vpa-admission-controller:0.8.0 imagePullPolicy: IfNotPresent 修改 recommender-deployment.yaml 里的 image: image: scofield/vpa-recommender:0.8.0 imagePullPolicy: IfNotPresent 修改 updater-deployment.yaml 文件里的 image: image: scofield/vpa-updater:0.8.0 imagePullPolicy: IfNotPresent cd /root/vpa/autoscaler-vertical-pod-autoscaler-0.8.0/vertical-pod-autoscaler/hack [root@master hack]# ./vpa-up.sh Warning: apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition customresourcedefinition.apiextensions.k8s.io/verticalpodautoscalers.autoscaling.k8s.io created customresourcedefinition.apiextensions.k8s.io/verticalpodautoscalercheckpoints.autoscaling.k8s.io created clusterrole.rbac.authorization.k8s.io/system:metrics-reader created clusterrole.rbac.authorization.k8s.io/system:vpa-actor created clusterrole.rbac.authorization.k8s.io/system:vpa-checkpoint-actor created clusterrole.rbac.authorization.k8s.io/system:evictioner created clusterrolebinding.rbac.authorization.k8s.io/system:metrics-reader created clusterrolebinding.rbac.authorization.k8s.io/system:vpa-actor created clusterrolebinding.rbac.authorization.k8s.io/system:vpa-checkpoint-actor created clusterrole.rbac.authorization.k8s.io/system:vpa-target-reader created clusterrolebinding.rbac.authorization.k8s.io/system:vpa-target-reader-binding created clusterrolebinding.rbac.authorization.k8s.io/system:vpa-evictionter-binding created serviceaccount/vpa-admission-controller created clusterrole.rbac.authorization.k8s.io/system:vpa-admission-controller created clusterrolebinding.rbac.authorization.k8s.io/system:vpa-admission-controller created clusterrole.rbac.authorization.k8s.io/system:vpa-status-reader created clusterrolebinding.rbac.authorization.k8s.io/system:vpa-status-reader-binding created serviceaccount/vpa-updater created deployment.apps/vpa-updater created serviceaccount/vpa-recommender created deployment.apps/vpa-recommender created Generating certs for the VPA Admission Controller in /tmp/vpa-certs. Generating RSA private key, 2048 bit long modulus .........................................................+++ .............+++ e is 65537 (0x10001) Generating RSA private key, 2048 bit long modulus ..+++ ............+++ e is 65537 (0x10001) Signature ok subject=/CN=vpa-webhook.kube-system.svc Getting CA Private Key Uploading certs to the cluster. secret/vpa-tls-certs created Deleting /tmp/vpa-certs. deployment.apps/vpa-admission-controller created service/vpa-webhook created [root@master manifests]# kubectl get pods -n kube-system | grep vpa vpa-admission-controller-777694497b-bqpb2 1/1 Running 0 7m9s vpa-recommender-64f6765bd9-twxbw 1/1 Running 0 7m9s vpa-updater-c5474f4c7-h78xt 1/1 Running 0 7m9s [root@master manifests]# kubectl get svc -n kube-system NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 18d metrics-server ClusterIP 10.109.69.92 <none> 443/TCP 18h vpa-webhook ClusterIP 10.99.181.122 <none> 443/TCP 12m
4.2 测试VPA实现Pod自动扩缩容
4.2.1 updateMode:"Off"
# 1、部署一个 nginx 服务,部署到 namespace: vpa 名称空间下: [root@master vpa]# kubectl create ns vpa namespace/vpa created [root@master 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@master vpa]# kubectl apply -f vpa-1.yaml deployment.apps/nginx created #2.在 nginx 管理的 pod 前端创建四层代理 Service [root@master 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@master vpa]# kubectl apply -f vpa-service-1.yaml service/nginx created [root@master vpa]# kubectl get svc -n vpa NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx NodePort 10.97.228.179 <none> 80:30127/TCP 9s [root@master vpa]# curl -I 192.168.10.10:30127 HTTP/1.1 200 OK # 3.创建VPA 先使用 updateMode: "Off"模式,这种模式仅获取资源推荐值,但是不更新 Pod [root@master 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" [root@master vpa]# kubectl apply -f vpa-nginx.yaml verticalpodautoscaler.autoscaling.k8s.io/nginx-vpa created [root@master vpa]# kubectl get vpa -n vpa NAME AGE nginx-vpa 31s # 查看详细信息 [root@master vpa]# kubectl describe vpa nginx-vpa -n vpa # 使用上面命令这次没看到 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: 1349m Memory: 1410936619 Events: <none> Lower Bound: 下限值 Target: 推荐值 Upper Bound: 上限值 Uncapped Target: 如果没有为 VPA 提供最小或最大边界,则表示目标利用率 上面结果表示,推荐的 Pod 的 CPU 请求为 500m,推荐的内存请求为 262144k 字节。
压测nginx:
[root@master vpa]# yum install -y httpd-tools ab [root@master manifests]# kubectl get svc -n vpa NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx NodePort 10.97.228.179 <none> 80:30127/TCP 55m [root@master vpa]# ab -c 100 -n 10000000 http://192.168.10.10:30127/ [root@master vpa]# kubectl describe vpa nginx-vpa -n vpa VPA 对 Pod 给出了推荐值:Cpu: 763m,因为我们这里设置了 updateMode: "Off",所以不会更新 Pod
4.2.2 updateMode: "On"
现在我把 updateMode: "Auto",看看 VPA 会有什么动
把 resources 改为:memory: 50Mi,cpu: 100m
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@master vpa]# kubectl apply -f vpa-nginx-1.yaml deployment.apps/nginx created [root@master vpa]# kubectl get pods -n vpa NAME READY STATUS RESTARTS AGE nginx-7d946f55c4-p52gj 1/1 Running 0 10s nginx-7d946f55c4-s8ggc 1/1 Running 0 10s # 再次部署vpa [root@master vpa]# cat vpa-nginx.yaml apiVersion: autoscaling.k8s.io/v1beta2 kind: VerticalPodAutoscaler metadata: name: nginx-vpa-2 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@master vpa]# kubectl apply -f vpa-nginx.yaml verticalpodautoscaler.autoscaling.k8s.io/nginx-vpa-2 created [root@master vpa]# kubectl get vpa -n vpa NAME AGE nginx-vpa-2 9s # 再次压测 [root@master vpa]# ab -c 100 -n 1000000 http://192.168.10.10:30127/
几分钟后,使用 describe 查看 vpa 详情,只关注 Container Recommendations kubectl describe vpa nginx-vpa -n vpa |tail -n 20 Target 变成了 Cpu: 656m ,Memory: 262144k
查看event事件
[root@master vpa]# kubectl get event -n vpa vpa 执行了 EvictedByVPA,自动停掉了 nginx,然后使用 VPA 推荐的 资源启动了新的 nginx [root@master vpa]# kubectl describe pods nginx-7d946f55c4-p52gj -n vpa 查看Requests的cpu和memory是多少和部署的文件中作比较 随着服务的负载的变化,VPA 的推荐值也会不断变化。当目前运行的 pod 的资源达不到 VPA 的推荐值,就会执行 pod 驱逐,重新部署新的足够资源的服务。
VPA 使用限制:
不能与 HPA(Horizontal Pod Autoscaler )一起使用
Pod 比如使用副本控制器,例如属于 Deployment 或者 StatefulSet
VPA优点:
Pod 资源用其所需,所以集群节点使用效率高。
Pod 会被安排到具有适当可用资源的节点上。
不必运行基准测试任务来确定 CPU 和内存请求的合适值。
VPA 可以随时调整 CPU 和内存请求,无需人为操作,因此可以减少维护时间。
VPA 是 Kubernetes 比较新的功能,还没有在生产环境大规模实践过,小环境可以使用试试,也可以提前测试看看
五、kubernetes cluster-autoscaler
5.1 什么是cluster-autoscaler?
Cluster Autoscaler (CA)是一个独立程序,是用来弹性伸缩 kubernetes 集群的。它可以自动根据部署应用所请求的资源量来动态的伸缩集群。当集群容量不足时,它会自动去 Cloud Provider (支持 GCE、GKE 和 AWS)创建新的 Node,而在 Node 长时间资源 利用率很低时自动将其删除以节省开支。
项目地址:https://github.com/kubernetes/autoscaler
5.2 Cluster Autoscaler什么时候伸缩集群?
在以下情况下,集群自动扩容或者缩放:
扩容:由于资源不足,某些 Pod 无法在任何当前节点上进行调度
缩容: Node 节点资源利用率较低时,且此 node 节点上存在的 pod 都能被重新调度到 其他 node 节点上运行
5.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,从而保证业务不中断
5.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 cluster-autoscaler.kubernetes.io/scale-down-disabled=true
5.5 Cluster Autoscaler 支持那些云厂商?
GCE https://kubernetes.io/docs/concepts/cluster-administration/cluster-management/ Google 云服务商 GKE https://cloud.google.com/container-engine/docs/cluster-autoscaler Google kubernetes 服务 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/READM.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
六、KPA实现pod扩缩容
Github: https://knative.dev/docs/install/
安装参考: https://knative.dev/docs/install/install-serving-with-yaml