Pod自动扩容与缩容

Pod自动扩容/缩容

HPA介绍

001 Horizontal Pod Autoscaler(HPA,Pod水平自动伸缩)
002 根据资源利用率或者自定义指标自动调整Deployment的Pod副本数量,提供应用并发。
003 HPA不适于无法缩放的对象,例如DaemonSet。
1639534110940.png

HPA基本工作原理

001 Kubernetes 中的 Metrics Server 持续采集所有 Pod 副本的指标数据。
002 HPA 控制器通过 Metrics Server 的 API(聚合 API)获取这些数据,
003 基于用户定义的扩缩容规则进行计算,得到目标 Pod 副本数量。
004 当目标 Pod 副本数量与当前副本数量不同时,HPA 控制器就向 Pod 的Deployment控制器发起scale 操作,调整 Pod 的副本数量,完成扩缩容操作
1639534522974.png

使用HPA前提条件

001 启用Kubernetes API聚合层
002 相应的API已注册
•   对于资源指标(例如CPU、内存),将使用metrics.k8s.io API,一般由metrics-server提供
•   对于自定义指标(例如QPS),将使用custom.metrics.k8s.io API,由相关适配器(Adapter)服务提供

API聚合层

001 在 Kubernetes 1.7 版本引入了聚合层,允许第三方应用程序通过将自己注册到kube-apiserver上,仍然通过 API Server 的 HTTP URL 对新的 API 进行访问和操作。
002 为了实现这个机制,Kubernetes 在 kube-apiserver 服务中引入了一个API 聚合层(API Aggregation Layer),用于将扩展 API 的访问请求转发到用户服务的功能
1639535446518.png

启用聚合层

#用kubeadm 默认已开启
#二进制方式
[root@k8s-m1 ~]# vi /opt/kubernetes/cfg/kube-apiserver.conf

--requestheader-client-ca-file=/opt/kubernetes/ssl/ca.pem \
--proxy-client-cert-file=/opt/kubernetes/ssl/server.pem \
--proxy-client-key-file=/opt/kubernetes/ssl/server-key.pem \
--requestheader-allowed-names=kubernetes \
--requestheader-extra-headers-prefix=X-Remote-Extra- \
--requestheader-group-headers=X-Remote-Group \
--requestheader-username-headers=X-Remote-User \
--enable-aggregator-routing=true \

基于资源指标

Metrics Server部署

[root@k8s-m1 hpa]# kubectl apply -f metrics-server.yaml

[root@k8s-m1 hpa]# kubectl get pod -n kube-system 
NAME                                      READY   STATUS    RESTARTS   AGE
......
metrics-server-b66888848-jqqww            1/1     Running   0          4m31s

查看指标并验证

[root@k8s-m1 hpa]# kubectl get apiservices
...
v1beta1.metrics.k8s.io                 kube-system/metrics-server   True        5m7s

[root@k8s-m1 hpa]# kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes
{...}
[root@k8s-m1 hpa]# kubectl get --raw /apis/metrics.k8s.io/v1beta1/pods
{...}

#查看Node资源消耗
[root@k8s-m1 hpa]# kubectl top node
NAME        CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%   
k8s-m1      309m         7%     1044Mi          28%       
k8s-node1   142m         3%     377Mi           10%  

#查看Pod资源消耗
[root@k8s-m1 hpa]# kubectl top pod  -n kube-system
NAME                                      CPU(cores)   MEMORY(bytes)   
calico-kube-controllers-97769f7c7-wfvvd   2m           14Mi            
calico-node-76zz7                         69m          71Mi            
calico-node-lfjsk                         83m          74Mi            
coredns-6cc56c94bd-2zsgn                  5m           13Mi            
metrics-server-b66888848-jqqww            5m           21Mi 

#如果能正常显示资源消耗说明Metrics Server服务工作正常

应用部署

部署应用

[root@k8s-m1 hpa]# kubectl create deployment web --image=nginx --dry-run=client -o yaml > deployment.yaml
[root@k8s-m1 hpa]# vi deployment.yaml 
    spec:
      containers:
      - image: nginx
        name: nginx
        resources: 
          requests:
            cpu: 0.5

[root@k8s-m1 hpa]# kubectl apply -f deployment.yaml 
deployment.apps/web created


[root@k8s-m1 hpa]# kubectl expose deployment web --port=80 --target-port=80 
service/web exposed

[root@k8s-m1 hpa]# kubectl get pod,svc
NAME                       READY   STATUS    RESTARTS   AGE
pod/web-67bbbf48fc-cgflp   1/1     Running   0          5m42s

NAME                 TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   10.0.0.1     <none>        443/TCP   2d21h
service/web          ClusterIP   10.0.0.129   <none>        80/TCP    5m8s

创建HPA

