1. 程式人生 > >如何利用kubernetes實現應用的水平擴充套件(HPA)

如何利用kubernetes實現應用的水平擴充套件(HPA)

雲端計算具有水平彈性的特性,這個是雲端計算區別於傳統IT技術架構的主要特性。對於Kubernetes中的POD叢集來說,HPA就是實現這種水平伸縮的控制器, 它能在當POD中業務負載上升的時候,建立新的POD來保證業務系統穩定執行,當POD中業務負載下降的時候,可以銷燬POD來提高資源利用率。

HPA介紹

Horizontal Pod Autoscaling,簡稱HPA,是Kubernetes中實現POD水平自動伸縮的功能。為什麼要水平而不叫垂直, 那是因為自動擴充套件主要分為兩種:

  • 水平擴充套件(scale out),針對於例項數目的增減
  • 垂直擴充套件(scal up),即單個例項可以使用的資源的增減, 比如增加cpu和增大記憶體
    而HPA屬於前者。它可以根據CPU使用率或應用自定義metrics
    自動擴充套件Pod數量(支援 replication controller、deployment 和 replica set)

架構介紹


獲取metrics的兩種方式:

  • Heapster: heapster提供metrics服務, 但是在v1(autoscaling/v1)版本中僅支援以CPU作為擴充套件度量指標, 而其他比如:記憶體, 網路流量, qps等目前處於beta階段(autoscaling/v2beta1)
  • Cousom: 同樣處於beta階段(autoscaling/v2beta1), 但是涉及到自定義的REST API的開發, 複雜度會大一些, 並且當需要從自定義的監控中獲取資料時,只能設定絕對值,無法設定使用率

工作流程:

  • 1.建立HPA資源,設定目標CPU使用率限額,以及最大、最小例項數, 一定要設定Pod的資源限制引數: request, 負責HPA不會工作。
  • 2.控制管理器每隔30s(可以通過–horizontal-pod-autoscaler-sync-period修改)查詢metrics的資源使用情況
  • 3.然後與建立時設定的值和指標做對比(平均值之和/限額),求出目標調整的例項個數
  • 4.目標調整的例項數不能超過1中設定的最大、最小例項數,如果沒有超過,則擴容;超過,則擴容至最大的例項個數
  • 重複2-4步

自動伸縮演算法:
HPA Controller會通過調整副本數量使得CPU使用率儘量向期望值靠近,而且不是完全相等.另外,官方考慮到自動擴充套件的決策可能需要一段時間才會生效:例如當pod所需要的CPU負荷過大,從而在建立一個新pod的過程中,系統的CPU使用量可能會同樣在有一個攀升的過程。所以,在每一次作出決策後的一段時間內,將不再進行擴充套件決策。對於擴容而言,這個時間段為3分鐘,縮容為5分鐘(可以通過--horizontal-pod-autoscaler-downscale-delay

, --horizontal-pod-autoscaler-upscale-delay進行調整)。

  • HPA Controller中有一個tolerance(容忍力)的概念,它允許一定範圍內的使用量的不穩定,現在預設為0.1,這也是出於維護系統穩定性的考慮。例如,設定HPA排程策略為cpu使用率高於50%觸發擴容,那麼只有當使用率大於55%或者小於45%才會觸發伸縮活動,HPA會盡力把Pod的使用率控制在這個範圍之間。
  • 具體的每次擴容或者縮容的多少Pod的演算法為: Ceil(前採集到的使用率 / 使用者自定義的使用率) * Pod數量)
  • 每次最大擴容pod數量不會超過當前副本數量的2倍

依賴部署

這是kuberntes整個系列的第四篇, 該篇依賴Heapster服務成功安裝, 如果未安裝請參考:

因為基於HeapsterHPA僅支援CPU為維度的自動伸縮, 因此寫了個計算100位π的HTTP服務, 該程式已打包放於百度網盤下, 下載hpa-test-app.tar 匯入然後推到自己私有倉庫, 等待後續測試(放心該映象僅有5M多點)
原始碼如下:

package main

import (
    "fmt"
    "log"
    "net/http"
    "strconv"
    "strings"
)

