杨梅冲
每天在想什么呢?

一、自动(弹性)扩缩容背景分析

背景:

弹性伸缩是根据用户的业务需求和策略,自动“调整”其“弹性资源”的管理服务。通过弹 性伸缩功能,用户可设置定时、周期或监控策略,恰到好处地增加或减少“弹性资源”,并完 成实例配置,保证业务平稳健康运行

  在实际工作中,我们常常需要做一些扩容缩容操作,如:电商平台在 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

 

posted on 2022-09-01 15:26  杨梅冲  阅读(6692)  评论(0编辑  收藏  举报