指標に基づいて Pod の自動スケーリングを最適化する


このチュートリアルでは、Cloud Monitoring から取得できる指標に基づいて Google Kubernetes Engine(GKE)ワークロードを自動的にスケーリングする方法を説明します。

このチュートリアルでは、次のいずれかの指標に基づいて自動スケーリングを設定します。

CPU

CPU 使用率

ノード間の CPU 使用率に基づいてスケーリングします。これにより、費用対効果が向上し、CPU リソースの使用効率を最大限に高めることができます。ただし、CPU 使用率は最後の指標であるため、スケールアップ中にレイテンシが発生する場合があります。

Pub/Sub

Pub/Sub バックログ

Pub/Sub サブスクリプションに残っている未確認のメッセージ数を報告する外部指標に基づいてスケーリングします。問題が発生する前にレイテンシを効果的に削減できますが、CPU 使用率に基づく自動スケーリングよりも多くのリソースが使用される可能性があります。

カスタム指標

Prometheus カスタム指標

Google Managed Prometheus を介して Prometheus 形式でエクスポートされたカスタム ユーザー定義指標に基づいてスケーリングします。Prometheus 指標のタイプは Gauge にする必要があります。

基本的に、自動スケーリングとは費用とレイテンシの許容可能なバランスを見つけるプロセスです。これらの指標と他の指標を組み合わせて試し、最適なポリシーを探してください。

目標

このチュートリアルでは、次のタスクについて説明します。

  1. カスタム指標アダプタをデプロイする方法。
  2. アプリケーション コードから指標をエクスポートする方法。
  3. Cloud Monitoring インターフェースに指標を表示する方法。
  4. Cloud Monitoring の指標に基づいてアプリケーションをスケーリングするために HorizontalPodAutoscaler(HPA)リソースをデプロイする方法。

費用

このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。 新しい Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

このドキュメントに記載されているタスクの完了後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。

始める前に

次の手順で Kubernetes Engine API を有効にします。
  1. Google Cloud コンソールの Kubernetes Engine ページにアクセスします。
  2. プロジェクトを作成または選択します。
  3. API と関連サービスが有効になるのを待ちます。 これには数分かかることがあります。
  4. Make sure that billing is enabled for your Google Cloud project.

このチュートリアルで使用する gcloudkubectl のコマンドライン ツールとともにプリインストールされる Cloud Shell を使用して、このチュートリアルを進めることができます。Cloud Shell を使用する場合は、これらのコマンドライン ツールをワークステーションにインストールする必要はありません。

Cloud Shell を使用するには:

  1. Google Cloud コンソールに移動します。
  2. Google Cloud コンソール ウィンドウの上部にある「Cloud Shell をアクティブにする」ボタン Shell をアクティブにするボタン をクリックします。

    Google Cloud コンソールの一番下にある新しいフレームの中で Cloud Shell セッションが開き、コマンドライン プロンプトが表示されます。

    Cloud Shell セッション

環境設定

  1. Google Cloud CLI のデフォルト ゾーンを設定します。

    gcloud config set compute/zone zone
    

    次のように置き換えます。

  2. 環境変数 PROJECT_IDPROJECT_NUMBERGoogle Cloud プロジェクト ID とプロジェクト番号に設定します。

    export PROJECT_ID=project-id
    export PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format 'get(projectNumber)')
    
  3. Google Cloud CLI のデフォルト ゾーンを設定します。

    gcloud config set project $PROJECT_ID
    
  4. GKE クラスタを作成する

    Google Cloud サービスにアクセスする際のセキュリティを強化するには、クラスタで GKE 用 Workload Identity 連携を有効にすることをおすすめします。このページでは、以前の方法(GKE 用 Workload Identity 連携は無効)を使用した例を示しますが、有効にすると保護が強化されます。

    Workload Identity

    GKE 用 Workload Identity 連携を有効にしてクラスタを作成するには、次のコマンドを実行します。

    gcloud container clusters create metrics-autoscaling --workload-pool=$PROJECT_ID.svc.id.goog
    

    以前の認証

    GKE 用 Workload Identity 連携を無効にしてクラスタを作成するには、次のコマンドを実行します。

    gcloud container clusters create metrics-autoscaling
    