[root@k8s-m1 hpa]# kubectl autoscale deployment web --min=2 --max=10 --cpu-percent=80

[root@k8s-m1 hpa]# kubectl get hpa
NAME   REFERENCE        TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
web    Deployment/web   <unknown>/80%   2         10        1          17s

说明:为名为web的deployment创建一个HPA对象,目标CPU使用率为80%,副本数量配置为2到10之间

压测

yum install httpd-tools
# 总20w请求,并发1000
[root@k8s-m1 hpa]# ab -n 200000 -c 1000 http://10.0.0.129/index.html 

观察扩容状态

#3分钟后扩容
[root@k8s-m1 ~]# kubectl get hpa
NAME   REFERENCE        TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
web    Deployment/web   0%/80%    2         10        4          11m
[root@k8s-m1 ~]# kubectl get pod
NAME                   READY   STATUS    RESTARTS   AGE
web-67bbbf48fc-5gkf8   1/1     Running   0          11m
web-67bbbf48fc-6xvdk   1/1     Running   0          4m14s
web-67bbbf48fc-cgflp   1/1     Running   0          18m
web-67bbbf48fc-ftvct   1/1     Running   0          4m14s

#5分钟后冷却
[root@k8s-m1 ~]# kubectl get hpa
NAME   REFERENCE        TARGETS   MINPODS   MAXPODS   REPLICAS   AGE
web    Deployment/web   0%/80%    2         10        2          17m
[root@k8s-m1 ~]# kubectl get pod
NAME                   READY   STATUS    RESTARTS   AGE
web-67bbbf48fc-5gkf8   1/1     Running   0          18m
web-67bbbf48fc-cgflp   1/1     Running   0          25m

基于自定义指标

概述

001 为满足更多的需求,HPA也支持自定义指标,例如QPS、5xx错误状态码等
002 实现自定义指标由autoscaling/v2版本提供
003 对于自定义指标(例如QPS),将使用custom.metrics.k8s.io API,由相关适配器(Adapter)服务提供
1639547057253.png

基于qps实现pod动态扩容缩容案例

假设我们有一个网站,想基于每秒接收到的HTTP请求对其Pod进行
自动缩放,实现HPA大概步骤:
001 部署Prometheus
002 对应用暴露指标,部署应用,并让Prometheus采集暴露的指标
003 部署Prometheus Adapter
004 为指定HPA配置Prometheus Adapter
005 创建HPA
006 压测、验证

部署Prometheus

[root@k8s-m1 prometheus]# kubectl apply -f .

[root@k8s-m1 prometheus]# kubectl get pod -n kube-system
NAME                                      READY   STATUS    RESTARTS   AGE
...
prometheus-8474f8559d-pff4r               2/2     Running   0          4m43s
1639548227041.png

对应用暴露指标,部署应用,并让Prometheus采集暴露的指标

apiVersion: apps/v1
kind: Deployment
metadata:
  name: metrics-flask-app
spec:
  replicas: 3
  selector:
    matchLabels:
      app: flask-app
  template:
    metadata:
      labels:
        app: flask-app
      # 声明Prometheus采集
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "80"
        prometheus.io/path: "/metrics"
    spec:
      containers:
      - image: lizhenliang/metrics-flask-app
        name: web
......
----------------------------------------------------------------------------------
[root@k8s-m1 metrics-app]# kubectl get pod
NAME                                 READY   STATUS    RESTARTS   AGE
metrics-flask-app-66c9995b58-b2pf5   1/1     Running   0          4m57s
metrics-flask-app-66c9995b58-mqthk   1/1     Running   0          4m57s
metrics-flask-app-66c9995b58-slgzm   1/1     Running   0          4m57s     
1639548836296.png
1639548983916.png

部署Prometheus Adapter

[root@k8s-m1 adapter]# ls
prometheus-adapter-configmap.yaml  prometheus-adapter.yaml
[root@k8s-m1 adapter]# kubectl apply -f .

[root@k8s-m1 adapter]# kubectl get pod -n kube-system
......
NAME                                      READY   STATUS    RESTARTS   AGE
prometheus-adapter-7f94cc997d-gdl9k       1/1     Running   0          6m34s

[root@k8s-m1 adapter]# kubectl get apiservices
v1beta1.custom.metrics.k8s.io    kube-system/prometheus-adapter   True        

[root@k8s-m1 adapter]# kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1"
{...}

为指定HPA配置Prometheus Adapter

[root@k8s-m1 adapter]# vi prometheus-adapter.yaml 
#加入自定义指标

data:
  config.yaml: |
    rules:
    - seriesQuery: 'request_count_total{app="flask-app"}'
      resources:
        overrides:
          kubernetes_namespace: {resource: "namespace"}
          kubernetes_pod_name: {resource: "pod"}
      name:
        matches: "request_count_total"
        as: "qps"
      metricsQuery: 'sum(rate(<<.Series>>{<<.LabelMatchers>>}[2m])) by (<<.GroupBy>>)'

