根據指標最佳化 Pod 自動調度資源

本教學課程示範如何依據 Cloud Monitoring 提供的指標,自動調整 Google Kubernetes Engine (GKE) 工作負載的資源配置。

在本教學課程中,您可以根據下列其中一項指標設定自動調度:

Pub/Sub

Pub/Sub 待處理事項

根據外部指標調整規模,該指標會回報Pub/Sub 訂閱項目中剩餘的未確認訊息數。這項功能可有效減少延遲,避免延遲成為問題,但與根據 CPU 使用率自動調度資源相比,可能會使用相對較多的資源。

自訂指標

自訂 Prometheus 指標

根據自訂使用者定義指標進行擴縮,並透過 Google 代管的 Prometheus 以 Prometheus 格式匯出。Prometheus 指標必須為「Gauge」類型。

自動調度資源的根本目標,是在成本和延遲時間之間取得可接受的平衡。建議您嘗試結合這些指標和其他指標,找出適合自己的政策。

部署自訂指標轉接器

自訂指標介面卡可讓叢集與 Cloud Monitoring 傳送及接收指標。

Pub/Sub

安裝 Custom Metrics Adapter 的程序會因叢集是否啟用 GKE 適用的工作負載身分聯盟而異。選取與建立叢集時所選設定相符的選項。

Workload Identity

授予使用者權限,使其能夠建立必要的授權角色:

kubectl create clusterrolebinding cluster-admin-binding \
    --clusterrole cluster-admin --user "$(gcloud config get-value account)"

在叢集上部署自訂指標轉接器:

kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml

轉接器會使用 custom-metrics 命名空間中的 custom-metrics-stackdriver-adapter Kubernetes 服務帳戶。指派「監控檢視者」角色,允許這個服務帳戶讀取 Cloud Monitoring 指標:

gcloud projects add-iam-policy-binding projects/$PROJECT_ID \
  --role roles/monitoring.viewer \
  --member=principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$PROJECT_ID./subject/ns/custom-metrics/sa/custom-metrics-stackdriver-adapter

舊版驗證

授予使用者權限,使其能夠建立必要的授權角色:

kubectl create clusterrolebinding cluster-admin-binding \
    --clusterrole cluster-admin --user "$(gcloud config get-value account)"

在叢集上部署自訂指標轉接器:

kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml

自訂指標

安裝 Custom Metrics Adapter 的程序會因叢集是否啟用 GKE 適用的工作負載身分聯盟而異。選取與建立叢集時所選設定相符的選項。

Workload Identity

授予使用者權限,使其能夠建立必要的授權角色:

kubectl create clusterrolebinding cluster-admin-binding \
    --clusterrole cluster-admin --user "$(gcloud config get-value account)"

在叢集上部署自訂指標轉接器:

kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml

轉接器會使用 custom-metrics 命名空間中的 custom-metrics-stackdriver-adapter Kubernetes 服務帳戶。指派「監控檢視者」角色,允許這個服務帳戶讀取 Cloud Monitoring 指標:

gcloud projects add-iam-policy-binding projects/$PROJECT_ID \
  --role roles/monitoring.viewer \
  --member=principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$PROJECT_ID./subject/ns/custom-metrics/sa/custom-metrics-stackdriver-adapter

舊版驗證

授予使用者權限,使其能夠建立必要的授權角色:

kubectl create clusterrolebinding cluster-admin-binding \
    --clusterrole cluster-admin --user "$(gcloud config get-value account)"

在叢集上部署自訂指標轉接器:

kubectl apply -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter_new_resource_model.yaml

部署含有指標的應用程式

下載內含本教學課程應用程式程式碼的存放區:

Pub/Sub

git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git
cd kubernetes-engine-samples/databases/cloud-pubsub

自訂指標

git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git
cd kubernetes-engine-samples/observability/custom-metrics-autoscaling/google-managed-prometheus

存放區包含將指標匯出至 Cloud Monitoring 的程式碼:

Pub/Sub

這個應用程式會輪詢 Pub/Sub 訂閱項目的新訊息,並在收到訊息時確認。Cloud Monitoring 會自動收集 Pub/Sub 訂閱指標。

from google import auth
from google.cloud import pubsub_v1


def main():
    """Continuously pull messages from subsciption"""

    # read default project ID
    _, project_id = auth.default()
    subscription_id = 'echo-read'

    subscriber = pubsub_v1.SubscriberClient()
    subscription_path = subscriber.subscription_path(
        project_id, subscription_id)

    def callback(message: pubsub_v1.subscriber.message.Message) -> None:
        """Process received message"""
        print(f"Received message: ID={message.message_id} Data={message.data}")
        print(f"[{datetime.datetime.now()}] Processing: {message.message_id}")
        time.sleep(3)
        print(f"[{datetime.datetime.now()}] Processed: {message.message_id}")
        message.ack()

    streaming_pull_future = subscriber.subscribe(
        subscription_path, callback=callback)
    print(f"Pulling messages from {subscription_path}...")

    with subscriber:
        try:
            streaming_pull_future.result()
        except Exception as e:
            print(e)

