---
# System prepended metadata

title: Autoscaling
tags: [k8s, Autoscaling, KEDA, Scale out, HPA, VPA, slurm, app, SlinkyProject, Kubernetes, Scale in]

---

Autoscaling
===
###### tags: `SlinkyProject`
###### tags: `Kubernetes`, `k8s`, `app`, `slurm`, `SlinkyProject`, `Autoscaling`, `KEDA`, `HPA`, `VPA`, `Scale out`, `Scale in`

<br>

[TOC]

<br>

## 所需背景知識
- [[應用] keda 部署與測試教學](/iU44zPyST9O5rD7OQYdQYQ)

<br>

## Intro
- [Autoscaling](https://github.com/SlinkyProject/slurm-operator/blob/main/docs/autoscaling.md)

<br>

## 如何填寫 `keda-slurm-compute-e900.yaml`  ？
- ### `keda-slurm-compute-e900.yaml`
    ```yaml=
    apiVersion: keda.sh/v1alpha1
    kind: ScaledObject
    metadata:
      name: scale-e900
      namespace: slurm
    spec:
      scaleTargetRef:
        apiVersion: slinky.slurm.net/v1alpha1
        kind: NodeSet
        name: slurm-compute-e900
      idleReplicaCount: 0
      minReplicaCount: 1
      maxReplicaCount: 3
      triggers:
        - type: prometheus
          metricType: Value
          metadata:
            serverAddress: http://monitor-kube-prometheus-st-prometheus.monitor:9090
            query: slurm_partition_pending_jobs{partition="radar"}
            threshold: '5'
    ```
- ### 確認 `scaleTargetRef` 資訊正確
    > ```yaml
    > scaleTargetRef:
    >   apiVersion: slinky.slurm.net/v1alpha1
    >   kind: NodeSet
    >   name: slurm-compute-e900
    > ```
    - ### 確認要縮放的對象存在：
        對象：`-n slurm NodeSet/slurm-compute-e900`
        ```bash
        $ kubectl -n slurm get NodeSet    # 同 $ kubectl -n slurm get nss
        NAME                     REPLICAS   UPDATED   READY   AGE
        slurm-compute-e900                                    20d
        slurm-compute-esc8000a                                38d
        slurm-compute-esc8000b   1          1         1       38d

        $ kubectl -n slurm get NodeSet/slurm-compute-e900
        NAME                 REPLICAS   UPDATED   READY   AGE
        slurm-compute-e900                                20d
        ```
    - ### apiVersion
        ```
        $ kubectl -n slurm get NodeSet/slurm-compute-e900 -o yaml | grep apiVersion:
        apiVersion: slinky.slurm.net/v1alpha1
        ```

- ### 預期的副本數
    > ```yaml
    > idleReplicaCount: 0
    > minReplicaCount: 1
    > maxReplicaCount: 3
    > ```
    - **`minReplicaCount` & `minReplicaCount`**
        當觸發器上有活動（至少有一個等待中的作業）時，KEDA 會將 NodeSet 的副本數調整為 `minReplicaCount`，然後讓 HPA 負責根據負載自動調整，最高可至 `maxReplicaCount`，或降回 minReplicaCount。
    - **`idleReplicaCount`**
        當觸發器在設定的時間內沒有偵測到活動時，KEDA 會將 NodeSet 的副本數調整為 `idleReplicaCount`。更多範例請參考 KEDA 官方文件中關於 `idleReplicaCount` 的說明。
    - 官方解釋
        > When there is activity on the trigger (at least one pending job), KEDA will scale the NodeSet to `minReplicaCount` and then let HPA handle scaling up to `maxReplicaCount` or back down to `minReplicaCount`. When there is no activity on the trigger after a configurable amount of time, KEDA will scale the NodeSet to `idleReplicaCount`. See the [KEDA](https://keda.sh/docs/) documentation on [`idleReplicaCount`](https://keda.sh/docs/concepts/scaling-deployments/#idlereplicacount) for more examples.
        
        當觸發器上有活動（至少有一個等待中的作業）時，KEDA 會將 NodeSet 的副本數調整為 `minReplicaCount`，然後讓 HPA 負責根據負載自動調整，最高可至 `maxReplicaCount`，或降回 `minReplicaCount`。當觸發器在設定的時間內沒有偵測到活動時，KEDA 會將 NodeSet 的副本數調整為 `idleReplicaCount`。更多範例請參考 [KEDA](https://keda.sh/docs/) 官方文件中關於 [`idleReplicaCount`](https://keda.sh/docs/concepts/scaling-deployments/#idlereplicacount) 的說明。
        

- ### 確認 triggers 資訊
    > ```yaml
    > triggers:
    > - type: prometheus
    >   metricType: Value
    >   metadata:
    >     serverAddress: http://prometheus-kube-prometheus-prometheus.prometheus:9090
    >     query: slurm_partition_pending_jobs{partition="radar"}
    >     threshold: '5'
    > ```
    
    - ### KEDA 使用的 scale object 是 `prometheus`
    - ### 確認 prometheus service 是否能存取？
        - ### helm repo 已經有 prometheus ？
            ```
            $ helm repo list | grep -i prometheus
            prometheus-community	https://prometheus-community.github.io/helm-charts
            ```
        - ### prometheus 安裝在哪個 namespace？
            ```
            $ helm list -A | egrep -i "name|prometheus"
            NAME               	NAMESPACE            	REVISION	UPDATED                                	STATUS  	CHART                       	APP VERSION
            monitor            	monitor              	1       	2025-07-16 07:05:53.714709202 +0000 UTC	deployed	kube-prometheus-stack-70.7.0	v0.81.0
            ```
        - ### 查看 prometheus 服務
            ```
            $ kubectl -n monitor get svc
            NAME                                      TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)                      AGE
            alertmanager-operated                     ClusterIP   None             <none>        9093/TCP,9094/TCP,9094/UDP   19d
            monitor-grafana                           ClusterIP   10.108.0.168     <none>        80/TCP                       19d
            monitor-grafana-headless                  ClusterIP   None             <none>        9094/TCP                     19d
            monitor-kube-prometheus-st-alertmanager   ClusterIP   10.108.233.120   <none>        9093/TCP,8080/TCP            19d
            monitor-kube-prometheus-st-operator       ClusterIP   10.97.240.59     <none>        443/TCP                      19d
            monitor-kube-prometheus-st-prometheus     ClusterIP   10.101.246.225   <none>        9090/TCP,8080/TCP            19d
            monitor-kube-state-metrics                ClusterIP   10.102.45.71     <none>        8080/TCP                     19d
            monitor-prometheus-node-exporter          ClusterIP   10.96.132.130    <none>        9100/TCP                     19d
            prometheus-operated                       ClusterIP   None             <none>        9090/TCP                     19d
            ```
            - **service**
                - name: `monitor-kube-prometheus-st-prometheus`
                - port: 9090 or 8080
            - **DNS 格式**
                - **`<service>.<namespace>:<port>`**
                    `monitor-kube-prometheus-st-prometheus.monitor:9090`
                - **`<service>.<namespace>.svc:<port>`**
                    `monitor-kube-prometheus-st-prometheus.monitor.svc:9090`
                - **`<service>.<namespace>.svc.cluster.local:<port>`**
                    `monitor-kube-prometheus-st-prometheus.monitor.svc.cluster.local:9090`
            - **進到 `-n slurm` 的任意 pod，查看 `/etc/resolv.conf` 設定**
                ```
                $ cat /etc/resolv.conf 
                search slurm.svc.cluster.local svc.cluster.local cluster.local
                nameserver 10.96.0.10
                options ndots:5
                ```
                | domain-name | matched suffix | FQDN |
                |-------------|--------|------|
                | `monitor-kube-prometheus-st-prometheus.monitor` | `svc.cluster.local` | `monitor-kube-prometheus-st-prometheus.monitor.svc.cluster.local` |
                | `monitor-kube-prometheus-st-prometheus.monitor.svc` | `cluster.local` | `monitor-kube-prometheus-st-prometheus.monitor.svc.cluster.local` |
                | `monitor-kube-prometheus-st-prometheus.monitor.svc.cluster.local` | | `monitor-kube-prometheus-st-prometheus.monitor.svc.cluster.local` |
            - **確定 service 可以連線？**
                ```bash
                # 建立測試用的 pod
                $ kubectl -n slurm run -it --rm dnstools --image=infoblox/dnstools
                
                # 或：進入現有的 pod：
                $ kubectl -n slurm exec -it pod/dnstools -- sh
                
                ---
                
                # 進入到 pod
                $ nslookup monitor-kube-prometheus-st-prometheus.monitor
                
                $ curl "http://monitor-kube-prometheus-st-prometheus.monitor:9090" -i
                HTTP/1.1 302 Found
                Content-Type: text/html; charset=utf-8
                Location: /query
                Date: Tue, 05 Aug 2025 04:15:10 GMT
                Content-Length: 29

                <a href="/query">Found</a>.
                
                ---
                
                # 確認可連線後，可進一步進行查詢：
                # 1. 查詢 Prometheus 自己的時間戳
                $ curl "http://monitor-kube-prometheus-st-prometheus.monitor:9090/api/v1/query?query=time()"
                
                # 2. 查詢 Prometheus 內建的 up 指標
                $ curl "http://monitor-kube-prometheus-st-prometheus.monitor:9090/api/v1/query?query=up"
                # up 這個指標會顯示每個 target 是否處於「上線」（1=正常，0=異常）。
                
                # 3. 查詢某個 exporter 的 metrics 數量
                $ curl "http://monitor-kube-prometheus-st-prometheus.monitor:9090/api/v1/query?query=node_cpu_seconds_total"
                
                # 4. 查詢所有 metric 名稱
                $ curl "http://monitor-kube-prometheus-st-prometheus.monitor:9090/api/v1/label/__name__/values"

                ```
- ### 套用並確認
    ```bash
    $ kubectl -n slurm apply -f keda-slurm-compute-e900.yaml
    ```
    ```
    $ kubectl -n slurm get all
    ...
    NAME                                                      REFERENCE                    TARGETS       MINPODS   MAXPODS   REPLICAS   AGE
    horizontalpodautoscaler.autoscaling/keda-hpa-scale-e900   NodeSet/slurm-compute-e900   <unknown>/5   1         3         0          25h
    ```
    - TARGETS 是 `<unknown>`，應該表示還沒有上傳 metrics 到 Prometheus ?
    
    ```
    $ kubectl -n slurm get scaledobjects
    NAME         SCALETARGETKIND                     SCALETARGETNAME      MIN   MAX   READY   ACTIVE   FALLBACK   PAUSED    TRIGGERS     AUTHENTICATIONS   AGE
    scale-e900   slinky.slurm.net/v1alpha1.NodeSet   slurm-compute-e900   1     3     True    False    False      Unknown   prometheus                     25h
    ```

<br>

## 討論
### 解釋 HPA 和 VPA
- ### Question
    https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
    Horizontal Pod Autoscaling

    https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler/
    Vertical Pod Autoscaler

    用簡單的方式解釋
- ### gpt-4.1 (2025/08/05)
    當然可以！以下是**Horizontal Pod Autoscaler (HPA)** 和 **Vertical Pod Autoscaler (VPA)** 的簡單說明：

    ---

    ### Horizontal Pod Autoscaler (HPA)

    [官方文件說明連結](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/)

    #### 功能簡介

    * **HPA 會根據 CPU 使用率、記憶體用量，或其他自訂指標，自動調整 Pod 的數量。**
    * 當負載增加時，HPA 會自動擴充（增加）Pod；負載降低時則會縮減（減少）Pod。

    #### 適用場景

    * 當你的服務在高流量時需要更多實例分攤流量，低流量時節省資源。

    #### 流程簡述

    1. 設定 HPA，指定監控指標（例如 CPU 使用率）。
    2. Kubernetes controller 會持續監控這些指標。
    3. 如果指標超過或低於你設定的目標，Kubernetes 會自動調整 Pod 數量。

    ---

    ### Vertical Pod Autoscaler (VPA)

    [GitHub 連結](https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler/)

    #### 功能簡介

    * **VPA 會根據實際的資源使用情況，自動調整 Pod 的「CPU/記憶體配額」大小（不是數量）。**
    * 負載變大時自動分配更多資源給 Pod；負載小時減少分配，提升資源利用率。

    #### 適用場景

    * 當你的應用程式的資源需求會隨負載變動，但不想頻繁調整 Deployment 的資源設定時。

    #### 流程簡述

    1. 部署 VPA 組件並套用 VPA 資源設定。
    2. VPA 持續監控每個 Pod 的資源實際用量。
    3. 需要時會建議或自動修改 Pod 的資源限制，可能需要重啟 Pod 以套用新設定。

    ---

    ### 小結比較表

    |         | HPA                | VPA                           |
    | ------- | ------------------ | ----------------------------- |
    | 自動調整什麼？ | Pod 數量             | Pod 的資源（CPU/記憶體）              |
    | 用途      | 水平擴展（Scale out/in） | 垂直調整（Scale up/down）           |
    | 適合的場景   | 處理流量大起大落的服務        | 資源需求變動大、不想手動調整資源              |
    | 常見組合    | 可和 VPA 合併用，但有限制    | 可和 HPA 合併用，但 Pod 必須有最小/最大數量限制 |

    ---

    如需範例設定，或想知道兩者能否同時使用，可以再告訴我！

<br>

---

### 水平擴展（Scale out / Scale in），哪個數量是增加？哪個數量是減少？
- ### gpt-4.1 (2025/08/05)
    讓我用最簡單的方式說明：「**Scale out**」和「**Scale in**」這兩個詞的意思：

    ---

    ### 水平擴展（Scale out / Scale in）

    * **Scale out（擴出）**：**增加**資源的「數量」

      * 例如：增加更多 Pod、伺服器、主機（通常是同樣規格的機器）。
      * 在 Kubernetes HPA 裡，就是**Pod 數量變多**，來應付更大的流量或工作量。
      * 中文常說「橫向擴展」。

    * **Scale in（縮入）**：**減少**資源的「數量」

      * 例如：把多餘的 Pod、伺服器關閉或刪除。
      * 在 Kubernetes HPA 裡，就是**Pod 數量變少**，以節省資源。
      * 中文常說「橫向縮減」。

    ---

    ### 小口訣

    * **out = 增加數量**（數量往「外」擴散出去）
    * **in = 減少數量**（數量往「內」收縮）

    ---

    ### 圖像化舉例

    假設原本有 2 個 Pod：

    * **Scale out** 之後 → 4 個 Pod

      ```
      原本： PodA, PodB
      擴出： PodA, PodB, PodC, PodD
      ```
    * **Scale in** 之後 → 1 個 Pod

      ```
      原本： PodA, PodB
      縮入： PodA
      ```

    ---

    ### 補充

    * **Scale up / Scale down（垂直擴展/縮減）**：是指「**單一台機器（或 Pod）的資源變大/變小**」，比如把 1G RAM 增加到 2G。

    ---

    如果還不確定，可以告訴我你遇到的情境或是哪裡卡住，我可以用更生活化的例子解釋！


<br>

{%hackmd vaaMgNRPS4KGJDSFG0ZE0w %}