# Horizontal Pod Autoscaling
應用的資源使用率通常都有高峰和低谷的時候,如何削峰填谷,提高集群的整體資源利用率,讓service中的Pod個數自動調整呢?這就有賴于Horizontal Pod Autoscaling了,顧名思義,使Pod水平自動縮放。這個Object(跟Pod、Deployment一樣都是API resource)也是最能體現kubernetes之于傳統運維價值的地方,不再需要手動擴容了,終于實現自動化了,還可以自定義指標,沒準未來還可以通過人工智能自動進化呢!
HPA屬于Kubernetes中的**autoscaling** SIG(Special Interest Group),其下有兩個feature:
- [Arbitrary/Custom Metrics in the Horizontal Pod Autoscaler#117](https://github.com/kubernetes/features/issues/117)
- [Monitoring Pipeline Metrics HPA API #118](https://github.com/kubernetes/features/issues/118)
Kubernetes自1.2版本引入HPA機制,到1.6版本之前一直是通過kubelet來獲取監控指標來判斷是否需要擴縮容,1.6版本之后必須通過API server、Heapseter或者kube-aggregator來獲取監控指標。
對于1.6以前版本中開啟自定義HPA請參考[Kubernetes autoscaling based on custom metrics without using a host port](https://medium.com/@marko.luksa/kubernetes-autoscaling-based-on-custom-metrics-without-using-a-host-port-b783ed6241ac),對于1.7及以上版本請參考[Configure Kubernetes Autoscaling With Custom Metrics in Kubernetes 1.7 - Bitnami](https://docs.bitnami.com/kubernetes/how-to/configure-autoscaling-custom-metrics/)。
## HPA解析
Horizontal Pod Autoscaling僅適用于Deployment和ReplicaSet,在V1版本中僅支持根據Pod的CPU利用率擴所容,在v1alpha版本中,支持根據內存和用戶自定義的metric擴縮容。
如果你不想看下面的文章可以直接看下面的示例圖,組件交互、組件的配置、命令示例,都畫在圖上了。
Horizontal Pod Autoscaling由API server和controller共同實現。

## Metrics支持
在不同版本的API中,HPA autoscale時可以根據以下指標來判斷:
- autoscaling/v1
- CPU
- autoscaling/v1alpha1
- 內存
- 自定義metrics
- kubernetes1.6起支持自定義metrics,但是必須在kube-controller-manager中配置如下兩項:
- `--horizontal-pod-autoscaler-use-rest-clients=true`
- `--api-server`指向[kube-aggregator](https://github.com/kubernetes/kube-aggregator),也可以使用heapster來實現,通過在啟動heapster的時候指定`--api-server=true`。查看[kubernetes metrics](https://github.com/kubernetes/metrics)
- 多種metrics組合
- HPA會根據每個metric的值計算出scale的值,并將最大的那個值作為擴容的最終結果。
## 使用kubectl管理
Horizontal Pod Autoscaling作為API resource也可以像Pod、Deployment一樣使用kubeclt命令管理,使用方法跟它們一樣,資源名稱為`hpa`。
```bash
kubectl create hpa
kubectl get hpa
kubectl describe hpa
kubectl delete hpa
```
有一點不同的是,可以直接使用`kubectl autoscale`直接通過命令行的方式創建Horizontal Pod Autoscaler。
用法如下:
```bash
kubectl autoscale (-f FILENAME | TYPE NAME | TYPE/NAME) [--min=MINPODS] --max=MAXPODS
[--cpu-percent=CPU] [flags] [options]
```
舉個例子:
```bash
kubectl autoscale deployment foo --min=2 --max=5 --cpu-percent=80
```
為Deployment foo創建 一個autoscaler,當Pod的CPU利用率達到80%的時候,RC的replica數在2到5之間。
**注意** :如果為ReplicaSet創建HPA的話,無法使用rolling update,但是對于Deployment來說是可以的,因為Deployment在執行rolling update的時候會自動創建新的ReplicationController。
## 什么是 Horizontal Pod Autoscaling?
利用 Horizontal Pod Autoscaling,kubernetes 能夠根據監測到的 CPU 利用率(或者在 alpha 版本中支持的應用提供的 metric)自動的擴容 replication controller,deployment 和 replica set。
Horizontal Pod Autoscaler 作為 kubernetes API resource 和 controller 的實現。Resource 確定 controller 的行為。Controller 會根據監測到用戶指定的目標的 CPU 利用率周期性得調整 replication controller 或 deployment 的 replica 數量。
## Horizontal Pod Autoscaler 如何工作?
Horizontal Pod Autoscaler 由一個控制循環實現,循環周期由 controller manager 中的 `--horizontal-pod-autoscaler-sync-period` 標志指定(默認是 30 秒)。
在每個周期內,controller manager 會查詢 HorizontalPodAutoscaler 中定義的 metric 的資源利用率。Controller manager 從 resource metric API(每個 pod 的 resource metric)或者自定義 metric API(所有的metric)中獲取 metric。
- 每個 Pod 的 resource metric(例如 CPU),controller 通過 resource metric API 獲取 HorizontalPodAutoscaler 中定義的每個 Pod 中的 metric。然后,如果設置了目標利用率,controller 計算利用的值與每個 Pod 的容器里的 resource request 值的百分比。如果設置了目標原始值,將直接使用該原始 metric 值。然后 controller 計算所有目標 Pod 的利用率或原始值(取決于所指定的目標類型)的平均值,產生一個用于縮放所需 replica 數量的比率。 請注意,如果某些 Pod 的容器沒有設置相關的 resource request ,則不會定義 Pod 的 CPU 利用率,并且 Aucoscaler 也不會對該 metric 采取任何操作。
- 對于每個 Pod 自定義的 metric,controller 功能類似于每個 Pod 的 resource metric,只是它使用原始值而不是利用率值。
- 對于 object metric,獲取單個度量(描述有問題的對象),并與目標值進行比較,以產生如上所述的比率。
HorizontalPodAutoscaler 控制器可以以兩種不同的方式獲取 metric :直接的 Heapster 訪問和 REST 客戶端訪問。
當使用直接的 Heapster 訪問時,HorizontalPodAutoscaler 直接通過 API 服務器的服務代理子資源查詢 Heapster。需要在集群上部署 Heapster 并在 kube-system namespace 中運行。
Autoscaler 訪問相應的 replication controller,deployment 或 replica set 來縮放子資源。
Scale 是一個允許您動態設置副本數并檢查其當前狀態的接口。
## API Object
Horizontal Pod Autoscaler 是 kubernetes 的 `autoscaling` API 組中的 API 資源。當前的穩定版本中,只支持 CPU 自動擴縮容,可以在`autoscaling/v1` API 版本中找到。
在 alpha 版本中支持根據內存和自定義 metric 擴縮容,可以在`autoscaling/v2alpha1` 中找到。`autoscaling/v2alpha1` 中引入的新字段在`autoscaling/v1` 中是做為 annotation 而保存的。
## 在 kubectl 中支持 Horizontal Pod Autoscaling
Horizontal Pod Autoscaler 和其他的所有 API 資源一樣,通過 `kubectl` 以標準的方式支持。
我們可以使用`kubectl create`命令創建一個新的 autoscaler。
我們可以使用`kubectl get hpa`列出所有的 autoscaler,使用`kubectl describe hpa`獲取其詳細信息。
最后我們可以使用`kubectl delete hpa`刪除 autoscaler。
另外,可以使用`kubectl autoscale`命令,很輕易的就可以創建一個 Horizontal Pod Autoscaler。
例如,執行`kubectl autoscale rc foo —min=2 —max=5 —cpu-percent=80`命令將為 replication controller *foo* 創建一個 autoscaler,目標的 CPU 利用率是`80%`,replica 的數量介于 2 和 5 之間。
## 滾動更新期間的自動擴縮容
目前在Kubernetes中,可以通過直接管理 replication controller 或使用 deployment 對象來執行 [滾動更新](https://kubernetes.io/docs/tasks/run-application/rolling-update-replication-controller),該 deployment 對象為您管理基礎 replication controller。
Horizontal Pod Autoscaler 僅支持后一種方法:Horizontal Pod Autoscaler 被綁定到 deployment 對象,它設置 deployment 對象的大小,deployment 負責設置底層 replication controller 的大小。
Horizontal Pod Autoscaler 不能使用直接操作 replication controller 進行滾動更新,即不能將 Horizontal Pod Autoscaler 綁定到 replication controller,并進行滾動更新(例如使用`kubectl rolling-update`)。
這不行的原因是,當滾動更新創建一個新的 replication controller 時,Horizontal Pod Autoscaler 將不會綁定到新的 replication controller 上。
## 支持多個 metric
Kubernetes 1.6 中增加了支持基于多個 metric 的擴縮容。您可以使用`autoscaling/v2alpha1` API 版本來為 Horizontal Pod Autoscaler 指定多個 metric。然后 Horizontal Pod Autoscaler controller 將權衡每一個 metric,并根據該 metric 提議一個新的 scale。在所有提議里最大的那個 scale 將作為最終的 scale。
## 支持自定義 metric
**注意:** Kubernetes 1.2 根據特定于應用程序的 metric ,通過使用特殊注釋的方式,增加了對縮放的 alpha 支持。
在 Kubernetes 1.6中刪除了對這些注釋的支持,有利于`autoscaling/v2alpha1` API。 雖然舊的收集自定義 metric 的舊方法仍然可用,但是這些 metric 將不可供 Horizontal Pod Autoscaler 使用,并且用于指定要縮放的自定義 metric 的以前的注釋也不在受 Horizontal Pod Autoscaler 認可。
Kubernetes 1.6增加了在 Horizontal Pod Autoscale r中使用自定義 metric 的支持。
您可以為`autoscaling/v2alpha1` API 中使用的 Horizontal Pod Autoscaler 添加自定義 metric 。
Kubernetes 然后查詢新的自定義 metric API 來獲取相應自定義 metric 的值。
## 前提條件
為了在 Horizontal Pod Autoscaler 中使用自定義 metric,您必須在您集群的 controller manager 中將 `--horizontal-pod-autoscaler-use-rest-clients` 標志設置為 true。然后,您必須通過將 controller manager 的目標 API server 設置為 API server aggregator(使用`--apiserver`標志),配置您的 controller manager 通過 API server aggregator 與API server 通信。 Resource metric API和自定義 metric API 也必須向 API server aggregator 注冊,并且必須由集群上運行的 API server 提供。
您可以使用 Heapster 實現 resource metric API,方法是將 `--api-server` 標志設置為 true 并運行 Heapster。 單獨的組件必須提供自定義 metric API(有關自定義metric API的更多信息,可從 [k8s.io/metrics repository](https://github.com/kubernetes/metrics) 獲得)。
## 參考
- HPA說明:https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
- HPA詳解:https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/
- 自定義metrics開發:https://github.com/kubernetes/metrics
- 1.7版本的kubernetes中啟用自定義HPA:[Configure Kubernetes Autoscaling With Custom Metrics in Kubernetes 1.7 - Bitnami](https://docs.bitnami.com/kubernetes/how-to/configure-autoscaling-custom-metrics/)
- 序言
- 云原生
- 云原生(Cloud Native)的定義
- CNCF - 云原生計算基金會簡介
- CNCF章程
- 云原生的設計哲學
- Play with Kubernetes
- 快速部署一個云原生本地實驗環境
- Kubernetes與云原生應用概覽
- 云原生應用之路——從Kubernetes到Cloud Native
- 云原生編程語言
- 云原生編程語言Ballerina
- 云原生編程語言Pulumi
- 云原生的未來
- Kubernetes架構
- 設計理念
- Etcd解析
- 開放接口
- CRI - Container Runtime Interface(容器運行時接口)
- CNI - Container Network Interface(容器網絡接口)
- CSI - Container Storage Interface(容器存儲接口)
- Kubernetes中的網絡
- Kubernetes中的網絡解析——以flannel為例
- Kubernetes中的網絡解析——以calico為例
- 具備API感知的網絡和安全性管理開源軟件Cilium
- Cilium架構設計與概念解析
- 資源對象與基本概念解析
- Pod狀態與生命周期管理
- Pod概覽
- Pod解析
- Init容器
- Pause容器
- Pod安全策略
- Pod的生命周期
- Pod Hook
- Pod Preset
- Pod中斷與PDB(Pod中斷預算)
- 集群資源管理
- Node
- Namespace
- Label
- Annotation
- Taint和Toleration(污點和容忍)
- 垃圾收集
- 控制器
- Deployment
- StatefulSet
- DaemonSet
- ReplicationController和ReplicaSet
- Job
- CronJob
- Horizontal Pod Autoscaling
- 自定義指標HPA
- 準入控制器(Admission Controller)
- 服務發現
- Service
- Ingress
- Traefik Ingress Controller
- 身份與權限控制
- ServiceAccount
- RBAC——基于角色的訪問控制
- NetworkPolicy
- 存儲
- Secret
- ConfigMap
- ConfigMap的熱更新
- Volume
- Persistent Volume(持久化卷)
- Storage Class
- 本地持久化存儲
- 集群擴展
- 使用自定義資源擴展API
- 使用CRD擴展Kubernetes API
- Aggregated API Server
- APIService
- Service Catalog
- 資源調度
- QoS(服務質量等級)
- 用戶指南
- 資源對象配置
- 配置Pod的liveness和readiness探針
- 配置Pod的Service Account
- Secret配置
- 管理namespace中的資源配額
- 命令使用
- Docker用戶過度到kubectl命令行指南
- kubectl命令概覽
- kubectl命令技巧大全
- 使用etcdctl訪問kubernetes數據
- 集群安全性管理
- 管理集群中的TLS
- kubelet的認證授權
- TLS bootstrap
- 創建用戶認證授權的kubeconfig文件
- IP偽裝代理
- 使用kubeconfig或token進行用戶身份認證
- Kubernetes中的用戶與身份認證授權
- Kubernetes集群安全性配置最佳實踐
- 訪問Kubernetes集群
- 訪問集群
- 使用kubeconfig文件配置跨集群認證
- 通過端口轉發訪問集群中的應用程序
- 使用service訪問群集中的應用程序
- 從外部訪問Kubernetes中的Pod
- Cabin - Kubernetes手機客戶端
- Kubernetic - Kubernetes桌面客戶端
- Kubernator - 更底層的Kubernetes UI
- 在Kubernetes中開發部署應用
- 適用于kubernetes的應用開發部署流程
- 遷移傳統應用到Kubernetes中——以Hadoop YARN為例
- 最佳實踐概覽
- 在CentOS上部署Kubernetes集群
- 創建TLS證書和秘鑰
- 創建kubeconfig文件
- 創建高可用etcd集群
- 安裝kubectl命令行工具
- 部署master節點
- 安裝flannel網絡插件
- 部署node節點
- 安裝kubedns插件
- 安裝dashboard插件
- 安裝heapster插件
- 安裝EFK插件
- 生產級的Kubernetes簡化管理工具kubeadm
- 使用kubeadm在Ubuntu Server 16.04上快速構建測試集群
- 服務發現與負載均衡
- 安裝Traefik ingress
- 分布式負載測試
- 網絡和集群性能測試
- 邊緣節點配置
- 安裝Nginx ingress
- 安裝配置DNS
- 安裝配置Kube-dns
- 安裝配置CoreDNS
- 運維管理
- Master節點高可用
- 服務滾動升級
- 應用日志收集
- 配置最佳實踐
- 集群及應用監控
- 數據持久化問題
- 管理容器的計算資源
- 集群聯邦
- 存儲管理
- GlusterFS
- 使用GlusterFS做持久化存儲
- 使用Heketi作為Kubernetes的持久存儲GlusterFS的external provisioner
- 在OpenShift中使用GlusterFS做持久化存儲
- GlusterD-2.0
- Ceph
- 用Helm托管安裝Ceph集群并提供后端存儲
- 使用Ceph做持久化存儲
- 使用rbd-provisioner提供rbd持久化存儲
- OpenEBS
- 使用OpenEBS做持久化存儲
- Rook
- NFS
- 利用NFS動態提供Kubernetes后端存儲卷
- 集群與應用監控
- Heapster
- 使用Heapster獲取集群和對象的metric數據
- Prometheus
- 使用Prometheus監控kubernetes集群
- Prometheus查詢語言PromQL使用說明
- 使用Vistio監控Istio服務網格中的流量
- 分布式跟蹤
- OpenTracing
- 服務編排管理
- 使用Helm管理Kubernetes應用
- 構建私有Chart倉庫
- 持續集成與發布
- 使用Jenkins進行持續集成與發布
- 使用Drone進行持續集成與發布
- 更新與升級
- 手動升級Kubernetes集群
- 升級dashboard
- 領域應用概覽
- 微服務架構
- 微服務中的服務發現
- 使用Java構建微服務并發布到Kubernetes平臺
- Spring Boot快速開始指南
- Service Mesh 服務網格
- 企業級服務網格架構
- Service Mesh基礎
- Service Mesh技術對比
- 采納和演進
- 定制和集成
- 總結
- Istio
- 安裝并試用Istio service mesh
- 配置請求的路由規則
- 安裝和拓展Istio service mesh
- 集成虛擬機
- Istio中sidecar的注入規范及示例
- 如何參與Istio社區及注意事項
- Istio教程
- Istio免費學習資源匯總
- 深入理解Istio Service Mesh中的Envoy Sidecar注入與流量劫持
- 深入理解Istio Service Mesh中的Envoy Sidecar代理的路由轉發
- Linkerd
- Linkerd 使用指南
- Conduit
- Condiut概覽
- 安裝Conduit
- Envoy
- Envoy的架構與基本術語
- Envoy作為前端代理
- Envoy mesh教程
- SOFAMesh
- SOFAMesh中的Dubbo on x-protocol
- SOFAMosn
- 使用 SOFAMosn 構建 SOFAMesh
- 大數據
- Spark standalone on Kubernetes
- 運行支持Kubernetes原生調度的Spark程序
- Serverless架構
- 理解Serverless
- FaaS-函數即服務
- OpenFaaS快速入門指南
- 邊緣計算
- 人工智能