自訂指標

這個應用程式會使用 Prometheus 格式,透過常數值指標回應 /metrics 路徑的任何網頁要求。

metric := prometheus.NewGauge(
	prometheus.GaugeOpts{
		Name: *metricName,
		Help: "Custom metric",
	},
)
prometheus.MustRegister(metric)
metric.Set(float64(*metricValue))

http.Handle("/metrics", promhttp.Handler())
log.Printf("Starting to listen on :%d", *port)
err := http.ListenAndServe(fmt.Sprintf(":%d", *port), nil)

這個存放區也包含 Kubernetes 資訊清單,可將應用程式部署到叢集。Deployment 是 Kubernetes API 物件,可讓您執行多個 Pod 副本,並將這些副本分散到叢集中的節點:

Pub/Sub

如果叢集啟用 Workload Identity Federation for GKE,資訊清單會有所不同。選取與建立叢集時所選設定相符的選項。

Workload Identity

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pubsub
spec:
  selector:
    matchLabels:
      app: pubsub
  template:
    metadata:
      labels:
        app: pubsub
    spec:
      serviceAccountName: pubsub-sa
      containers:
      - name: subscriber
        image: us-docker.pkg.dev/google-samples/containers/gke/pubsub-sample:v2

舊版驗證

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pubsub
spec:
  selector:
    matchLabels:
      app: pubsub
  template:
    metadata:
      labels:
        app: pubsub
    spec:
      volumes:
      - name: google-cloud-key
        secret:
          secretName: pubsub-key
      containers:
      - name: subscriber
        image: us-docker.pkg.dev/google-samples/containers/gke/pubsub-sample:v2
        volumeMounts:
        - name: google-cloud-key
          mountPath: /var/secrets/google
        env:
        - name: GOOGLE_APPLICATION_CREDENTIALS
          value: /var/secrets/google/key.json

自訂指標

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: custom-metrics-gmp
  name: custom-metrics-gmp
  namespace: default
spec:
  replicas: 1
  selector:
    matchLabels:
      run: custom-metrics-gmp
  template:
    metadata:
      labels:
        run: custom-metrics-gmp
    spec:
      containers:
      # sample container generating custom metrics
      - name: prometheus-dummy-exporter
        image: us-docker.pkg.dev/google-samples/containers/gke/prometheus-dummy-exporter:v0.2.0
        command: ["./prometheus-dummy-exporter"]
        args:
        - --metric-name=custom_prometheus
        - --metric-value=40
        - --port=8080

透過 PodMonitoring 資源,Google Cloud Managed Service for Prometheus 會將 Prometheus 指標匯出至 Cloud Monitoring:

apiVersion: monitoring.googleapis.com/v1
kind: PodMonitoring
metadata:
  name: "custom-metrics-exporter"
spec:
  selector:
    matchLabels:
      run: custom-metrics-gmp
  endpoints:
  - port: 8080
    path: /metrics
    interval: 15s

從 GKE Standard 1.27 版或 GKE Autopilot 1.25 版開始,Google Cloud Managed Service for Prometheus 會啟用。如要在舊版叢集中啟用 Google Cloud Managed Service for Prometheus,請參閱「啟用代管收集作業」。

將應用程式部署至叢集:

Pub/Sub

如果叢集已啟用 Workload Identity Federation for GKE,應用程式部署程序會有所不同。選取與建立叢集時所選設定相符的選項。

Workload Identity

  1. 在專案中啟用 Pub/Sub API:

    gcloud services enable cloudresourcemanager.googleapis.com pubsub.googleapis.com
    
  2. 建立 Pub/Sub 主題和訂閱項目:

    gcloud pubsub topics create echo
    gcloud pubsub subscriptions create echo-read --topic=echo
    
  3. 將應用程式部署至叢集:

    kubectl apply -f deployment/pubsub-with-workload-identity.yaml
    
  4. 這個應用程式定義了 pubsub-sa Kubernetes 服務帳戶。指派「Pub/Sub 訂閱者」角色給該服務帳戶,讓應用程式可以將訊息發布至 Pub/Sub 主題。

    gcloud projects add-iam-policy-binding projects/$PROJECT_ID \
      --role=roles/pubsub.subscriber \
      --member=principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/$PROJECT_ID./subject/ns/default/sa/pubsub-sa
    

    上述指令會使用主體 ID,讓 IAM 直接參照 Kubernetes 服務帳戶。

    最佳做法

    使用主體 ID,但請注意替代方法說明中的限制。

舊版驗證

  1. 在專案中啟用 Pub/Sub API:

    gcloud services enable cloudresourcemanager.googleapis.com pubsub.googleapis.com
    
  2. 建立 Pub/Sub 主題和訂閱項目:

    gcloud pubsub topics create echo
    gcloud pubsub subscriptions create echo-read --topic=echo
    
  3. 建立可存取 Pub/Sub 的服務帳戶:

    gcloud iam service-accounts create autoscaling-pubsub-sa
    gcloud projects add-iam-policy-binding $PROJECT_ID \
      --member "serviceAccount:autoscaling-pubsub-sa@$PROJECT_ID." \
      --role "roles/pubsub.subscriber"
    
  4. 下載服務帳戶金鑰檔案:

    gcloud iam service-accounts keys create key.json \
      --iam-account autoscaling-pubsub-sa@$PROJECT_ID.
    
  5. 將服務帳戶金鑰匯入叢集做為 Secret

    kubectl create secret generic pubsub-key --from-file=key.json=./key.json
    
  6. 將應用程式部署至叢集:

    kubectl apply -f deployment/pubsub-with-secret.yaml
    