カスタム指標アダプタのデプロイ

カスタム指標アダプタを使用すると、クラスタで Cloud Monitoring を使用して指標の送受信を行うことができます。

CPU

該当なし: 水平 Pod オートスケーラーは CPU 使用率に基づいてネイティブにスケーリングできるため、カスタム指標アダプタは必要ありません。

Pub/Sub

カスタム指標アダプタをインストールする手順は、GKE 用 Workload Identity 連携を有効にしているクラスタと有効にしていないクラスタで異なります。クラスタを作成する際に選択した設定に合うオプションを選択します。

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 Namespace の 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.svc.id.goog/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

カスタム指標

カスタム指標アダプタをインストールする手順は、GKE 用 Workload Identity 連携を有効にしているクラスタと有効にしていないクラスタで異なります。クラスタを作成する際に選択した設定に合うオプションを選択します。

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 Namespace の 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.svc.id.goog/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

指標を使用したアプリケーションのデプロイ

このチュートリアルのアプリケーション コードを含むリポジトリをダウンロードします。

CPU

git clone https://github.com/GoogleCloudPlatform/kubernetes-engine-samples.git
cd kubernetes-engine-samples/quickstarts/hello-app

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 に指標をエクスポートするコードが含まれています。

CPU

このアプリケーションは、ポート 8080 へのすべてのウェブ リクエストに対して「Hello、world!」というレスポンスを返します。Compute Engine の CPU 指標は Cloud Monitoring によって自動的に収集されます。

package main

import (
	"fmt"
	"log"
	"net/http"
	"os"
)

func main() {
	// register hello function to handle all requests
	mux := http.NewServeMux()
	mux.HandleFunc("/", hello)

	// use PORT environment variable, or default to 8080
	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
	}

	// start the web server on port and accept requests
	log.Printf("Server listening on port %s", port)
	log.Fatal(http.ListenAndServe(":"+port, mux))
}

// hello responds to the request with a plain-text "Hello, world" message.
func hello(w http.ResponseWriter, r *http.Request) {
	log.Printf("Serving request: %s", r.URL.Path)
	host, _ := os.Hostname()
	fmt.Fprintf(w, "Hello, world!\n")
	fmt.Fprintf(w, "Version: 1.0.0\n")
	fmt.Fprintf(w, "Hostname: %s\n", host)
}

Pub/Sub

このアプリケーションは、Pub/Sub サブスクリプションをポーリングし、新しいメッセージの着信を確認します。Pub/Sub サブスクリプションの指標は Cloud Monitoring によって自動的に収集されます。

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 マニフェストも含まれています。

CPU

apiVersion: apps/v1
kind: Deployment
metadata:
  name: helloweb
  labels:
    app: hello
spec:
  selector:
    matchLabels:
      app: hello
      tier: web
  template:
    metadata:
      labels:
        app: hello
        tier: web
    spec:
      containers:
      - name: hello-app
        image: us-docker.pkg.dev/google-samples/containers/gke/hello-app:1.0
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: 200m

Pub/Sub

マニフェストは、GKE 用 Workload Identity 連携を有効にしているクラスタと有効にしていないクラスタで異なります。クラスタを作成する際に選択した設定に合うオプションを選択します。

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

アプリケーションをクラスタにデプロイします。

CPU

kubectl apply -f manifests/helloweb-deployment.yaml

Pub/Sub

アプリケーションのデプロイ手順は、GKE 用 Workload Identity 連携が有効になっているクラスタと有効になっていない場合で異なります。クラスタを作成する際に選択した設定に合うオプションを選択します。

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.svc.id.goog/subject/ns/default/sa/pubsub-sa
    