----------------------------------------------------------------------------
部署
[root@k8s-m1 adapter]# kubectl apply -f prometheus-adapter.yaml 

[root@k8s-m1 adapter]# kubectl get --raw "/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/*/qps"
{"kind":"MetricValueList","apiVersion":"custom.metrics.k8s.io/v1beta1","metadata":{"selfLink":"/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/pods/%2A/qps"},"items":[{"describedObject":{"kind":"Pod","namespace":"default","name":"metrics-flask-app-66c9995b58-b2pf5","apiVersion":"/v1"},"metricName":"qps","timestamp":"2021-12-15T07:48:11Z","value":"16m","selector":null},{"describedObject":{"kind":"Pod","namespace":"default","name":"metrics-flask-app-66c9995b58-mqthk","apiVersion":"/v1"},"metricName":"qps","timestamp":"2021-12-15T07:48:11Z","value":"16m","selector":null},{"describedObject":{"kind":"Pod","namespace":"default","name":"metrics-flask-app-66c9995b58-slgzm","apiVersion":"/v1"},"metricName":"qps","timestamp":"2021-12-15T07:48:11Z","value":"16m","selector":null}]}

----------------------------------------------------------------------------
配置描述:
• seriesQuery:Prometheus查询语句,查询应用系列指标。
• resources:Kubernetes资源标签映射到Prometheus标签。
• name:将Prometheus指标名称在自定义指标API中重命名,matches正则匹配,as指定新名称。
• metricsQuery:一个Go模板,对调用自定义指标API转换为Prometheus查询语句。


Adapter向Prometheus查询语句最终是:
sum(rate(request_count_total{app="flask-app", kubernetes_namespace="default"}[2m])) by (kubernetes_pod_name)

1639550395349.png

创建HPA

[root@k8s-m1 hpa]# vi hpa-v2-qps.yaml 
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: metrics-flask-app 
  namespace: default
spec:
  minReplicas: 1
  maxReplicas: 10
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: metrics-flask-app
  metrics:
  - type: Pods
    pods:
      metric:
        name: qps 
      target:
        type: AverageValue
        averageValue: 10000m

-------------------------------------------------------------------------
# 所有Pod平均值为10000m触发扩容,即每秒10个请求
[root@k8s-m1 hpa]# kubectl apply -f hpa-v2-qps.yaml

[root@k8s-m1 hpa]# kubectl get pod,svc
NAME                                     READY   STATUS    RESTARTS   AGE
pod/metrics-flask-app-66c9995b58-b2pf5   1/1     Running   2          109m
pod/metrics-flask-app-66c9995b58-mqthk   1/1     Running   2          109m
pod/metrics-flask-app-66c9995b58-slgzm   1/1     Running   2          109m

NAME                        TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
service/metrics-flask-app   ClusterIP   10.0.0.119   <none>        80/TCP    109m

压力测试

[root@k8s-m1 hpa]# ab -n 300000 -c 1000 http://10.0.0.119/

[root@k8s-m1 hpa]# kubectl get pod        
NAME                                 READY   STATUS    RESTARTS   AGE
metrics-flask-app-66c9995b58-5gb77   1/1     Running   0          4m4s
metrics-flask-app-66c9995b58-b2pf5   1/1     Running   2          127m
metrics-flask-app-66c9995b58-jv2dr   1/1     Running   0          4m19s
metrics-flask-app-66c9995b58-lq8s4   1/1     Running   0          4m4s
metrics-flask-app-66c9995b58-mqthk   1/1     Running   2          127m
metrics-flask-app-66c9995b58-rq8zs   1/1     Running   0          4m19s
metrics-flask-app-66c9995b58-sgtkw   1/1     Running   0          4m4s
metrics-flask-app-66c9995b58-slgzm   1/1     Running   2          127m
metrics-flask-app-66c9995b58-vzzgt   1/1     Running   0          4m19s
metrics-flask-app-66c9995b58-xh9bb   1/1     Running   0          4m4s

[root@k8s-m1 hpa]# kubectl get hpa
NAME              REFERENCE                     TARGETS      MINPODS   MAXPODS REPLICAS 
metrics-flask-app Deployment/metrics-flask-app  258837m/10   1         10        10     



#5分钟后冷却
[root@k8s-m1 hpa]# kubectl get pod 
NAME                                 READY   STATUS    RESTARTS   AGE
metrics-flask-app-66c9995b58-b2pf5   1/1     Running   2          133m

[root@k8s-m1 hpa]# kubectl get hpa
NAME                REFERENCE                      TARGETS   MINPODS   MAXPODS REPLICAS
metrics-flask-app   Deployment/metrics-flask-app   16m/10    1         10      1     


©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容