自訂指標

kubectl apply -f custom-metrics-gmp.yaml

稍待片刻,應用程式部署完成後,所有 Pod 都會達到 Ready 狀態:

Pub/Sub

kubectl get pods

輸出:

NAME                     READY   STATUS    RESTARTS   AGE
pubsub-8cd995d7c-bdhqz   1/1     Running   0          58s

自訂指標

kubectl get pods

輸出:

NAME                                  READY   STATUS    RESTARTS   AGE
custom-metrics-gmp-865dffdff9-x2cg9   1/1     Running   0          49s

在 Cloud Monitoring 中查看指標

應用程式執行時,會將指標寫入 Cloud Monitoring。

如要使用 Metrics Explorer 查看受監控資源的指標,請按照下列步驟操作:

  1. 前往 Google Cloud 控制台的 「Metrics Explorer」頁面:

    前往 Metrics Explorer

    如果您是使用搜尋列尋找這個頁面,請選取子標題為「Monitoring」的結果

  2. 在「指標」元素中,展開「選取指標」選單,然後選取資源類型和指標類型。舉例來說,如要繪製虛擬機器的 CPU 使用率圖表,請按照下列步驟操作:
    1. (選用) 如要減少選單選項,請在「篩選器」列中輸入部分指標名稱。在本例中,請輸入 utilization
    2. 在「Active resources」(有效資源) 選單中,選取「VM instance」(VM 執行個體)
    3. 在「使用中的指標類別」選單中,選取「執行個體」
    4. 在「有效指標」選單中,選取「CPU 使用率」,然後按一下「套用」
  3. 如要篩選顯示的時間序列,請使用篩選元素

  4. 如要合併時間序列,請使用「Aggregation」(匯總) 元素上的選單。舉例來說,如要依據 VM 的所在區域顯示 CPU 使用率,請將第一個選單設為「平均值」,第二個選單設為「區域」

    如果將「Aggregation」(匯總) 元素的第一個選單設為「Unaggregated」(未匯總),系統就會顯示所有時間序列。「匯總」元素的預設設定取決於您選取的指標類型。

資源類型和指標如下:

Pub/Sub

Metrics Explorer

資源類型:pubsub_subscription

指標:pubsub.googleapis.com/subscription/num_undelivered_messages

自訂指標

Metrics Explorer

資源類型:prometheus_target

指標:prometheus.googleapis.com/custom_prometheus/gauge

視指標而定,您可能還不會在 Cloud Monitoring Metrics Explorer 中看到太多活動。如果指標沒有更新,請別感到意外。

建立 HorizontalPodAutoscaler 物件

在 Cloud Monitoring 中看到指標後,您可以部署 HorizontalPodAutoscaler,根據指標調整部署大小。

Pub/Sub

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: pubsub
spec:
  minReplicas: 1
  maxReplicas: 5
  metrics:
  - external:
      metric:
       name: pubsub.googleapis.com|subscription|num_undelivered_messages
       selector:
         matchLabels:
           resource.labels.subscription_id: echo-read
      target:
        type: AverageValue
        averageValue: 2
    type: External
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: pubsub

自訂指標

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: custom-metrics-gmp-hpa
  namespace: default
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: custom-metrics-gmp
  minReplicas: 1
  maxReplicas: 5
  metrics:
  - type: Pods
    pods:
      metric:
        name: prometheus.googleapis.com|custom_prometheus|gauge
      target:
        type: AverageValue
        averageValue: 20

HorizontalPodAutoscaler 部署至叢集:

Pub/Sub

kubectl apply -f deployment/pubsub-hpa.yaml

自訂指標

kubectl apply -f custom-metrics-gmp-hpa.yaml

產生負載

對於部分指標,您可能需要產生負載,才能觀察自動調度資源功能:

Pub/Sub

將 200 則訊息發布至 Pub/Sub 主題:

for i in {1..200}; do gcloud pubsub topics publish echo --message="Autoscaling #${i}"; done

自訂指標

不適用:本範例使用的程式碼會為自訂指標匯出 40 的常數值。HorizontalPodAutoscaler 設定的目標值為 20,因此會嘗試自動調度部署資源。

您可能需要稍候幾分鐘,HorizontalPodAutoscaler 才會回應指標變更。

觀察 HorizontalPodAutoscaler 擴充

您可以執行下列指令,檢查部署目前的備用資源數:

kubectl get deployments

指標傳播一段時間後,Deployment 會建立五個 Pod 來處理待處理事項。

您也可以執行下列指令,檢查 HorizontalPodAutoscaler 的狀態和最近的活動:

kubectl describe hpa