Keda 101

說明 KEDA ScaledObject 與 HPA 的分工、scale to 0 的條件,並以 cron trigger 範例示範設定與暫停方式。

發佈 ~2 分鐘 #K8s#keda

Basic Arch

KEDA 架構圖

圖:KEDA 架構圖(來源:KEDA 官方文件,KEDA 專案文件採 Apache-2.0 授權)

核心概念:

  1. ScaledObject 是 event 和 HPA 的介面,讓我們能透過 event 來去操控 HPA,達到 scaling 的效果

  2. 概念上分為兩個階段

    1. Activation Phase:由 Keda operator 負責 0 ↔ 1 scaling
    2. Scaling phase:由 HPA 負責 1 ↔ N scaling

    會這樣切分是因為 HPA 本身不支援 minReplicaCount = 0

  3. Applying Order:基於現狀選最大

    • 在一個 ScaledObject 裡面,所有的 triggers 都會被轉成 HPA 的 metrics(ie, ScaledObject 裡面有五個 triggers,那他長出來的 HPA 就會有五個 metrics)
    • HPA 會對每個指標各自算出期望副本數,最後取「最大值」作為本輪期望副本數;若有任一指標無法取到數值而其他指標建議縮容,會跳過縮容
    • Horizontal Pod Autoscaling

其他補充概念:

  1. Event 會可以從 workload、也可以從外部來(像是 SQS queue length)

  2. Polling Interval

    • Keda 在 Activation Phase 會根據 ScaledObject 裡面的 triggers 做 polling (間隔 based on pollingInterval)
    • HPA 也會在 Scaling Phase 基於 kube-controller-manager 的 --horizontal-pod-autoscaler-sync-period 來對 metrics 做 polling,預設是 15s
  3. 使用 Keda 要怎麼 scale 到 0?

    根據第四點的邏輯,如果要 scale 到 0,必須要讓現狀滿足以下兩個條件

    1. 現狀不符合任何 trigger → 若現狀有符合任一個 trigger 條件,KEDA 會把目標 workload 的 replicas 從 0 喚醒到 ≥1,然後交給 HPA 去處理 desired 數量
    2. minReplicaCount 或 idleReplicaCount 必須設置為 0

    → 接著 Keda 會 disable HPA,並且直接把 Deployment replica 設置為 0

    → 基本上寫 ScaledObject triggers 要以 scale up 的角度來寫,所有條件都不符合才會 scale down

  4. Difference between minReplicaCount & idleReplicaCount

    • minReplicaCount:在 Scaling Phase(有任何 trigger 被觸發時)最小的 replicaCount
    • idleReplicaCount:在 Activation Phase(沒有觸發任何 trigger 時)時的 replicaCount
[Start: KEDA ScaledObject]
   │
   ▼
(1) KEDA 輪詢每個 trigger (pollingInterval)
   ├─ Trigger A → active 嗎?
   ├─ Trigger B → active 嗎?
   └─ Trigger C → active 嗎?
   │
   ▼
(2) 判斷「是否有任何一個 trigger active?」
   ├─ 是 → 進入「活動模式 Scaling Phase」
   │       │
   │       ├─ 如果目前 replicas = 0 → KEDA 直接把目標 workload 設成 ≥1
   │       └─ 將所有 triggers 轉換成 HPA 指標 (external metrics)
   │       └─ HPA 接管:
   │             ├─ 計算每個指標的期望 replicas,取最大值
   │             └─ 若計算結果 < minReplicaCount → 強制維持在 minReplicaCount
   │
   └─ 否 → 進入「非活動模式 Activation Phase」
   │       │
   │       └─ 有設定 idleReplicaCount ?
   │               ├─ 是 → replicas = idleReplicaCount
   │               └─ 否 → replicas = minReplicaCount
   │                         (如果 =0,就縮到 0)
   │
   ▼
(3) 重複下一輪 pollingInterval / HPA syncPeriod

Cron Trigger

apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
  name: gitlab-runner-arm-1
  namespace: gitlab-runner
spec:
  cooldownPeriod: 10
  idleReplicaCount: 0
  initialCooldownPeriod: 0
  maxReplicaCount: 4
  minReplicaCount: 0
  pollingInterval: 30
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: arm-gitlab-runner-gitlab-runner
  triggers:
    - type: cron
	    metadata:
        desiredReplicas: "1"  # 如果現況大於 1 且符合 trigger 條件,則不會改變數量
        end: 0 18 * * mon-fri
        start: 0 10 * * mon-fri
        timezone: Asia/Taipei

效果:週一到週五的 10:00 - 18:00,HPA 會確保我們的 replica ≥ 1。超過這些時間段以外,Keda 會確保我們的 replica = 0

但是他會直接去把 deployment replica count 改成 0,就算我們手動改成 1 還是會被 keda 改回去。解決方法為,暫時讓 keda 的 ScaledObject 停止作用,方法如下:

# ScaledObject 停止作用
kubectl annotate scaledobject gitlab-runner-arm-1 autoscaling.keda.sh/paused=true -n gitlab-runner --overwrite

# 加班完之後
# ScaledObject 開始作用
kubectl annotate scaledobject gitlab-runner-arm-1 autoscaling.keda.sh/paused=false -n gitlab-runner --overwrite

Reference