以前の認証

  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.iam.gserviceaccount.com" \
      --role "roles/pubsub.subscriber"
    
  4. サービス アカウント キー ファイルをダウンロードします。

    gcloud iam service-accounts keys create key.json \
      --iam-account autoscaling-pubsub-sa@$PROJECT_ID.iam.gserviceaccount.com
    
  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 状態になります。

CPU

kubectl get pods

出力:

NAME                        READY   STATUS    RESTARTS   AGE
helloweb-7f7f7474fc-hzcdq   1/1     Running   0          10s

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. [有効なリソース] メニューで、[VM インスタンス] を選択します。
    3. [有効な指標カテゴリ] メニューで、[インスタンス] を選択します。
    4. [有効な指標] メニューで [CPU utilization] を選択し、[適用] をクリックします。
  3. 表示される時系列をフィルタするには、[フィルタ] 要素を使用します。

  4. 時系列を結合するには、[集計] 要素のメニューを使用します。たとえば、ゾーンに基づいて VM の CPU 使用率を表示するには、最初のメニューを [平均] に設定し、2 番目のメニューを [ゾーン] に設定します。

    [集計] 要素の最初のメニューが [未集計] になっている場合は、すべての時系列が表示されます。[集計] 要素のデフォルトは、選択した指標タイプによって決まります。

リソースタイプと指標は次のとおりです。

CPU

Metrics Explorer

Resource type: gce_instance

Metric: compute.googleapis.com/instance/cpu/utilization

Pub/Sub

Metrics Explorer

Resource type: pubsub_subscription

Metric: pubsub.googleapis.com/subscription/num_undelivered_messages

カスタム指標

Metrics Explorer

Resource type: prometheus_target

Metric: prometheus.googleapis.com/custom_prometheus/gauge

HorizontalPodAutoscaler オブジェクトの作成

Cloud Monitoring に指標が表示されたら、HorizontalPodAutoscaler をデプロイして、指標に基づいて Deployment のサイズを変更できます。

CPU

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: cpu
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: helloweb
  minReplicas: 1
  maxReplicas: 5
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 30

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 をクラスタにデプロイします。

CPU

kubectl apply -f manifests/helloweb-hpa.yaml

Pub/Sub

kubectl apply -f deployment/pubsub-hpa.yaml

カスタム指標

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

負荷の生成

指標によっては、自動スケーリングを監視するために負荷の生成が必要になることがあります。

CPU

helloweb サーバーに対して 10,000 件のリクエストをシミュレートします。

 kubectl exec -it deployments/helloweb -- /bin/sh -c \
     "for i in $(seq -s' ' 1 10000); do wget -q -O- localhost:8080; done"

Pub/Sub

Pub/Sub トピックに 200 件のメッセージを公開します。

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

カスタム指標

なし: このサンプルで使用されているコードは、カスタム指標の定数値 40 をエクスポートします。HorizontalPodAutoscaler が 20 のターゲット値で設定されているため、Deployment が自動的にスケールアップされます。

HorizontalPodAutoscaler のスケールアップの監視

Deployment の現在のレプリカの数を確認するには、次のコマンドを実行します。

kubectl get deployments

指標が反映されるまでしばらく待ってから、Deployment は 5 つの Pod を作成してバックログを処理します。

また、次のコマンドを実行することで、HorizontalPodAutoscaler の状態と最近のアクティビティを調べることもできます。

kubectl describe hpa

クリーンアップ

このチュートリアルで使用したリソースについて、Google Cloud アカウントに課金されないようにするには、リソースを含むプロジェクトを削除するか、プロジェクトを維持して個々のリソースを削除します。

CPU

GKE クラスタを削除します。

 gcloud container clusters delete metrics-autoscaling

Pub/Sub

  1. Pub/Sub サブスクリプションとトピックをクリーンアップします。

    gcloud pubsub subscriptions delete echo-read
    gcloud pubsub topics delete echo
    
  2. GKE クラスタを削除します。

    gcloud container clusters delete metrics-autoscaling
    

カスタム指標

GKE クラスタを削除します。

 gcloud container clusters delete metrics-autoscaling

次のステップ