
通常、KubernetesのデプロイはCPUやメモリ使用量などを基準にスケールさせますが、外部指標を使ってスケールさせたい場面もあります。本記事では、任意のStackdriver指標を使ってHorizontal Pod Autoscaler (HPA) による自動スケーリングを構成する手順を解説します。題材として、Google Cloud HTTP/SロードバランサーのRequest Per Second (RPS) を使用します。

Stackdriver指標を使ったKubernetes Horizontal Pod Autoscalerの自動スケーリング
さっそく始めよう
まずは、新しいGoogle Kubernetes Engine (GKE) クラスターを作成します。
gcloud beta container clusters create "hpa-with-stackdriver-metrics" --zone "us-central1-a" \--username "admin" \--cluster-version "1.10.7-gke.6" \--machine-type "n1-standard-1" \--image-type "COS" \--disk-type "pd-standard" \--disk-size "100" --scopes \ "https://www.googleapis.com/auth/devstorage.read_only","https://www.googleapis.com/auth/logging.write","https://www.googleapis.com/auth/monitoring","https://www.googleapis.com/auth/servicecontrol","https://www.googleapis.com/auth/service.management.readonly","https://www.googleapis.com/auth/trace.append"--num-nodes "3" \--enable-cloud-logging \--enable-cloud-monitoring \--addons HorizontalPodAutoscaling,HttpLoadBalancing \--enable-autoupgrade --enable-autorepairポイントは `enable-cloud-monitoring` です。これによってStackdriver Monitoringの指標を読み取れるようになります。
Custom Metrics Stackdriver Adapterのデプロイ
カスタム指標アダプターは、Stackdriverの指標をKubernetes APIに取り込む役割を担います。これによってHPAがこれらの指標を参照し、それに応じた動作ができるようになります。詳細は後述のトラブルシューティングのセクションをご覧ください。
GKEオブジェクトからStackdriverに保存された指標へアクセスできるようにするには、クラスターに Custom Metrics Stackdriver Adapter をデプロイする必要があります。
Custom Metrics Adapterを動かすには、まず以下のコマンドを実行し、必要な認可ロールを作成できる権限をユーザーに付与してください。
kubectl create clusterrolebinding cluster-admin-binding \--clusterrole cluster-admin \--user "$(gcloud config get-value account)"続いて、Stackdriverから指標を読み取るためのアダプター本体をデプロイします。
kubectl create -f https://raw.githubusercontent.com/GoogleCloudPlatform/k8s-stackdriver/master/custom-metrics-stackdriver-adapter/deploy/production/adapter.yamlDeploymentを作成する
次に、シンプルなnginxアプリケーションをデプロイし、後ほどHTTP/Sロードバランサーで計測したRPSに応じてスケールさせます。
以下のファイルを作成してください: deployment.yaml
apiVersion: apps/v1kind: Deploymentmetadata: name: nginxspec: selector: matchLabels: app: nginx replicas: 1 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.8 ports: - containerPort: 80---apiVersion: v1kind: Servicemetadata: name: nginx labels: app: nginxspec: type: NodePort ports: - port: 80 protocol: TCP selector: app: nginxそしてデプロイします。
kubectl apply -f deployment.yamlLoadBalancer Ingressを作成する
Ingressファイルを作成します: ingress.yaml
apiVersion: extensions/v1beta1kind: Ingressmetadata: name: basic-ingressspec: backend: serviceName: nginx servicePort: 80Ingressを適用します。
kubectl apply -f ingress.yamlHorizontalPodAutoscalerオブジェクトを作成する
ここが本記事の肝です。
外部指標 (external metric)* を使用し、metricName には以下を指定します。
loadbalancing.googleapis.com|https|補足: Stackdriver指標の一覧は こちら で確認できます。 Metrics Explorer を使うのも便利です。
さらに、対象のロードバランサーの指標だけに絞り込むため、metricSelectorも指定します。
LBのforwarding ruleを確認してみましょう。
$ kubectl describe ingress basic-ingressName: basic-ingressNamespace: defaultAddress: 35.190.3.165Default backend: nginx:80 (10.48.2.11:80)Rules: Host Path Backends ---- ---- -------- * * nginx:80 (10.48.2.11:80)Annotations: backends: {"k8s-be-32432--ffd629d77b6630de":"HEALTHY"} forwarding-rule: k8s-fw-default-basic-ingress--ffd629d77b6630de target-proxy: k8s-tp-default-basic-ingress--ffd629d77b6630de url-map: k8s-um-default-basic-ingress--ffd629d77b6630deこれで、設定にラベルマッチを追加できます (ラベル「forwarding_rule_name」に注目)。
metricSelector: matchLabels: resource.labels.forwarding_rule_name: k8s-fw-default-basic-ingress--ffd629d77b6630de最終的なファイルは次のようになります: hpa.yaml
apiVersion: autoscaling/v2beta1kind: HorizontalPodAutoscalermetadata: name: nginxspec: minReplicas: 1 maxReplicas: 5 metrics: - external: metricName: loadbalancing.googleapis.com|https|request_count metricSelector: matchLabels: resource.labels.forwarding_rule_name: k8s-fw-default-basic-ingress--ffd629d77b6630de targetAverageValue: "1" type: External scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nginxここでtargetAverageValueを使っている点に注目してください。これは1つのレプリカが処理できる指標値の総量を指定するもので、レプリカ間で分担できる作業やリソースを表す指標を扱うときに役立ちます。今回のケースでは、各レプリカが1 RPSを処理する想定です。実運用では、ご自身の要件に合わせて調整してください。
動作確認
まずはロードバランサーへトラフィックを流していきます。
先ほどのコマンドの結果から:
kubectl describe ingress basic-ingressIngressのパブリックIPアドレスは 35.190.3.165 です。
では、このエンドポイントにリクエストを送り続けてみましょう 🥊
while true ; do curl -Ss -k --write-out '%{http_code}\n' --output /dev/null http://35.190.3.165/ ; doneHorizontalPodAutoscalerに変化があるか確認します。
kubectl describe hpa nginx-hpaこの時点では指標がまだ収集されていないため警告が表示されることがありますが、数分後にはMetricsセクションに値が入っているはずです。
Name: nginx-hpaNamespace: defaultLabels: <none>Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"autoscaling/v2beta1","kind":"HorizontalPodAutoscaler","metadata":{"annotations":{},"name":"nginx-hpa","namespace":"default"},"spec":{"ma...CreationTimestamp: Wed, 31 Oct 2018 18:18:28 +0200Reference: Deployment/nginxMetrics: ( current / target )"loadbalancing.googleapis.com|https|request_count" (target average value): 1034m / 1Min replicas: 1Max replicas: 5そして「Events」セクションには次のように表示されます。
Events:Type Reason Age From Message...Normal SuccessfulRescale 2m horizontal-pod-autoscaler New size: 2; reason: external metric loadbalancing.googleapis.com|https|request_count(&LabelSelector{MatchLabels:map[string]string{resource.labels.forwarding_rule_name: k8s-fw-default-basic-ingress--ffd629d77b6630de,},MatchExpressions:[],}) above target無事に発射成功です! 🚀
トラブルシューティング
- 指標がKubernetesのexternal metrics APIに正しく取り込まれているかを確認する手軽な方法は、APIを直接たどってみることです。metricSelectorが正しく機能しているかの確認にも使えます。
まず、kubernetes proxyを起動します。
kubectl proxy --port=8080続いて、ローカルホストからアクセスします。
http://localhost:8080/apis/external.metrics.k8s.io/v1beta1/namespaces/default/loadbalancing.googleapis.com%7Chttps%7Crequest_count結果の抜粋は以下のとおりです。
{ "kind": "ExternalMetricValueList", "apiVersion": "external.metrics.k8s.io/v1beta1", "metadata": { "selfLink": "/apis/external.metrics.k8s.io/v1beta1/namespaces/default/loadbalancing.googleapis.com%7Chttps%7Crequest_count" }, "items": [\ {\ "metricName": "loadbalancing.googleapis.com|https|request_count",\ "metricLabels": {\ "metric.labels.cache_result": "DISABLED",\ "resource.labels.backend_target_type": "BACKEND_SERVICE",\ "resource.labels.backend_name": "k8s-ig--ffd629d77b6630de",\ ...\ "resource.labels.forwarding_rule_name": "k8s-fw-default-basic-ingress--ffd629d77b6630de",\ ...\ },\ "timestamp": "2018-11-01T08:41:30Z",\ "value": "2433m"\ }\ ]}うまくいきました!
2. アダプターの挙動を確認するもう1つの方法は、ログを見ることです。まずはcustom-metricsのPodを一覧表示します。
$ kubectl get pods -n custom-metricsNAME READYcustom-metrics-stackdriver-adapter-c4d98dc54-2n4jz 1/1続いて、ログを追跡します。
$ kubectl logs custom-metrics-stackdriver-adapter-c4d98dc54-2n4jz -n custom-metrics...I1104 06:42:11.125627 1 trace.go:76] Trace[1192308782]: "List /apis/external.metrics.k8s.io/v1beta1/namespaces/default/loadbalancing.googleapis.com|https|request_count" (started: 2018-11-04 06:42:08.155209905 +0000 UTC m=+311951.293335726) (total time: 2.970372027s):Trace[1192308782]: [2.97027864s] [2.970185564s] Listing from storage done...これらのログ、特にエラーメッセージからは多くの有益な情報が得られます。
まとめ
Stackdriverに収集・保存された外部指標の活用は、とてもシンプルで扱いやすい仕組みです。同じ要領で、Monitoring API経由でStackdriverに送信した独自のカスタム指標も利用できます。
本記事で使用したリソースは、こちらのGitHubリポジトリにまとめてあります。
他の記事も読みたい方は、ぜひブログをご覧いただくか、EranをTwitterでフォローしてください。