func main() {
    http.HandleFunc("/", compPiHandler)
    log.Println("Server work at :8080 ...")
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

func compPiHandler(w http.ResponseWriter, r *http.Request) {
    var (
        lenI int
        err  error
    )

    lenS := r.URL.Query().Get("length")
    if lenS != "" {
        lenI, err = strconv.Atoi(lenS)
        if err != nil {
            lenI = 100
        }
    } else {
        lenI = 100
    }

    fmt.Fprintf(w, compPi(lenI))
}

func compPi(L int) string {
    var Pi []string

    N := (L)/4 + 1

    s := make([]int, N+3)
    w := make([]int, N+3)
    v := make([]int, N+3)
    q := make([]int, N+3)
    n := (int)(float32(L)/1.39793 + 1)

    w[0] = 16 * 5
    v[0] = 4 * 239

    for k := 1; k <= n; k++ {
        div(w, 25, w, N)
        div(v, 57121, v, N)
        sub(w, v, q, N)
        div(q, 2*k-1, q, N)
        if k%2 != 0 {
            add(s, q, s, N)
        } else {
            sub(s, q, s, N)
        }
    }

    Pi = append(Pi, fmt.Sprintf("%d.", s[0]))

    for k := 1; k < N; k++ {
        Pi = append(Pi, fmt.Sprintf("%04d", s[k]))
    }

    return strings.Join(Pi, "")
}

func add(a []int, b []int, c []int, N int) {
    i, carry := 0, 0
    for i = N + 1; i >= 0; i-- {
        c[i] = a[i] + b[i] + carry
        if c[i] < 10000 {
            carry = 0
        } else {
            c[i] = c[i] - 10000
            carry = 1
        }
    }
}

func sub(a []int, b []int, c []int, N int) {
    i, borrow := 0, 0
    for i = N + 1; i >= 0; i-- {
        c[i] = a[i] - b[i] - borrow
        if c[i] >= 0 {
            borrow = 0
        } else {
            c[i] = c[i] + 10000
            borrow = 1
        }
    }
}

func div(a []int, b int, c []int, N int) {
    i, tmp, remain := 0, 0, 0
    for i = 0; i <= N+1; i++ {
        tmp = a[i] + remain
        c[i] = tmp / b
        remain = (tmp % b) * 10000
    }
}

服務測試

基於上面提供的hpa-test-app映象, 我們建立一個hpa-test-app service, 然後為該service新增HPA機制。

注意事項:

  • 當Pod沒有設定request時,HPA不會工作。

建立Deployment

注意根據需要修改自己的映象地址

cat << EOF > hpa-test-app-deploy.yaml
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: hpa-test-app-deploy
  labels:
    app: hpa
    version: v0.0.1
spec:
  replicas: 1
  selector:
    matchLabels:
      name: hpa-test-app-deploy
      app: hpa
      version: v0.0.1
  template:
    metadata:
      labels:
        name: hpa-test-app-deploy
        app: hpa
        version: v0.0.1
    spec:
      containers:
      - name: hpa-test-app-deploy
        image: 192.168.204.15/kubernetes/hpa-test-app:v0.0.1
        ports:
        - containerPort: 8080
          name: http
          protocol: TCP
        resources:
          requests:
            cpu: 0.006
            memory: 32Mi
          limits:
            cpu: 0.06
            memory: 128Mi
EOF
kubectl create -f hpa-test-app-deploy.yaml

建立service

cat << EOF > hpa-test-app-svc.yaml
apiVersion: v1
kind: Service
metadata:
  name: hpa-test-app-svc
  labels:
    app: hpa
    version: v0.0.1
spec:
  selector:
    name: hpa-test-app-deploy
    app: hpa
    version: v0.0.1
  ports:
  - name: http
    port: 8080
    protocol: TCP
EOF
kubectl create -f hpa-test-app-svc.yaml

建立HPA

cat << EOF > hpa-test-app-hpa.yaml
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: hpa-test-app-hpa
  labels:
    app: hpa
    version: v0.0.1
spec:
  scaleTargetRef:
    apiVersion: v1
    kind: Deployment
    name: hpa-test-app-deploy
  minReplicas: 1
  maxReplicas: 10
  targetCPUUtilizationPercentage: 70
EOF
kubectl create -f hpa-test-app-hpa.yaml

檢查服務

[[email protected] hpa-test]# kubectl get pods
NAME                                   READY     STATUS    RESTARTS   AGE
hpa-test-app-deploy-69dbc4cf84-5jvb6   1/1       Running   0          23s
[[email protected] hpa-test]# kubectl logs hpa-test-app-deploy-69dbc4cf84-5jvb6
2018/02/05 05:13:14 Server work at :8080 ...
[[email protected] hpa-test]# kubectl get hpa
NAME               REFERENCE                        TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
hpa-test-app-hpa   Deployment/hpa-test-app-deploy   0% / 70%   1         10        1          38s

增壓和減壓測試

首先我們啟動一個busybox的pod, 用來對hap-test-app服務進行壓力測試

cat << EOF > pod-busybox.yaml
apiVersion: v1
kind: Pod
metadata:
  name: busybox
  namespace: default
spec:
  containers:
  - image: busybox
    command:
      - sleep
      - "3600"
    imagePullPolicy: IfNotPresent
    name: busybox
  restartPolicy: Always
EOF
kubectl create -f pod-busybox.yaml

然後我們找到hpa-test-app服務的clusterIP:

[[email protected] apps]# kubectl get svc hpa-test-app-svc
NAME               TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE
hpa-test-app-svc   ClusterIP   10.254.155.132   <none>        8080/TCP   1m

應用擴張

進入容器, 持續訪問hpa-test-app的API(預設計算100位的π, 如果想加大計算可以通過query string: ?length=1000來增大單個請求對cpu的壓力),

kubectl exec -it busybox /bin/sh
/ # while true; do wget -q -O-  10.254.155.132:8080; done

然後我們持續關係HPA的擴張

[[email protected] ~]# kubectl get hpa
NAME               REFERENCE                        TARGETS      MINPODS   MAXPODS   REPLICAS   AGE
hpa-test-app-hpa   Deployment/hpa-test-app-deploy   345% / 70%   1         10        4          52m
[[email protected] ~]# kubectl get hpa
NAME               REFERENCE                        TARGETS      MINPODS   MAXPODS   REPLICAS   AGE
hpa-test-app-hpa   Deployment/hpa-test-app-deploy   287% / 70%   1         10        8          56m
[[email protected] ~]# kubectl get hpa
NAME               REFERENCE                        TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
hpa-test-app-hpa   Deployment/hpa-test-app-deploy   0% / 70%   1         10        10         1h

pod數量的變化情況 1–>2–>4–>8–>10, 最終達到最大的擴充套件上線而停止.

應用收縮

中斷對app的訪問, 會發現容器又收縮為原來的1個:

[[email protected] ~]# kubectl get hpa
NAME               REFERENCE                        TARGETS    MINPODS   MAXPODS   REPLICAS   AGE
hpa-test-app-hpa   Deployment/hpa-test-app-deploy   0% / 70%   1         10        1          1h
[[email protected] ~]# kubectl describe  hpa hpa-test-app-hpa
Name:                                                  hpa-test-app-hpa
Namespace:                                             default
Labels:                                                app=hpa
                                                       version=v0.0.1
Annotations:                                           <none>
CreationTimestamp:                                     Mon, 05 Feb 2018 00:47:31 -0500
Reference:                                             Deployment/hpa-test-app-deploy
Metrics:                                               ( current / target )
  resource cpu on pods  (as a percentage of request):  0% (0) / 70%
Min replicas:                                          1
Max replicas:                                          10
Conditions:
  Type            Status  Reason            Message
  ----            ------  ------            -------
  AbleToScale     True    ReadyForNewScale  the last scale time was sufficiently old as to warrant a new scale
  ScalingActive   True    ValidMetricFound  the HPA was able to succesfully calculate a replica count from cpu resource utilization (percentage of request)
  ScalingLimited  True    TooFewReplicas    the desired replica count was less than the minimum replica count
Events:
  Type     Reason                   Age                From                       Message
  ----     ------                   ----               ----                       -------
  Warning  FailedGetResourceMetric  46m (x57 over 1h)  horizontal-pod-autoscaler  missing request for cpu on container hpa-test-app-deploy in pod default/hpa-test-app-deploy-75b4fd6cf6-sf78p
  Normal   SuccessfulRescale        41m (x2 over 1h)   horizontal-pod-autoscaler  New size: 4; reason: cpu resource utilization (percentage of request) above target
  Normal   SuccessfulRescale        33m                horizontal-pod-autoscaler  New size: 10; reason: cpu resource utilization (percentage of request) above target
  Normal   SuccessfulRescale        28m                horizontal-pod-autoscaler  New size: 1; reason: All metrics below target

總結

本文主要介紹了HPA的相關原理和使用方法,此功能可以能對服務的容器數量做自動伸縮,對於服務的穩定性是一個很好的提升。但是當前穩定版本中只有cpu使用率這一個指標,是一個很大的弊端。但是kubernetes中關於HPA的架子已經成熟, 期待v2進入stable, 到時候HPA才能爆發它正在的魅力。

參考