---
tags: Kubernetes, HPA
description: Horizontal Pod Autoscaler, aka pod autoscaling
robots: index, follow
---
<style>
html, body, .ui-content {
background-color: #333;
color: #ddd;
}
.markdown-body h1,
.markdown-body h2,
.markdown-body h3,
.markdown-body h4,
.markdown-body h5,
.markdown-body h6 {
color: #ddd;
}
.markdown-body h1,
.markdown-body h2 {
border-bottom-color: #ffffff69;
}
.markdown-body h1 .octicon-link,
.markdown-body h2 .octicon-link,
.markdown-body h3 .octicon-link,
.markdown-body h4 .octicon-link,
.markdown-body h5 .octicon-link,
.markdown-body h6 .octicon-link {
color: #fff;
}
.markdown-body img {
background-color: transparent;
}
.ui-toc-dropdown .nav>.active:focus>a, .ui-toc-dropdown .nav>.active:hover>a, .ui-toc-dropdown .nav>.active>a {
color: white;
border-left: 2px solid white;
}
.expand-toggle:hover,
.expand-toggle:focus,
.back-to-top:hover,
.back-to-top:focus,
.go-to-bottom:hover,
.go-to-bottom:focus {
color: white;
}
.ui-toc-dropdown {
background-color: #333;
}
.ui-toc-label.btn {
background-color: #191919;
color: white;
}
.ui-toc-dropdown .nav>li>a:focus,
.ui-toc-dropdown .nav>li>a:hover {
color: white;
border-left: 1px solid white;
}
.markdown-body blockquote {
color: #bcbcbc;
}
.markdown-body table tr {
background-color: #5f5f5f;
}
.markdown-body table tr:nth-child(2n) {
background-color: #4f4f4f;
}
.markdown-body code,
.markdown-body tt {
color: #eee;
background-color: rgba(230, 230, 230, 0.36);
}
a,
.open-files-container li.selected a {
color: #5EB7E0;
}
</style>
# HPA - Horizontal Pod Autoscaler
HPA(Horizontal Pod Autoscaler)在其他技術中,又稱為autoscaling技術,例如能夠依據CPU、RAM的附載狀況,擴展虛擬機的數量,不過在Kubernetes的世界中,我們擴展的是Pod。
要搭配HPA最好的作法,就是使用deployment建立pod。
首先我們要確認metrics-server有在運作。
```shell=
student@master:~$ kubectl -n kube-system get deployments.apps metrics-server
NAME READY UP-TO-DATE AVAILABLE AGE
metrics-server 1/1 1 1 5d17h
```
如果沒有的話,可以到這邊[下載yaml](https://github.com/yansheng133/initk8sfortraining/blob/main/components.yaml "meter server")檔進行安裝。
```shell=
student@master:~$ kubectl create -f components.yaml
```
## 1. 建立web image
使用一個網頁服務(hpa-php5),建立deployment資源,使用80 port,暫定為一個副本。
image中所使用的php source code,除了跑一些迴圈外,也會顯示source ip與回應的container還有時間。
```php=
<?php
$x = 0.0001;
for ($i = 0; $i <= 1000000; $i++) {
$x += sqrt($x);
}
if (!empty($_SERVER["HTTP_CLIENT_IP"])){
$ip = $_SERVER["HTTP_CLIENT_IP"];
}elseif(!empty($_SERVER["HTTP_X_FORWARDED_FOR"])){
$ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
}else{
$ip = $_SERVER["REMOTE_ADDR"];
}
date_default_timezone_set('Asia/Taipei');
echo "Source IP:" . $ip . ", Response by: " . gethostname() . " -- " . date('Y/m/d H:i:s');
echo "\n";
?>
```
建立hpa-php5 image,如果你想要完整走過一遍的話,可以參考這邊的[建立指令](https://hackmd.io/qCalUX98TP6LafSJ2mCadg?view#3-build-elasticsearch-fluentd-image)。
```dockerfile=
FROM php:5-apache
COPY index.php /var/www/html/index.php
RUN chmod a+rx index.php
```
或者使用作者建好的[image](https://hub.docker.com/repository/docker/yansheng133/hpa-php5 "HPA PHP5")進行。
## 2. 建立HPA web服務
建立hpa web的yaml檔,同時要加入資源需求與限制(cpu: 200m, 500m)。
```yaml=
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: hpaweb
name: hpaweb
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: hpaweb
template:
metadata:
creationTimestamp: null
labels:
app: hpaweb
spec:
containers:
- image: yansheng133/hpa-php5:0.5
imagePullPolicy: IfNotPresent
name: hpa-php5
ports:
- containerPort: 80
protocol: TCP
resources:
limits:
cpu: 500m
requests:
cpu: 200m
```
建立hpa web deployment。
```shell=
student@master:~$ kubectl create -f hpaweb.yaml
deployment.apps/hpaweb created
```
使用export搭配NodePort讓服務對外。
```shell=
student@master:~$ kubectl expose deployment hpaweb --port=80 --target-port=80 --type=NodePort
service/hpaweb exposed
student@master:~$ kubectl get svc hpaweb
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hpaweb NodePort 10.106.90.127 <none> 80:30516/TCP 2s
```
## 3. 附載觀察與設定HPA
先觀察一下這些資源建立完畢後,hpaweb的附載狀況,我們應該會發現非常低。
```shell=
student@master:~$ kubectl top pod
NAME CPU(cores) MEMORY(bytes)
hpaweb-cf96cf8c4-k8gdf 1m 13Mi
```
此時先對他增加一些附載,觀察CPU的附載狀況會到多少,此時可以開兩個連線視窗進行觀察。
增加附載。
```shell=
student@master:~$ watch -n 0.1 curl 192.168.122.30:30516
...
...
...
Every 0.1s: curl 192.168.122.30:30516 master9013.inwinstack.lab: Sun Sep 19 07:48:03 2021
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 100 80 100 80 0 0 1081
0 --:--:-- --:--:-- --:--:-- 1095
Source IP:10.6.72.0, Response by: hpaweb-cf96cf8c4-k8gdf -- 2021/09/19 15:48:03
...
...
...
```
觀察附載。
```shell=
student@master:~$ watch -n 1 kubectl top pod
...
...
Every 1.0s: kubectl top pod master9013.inwinstack.lab: Sun Sep 19 07:49:34 2021
NAME CPU(cores) MEMORY(bytes)
hpaweb-cf96cf8c4-k8gdf 406m 13Mi
...
...
```
此時我們可以停止觀察附載狀況,利用hpa指令進行hpa設置。
```shell=
student@master:~$ kubectl autoscale deployment hpaweb --max=7 --min=1 --cpu-percent=50
horizontalpodautoscaler.autoscaling/hpaweb autoscaled
student@master:~$ kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
hpaweb Deployment/hpaweb 0%/50% 1 7 1 70m
```
依據我們前面對pod的資源需求(200m)來看,超過50%(100m)就要scale出新的pod,依據先前的pod附載狀況來看(406m),我們可以算出最後一共約會有4~5個pod。
先前的yaml設置搭配HPA的規則,如果負擔全滿,會有7個pod運作,每個pod最高CPU資源為500m。
如果先前沒有設置pod resource limit, request,會發現TARGETS的第一個欄位是?%
讓我們繼續對hpaweb增加附載。
```shell=
student@master:~$ watch -n 0.1 curl 192.168.122.30:30516
...
...
...
Every 0.1s: curl 192.168.122.30:30516 master9013.inwinstack.lab: Sun Sep 19 07:48:03 2021
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0 100 80 100 80 0 0 1081
0 --:--:-- --:--:-- --:--:-- 1095
Source IP:10.6.72.0, Response by: hpaweb-cf96cf8c4-k8gdf -- 2021/09/19 15:48:03
...
...
...
```
觀察一下pod的狀態。
```shell=
student@master:~$ watch -n 1 kubectl top pod
...
...
Every 1.0s: kubectl top pod master9013.inwinstack.lab: Sun Sep 19 09:17:03 2021
NAME CPU(cores) MEMORY(bytes)
hpaweb-59d6c9779b-9946b 88m 13Mi
hpaweb-59d6c9779b-mwhg6 139m 15Mi
hpaweb-59d6c9779b-rbwb7 74m 13Mi
hpaweb-59d6c9779b-tgzbw 100m 13Mi
...
...
```
觀察hpa的狀態。
```shell=
student@master:~$ kubectl get hpa hpaweb
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
hpaweb Deployment/hpaweb 42%/50% 1 7 4 82m
```
使用describe多取得一些hpa的資訊,例如Events。
```shell=
student@master:~$ kubectl describe hpa hpaweb
Name: hpaweb
Namespace: default
Labels: <none>
Annotations: <none>
CreationTimestamp: Sun, 19 Sep 2021 07:59:05 +0000
Reference: Deployment/hpaweb
Metrics: ( current / target )
resource cpu on pods (as a percentage of request): 47% (95m) / 50%
Min replicas: 1
Max replicas: 7
Deployment pods: 4 current / 4 desired
Conditions:
Type Status Reason Message
---- ------ ------ -------
AbleToScale True ReadyForNewScale recommended size matches current size
ScalingActive True ValidMetricFound the HPA was able to successfully calculate a replica count from cpu resource utilization (percentage of request)
ScalingLimited False DesiredWithinRange the desired count is within the acceptable range
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulRescale 25m horizontal-pod-autoscaler New size: 4; reason: cpu resource utilization (percentage of request) above target
```
## 4. 建議
:::info
1. HPA在一些無狀態的應用相當不錯,透過一個良好的pod設計,將Application與Data、config分別拆開,搭配Service與Deployment,比較能夠享用HPA的好處。
2. 除了本例中所使用的CPU作為條件外,還有[其他做法可以參考](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/instrumentation/custom-metrics-api.md "Custom Metrics API")。
3. 有狀態的pod(statefulset),例如SQL, 或者有使用storage的應用(NFS搭配readonly除外)要慎用。
:::
## 5. 參考資料
1. [Official - Horizontal Pod Autoscaler](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/ "Horizontal Pod Autoscaler")
2. [Official - horizontal-pod-autoscale-walkthrough](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/ "horizontal-pod-autoscale-walkthrough")