JavaアプリケーションのAPIへのリクエスト数が急増した場合は、Horizontal Pod Autoscaler (HPA) を設定して、APIの1秒あたりのクエリ (QPS) に基づいてアプリケーションを自動的にスケーリングできます。 このトピックでは、application Real-Time monitoring service (ARMS) のアプリケーションパフォーマンス管理 (APM) サービスを使用して収集されたモニタリングデータに基づいて、アプリケーションを自動的にスケーリングするようにHPAを設定する方法について説明します。
制御ポリシー機能の動作
Container Service for Kubernetes (ACK) クラスターでJavaアプリケーションのARMS APMを有効にすると、アプリケーションのAPIリクエストに関する詳細情報を表示できます。 JavaアプリケーションでARMS APMを有効にする方法の詳細については、「アプリケーションの監視」をご参照ください。 ARMS APMは、収集したデータをPrometheusのManaged Service for Prometheus (Prometheus) がサポートするメトリックに変換します。 次に、alibaba-cloud-metrics-adapterコンポーネントは、PrometheusメトリクスをHPAでサポートされているメトリクスに変換します。 このように、HPAは、収集されたメトリックに基づいてアプリケーションをスケーリングすることができる。
この例では、arms-springboot-demoという名前のアプリケーションが作成されます。 ストレステストは、アプリケーションによって公開される /demo/queryUser/10 APIで実行されます。
前提条件
Prometheusコンポーネントがインストールされています。 詳細については、「Prometheusのマネージドサービス」トピックの手順1: Prometheusのマネージドサービスの有効化を参照してください。
kube-system名前空間にalibaba-cloud-metrics-adapterがインストールされています。 詳細については、「alibaba cloudメトリクスに基づく水平自動スケーリングの実装」トピックの「Alibaba-Cloud-metrics-adapterのデプロイ」セクションをご参照ください。
名前空間が作成されます。 詳細については、「名前空間とリソースクォータの管理」をご参照ください。 この例では、arms-demo名前空間が作成されています。
Java Development Kit (JDK) がインストールされています。 ARMS APMでサポートされているJDKバージョンの詳細については、「ARMSでサポートされているJavaコンポーネントとフレームワーク」をご参照ください。
手順
手順1: ARMS APMコンポーネントのインストール
アプリケーションでARMS APMを有効にするには、クラスターにone-pilotコンポーネントをインストールする必要があります。
ACKコンソールにログインします。 左側のナビゲーションウィンドウで、[クラスター] をクリックします。
[クラスター] ページで、管理するクラスターの名前をクリックします。 左側のナビゲーションウィンドウで、 を選択します。
[アドオン] ページで、ack-onepilotコンポーネントを見つけ、コンポーネントカードの [インストール] をクリックします。 表示されるダイアログボックスで、パラメーターを設定し、[OK] をクリックします。
ステップ2: ARMSへのアクセスをクラスターに許可する
ACKサーバーレスクラスター内のアプリケーション、またはエラスティックコンテナインスタンスにデプロイされているアプリケーションを監視するには、まず [クラウドリソースアクセス許可] ページでARMSへのアクセスをクラスターに許可する必要があります。 次に、ack-onepilot用に作成されたすべてのポッドを再起動します。
ACKクラスター内のアプリケーションを監視するには、まずARMS Addon Tokenがクラスターに存在するかどうかを確認する必要があります。
ACKクラスターにARMSアドントークンがある場合、ARMSはクラスターに対してパスワードなしの認証を実行します。
説明デフォルトでは、ARMSアドントークンはACK管理クラスターに存在します。 ただし、ARMSアドントークンは、かなり前に作成された一部のACK管理クラスターには存在しない場合があります。 次の手順を実行して、クラスターにARMSへのアクセスを許可します。
ACKクラスターにARMSアドントークンがない場合は、ACKクラスターにARMSへのアクセスを手動で許可する必要があります。
カスタムポリシーを作成し、次の内容をポリシードキュメントに追加します。 詳細については、「 [製品の変更] ACK管理クラスターのワーカーRAMロールの権限が取り消されます」トピックのステップ1: カスタムポリシーの作成セクションをご参照ください。
{ "Action": "arms:*", "Resource": "*", "Effect": "Allow" }
カスタムポリシーをワーカーRAM (Resource Access Management) ロールにアタッチします。 詳細については、「 [製品の変更] ACK管理クラスターのワーカーRAMロールの権限が取り消されます」トピックのステップ2: カスタムポリシーをワーカーRAMロールにアタッチするセクションをご参照ください。
ステップ3: JavaアプリケーションのARMS APMの有効化
Javaアプリケーションをクラスターにデプロイする場合、アプリケーションにラベルを追加することでARMS APMを有効にできます。
ACKコンソールにログインします。 左側のナビゲーションウィンドウで、[クラスター] をクリックします。
[クラスター] ページで、管理するクラスターの名前をクリックします。 左側のウィンドウで、 を選択します。
の右上隅にデプロイメントページをクリックします。YAMLから作成する.
表示されるページで、[サンプルテンプレート] ドロップダウンリストからテンプレートを選択し、[テンプレート] コードエディターのspec > template > metadataセクションに次の
ラベル
を追加します。labels: armsPilotAutoEnable: "on" armsPilotCreateAppName: "<your-deployment-name>" # Replace <your-deployment-name> with the actual application name. one-agent.jdk.version: "OpenJDK11" # This parameter is required if the application uses JDK 11. armsSecAutoEnable: "on" # This parameter is required if you want to enable Application Security.
説明アプリケーションセキュリティの詳細については、アプリケーションセキュリティとは
アプリケーションセキュリティの使用に対して課金されます。 アプリケーションセキュリティの課金の詳細については、「課金」をご参照ください。
次のYAMLテンプレートは、ARMS APMが有効な配置を作成する方法を示しています。
ARMS APMによって収集されたモニタリングデータを表示します。
[デプロイメント] ページでアプリケーションを見つけ、[ARMSコンソール] が [操作] 列に表示されているかどうかを確認します。
[ARMSコンソール] をクリックしてモニタリングデータを表示します。 左側のナビゲーションウィンドウで、[Interface Invocation] をクリックして、アプリケーションのAPIへのリクエスト (HTTPリクエストなど) に関する情報を表示します。 arms-springboot-demoアプリケーションのAPIへのリクエストを次の図に示します。 リクエスト頻度は安定しています。
Server Load Balancer (SLB) インスタンスを使用してarms-springboot-demoアプリケーションのAPIを公開するサービスを作成します。
[クラスター] ページで、管理するクラスターの名前をクリックします。 左側のウィンドウで、 を選択します。
サービスページの右上隅にある [作成] をクリックします。 [サービスの作成] ダイアログボックスでパラメーターを設定し、[OK] をクリックします。 サービスパラメーターの詳細については、「サービスの作成」をご参照ください。
サービスが作成されるまで待ちます。 [サービス] ページでは、arms-demo-svcサービスの外部エンドポイントを表示できます。 例: 47.94.XX.XX:8080。
次のコマンドを実行して、サービスの外部エンドポイントを使用して /demo/queryUser/10 APIにリクエストを送信します。
curl http://47.94.XX.XX:8080/demo/queryUser/10
期待される出力:
{"id":1,"name":"KeyOfSpectator","password":"12****"}
期待される出力は、リクエストが成功したことを示します。
手順4: alibaba-cloud-metrics-adapterの設定
Prometheusコンポーネントがインストールされていることを確認します。 それ以外の場合、この手順は実行できません。 詳細については、「Prometheusのマネージドサービス」トピックの手順1: Prometheusのマネージドサービスの有効化を参照してください。
alibaba-cloud-metrics-adapterがkube-system名前空間にデプロイされていることを確認します。 それ以外の場合、この手順は実行できません。 詳細については、「alibaba-cloud-metrics-adapterのデプロイ」をご参照ください。
最初に
ARMSコンソールを使用します。左側のナビゲーションウィンドウで、 .
[インスタンス] ページで、管理するインスタンスを見つけ、その名前をクリックします。 名前はarms_metrics_{RegionId}_XXX形式です。 左側のナビゲーションウィンドウで、[設定] をクリックします。 [設定] タブの下部で、[HTTP API URL (Grafana読み取りURL)] セクションにプロメテウスURLを表示して記録します。
から取得したPrometheus URLを指定します。HTTP APIアドレス (Grafana読み取りアドレス)前の手順で、ack-alibaba-cloud-metrics-adapterの設定セクションを使用します。
ack-alibaba-cloud-metrics-adapterのadapter-config ConfigMapの設定を変更します。
Helmページで、ack-alibaba-cloud-metrics-adapterをクリックします。
[基本情報] タブで、[adapter-config] をクリックします。
adapter-configページの右上隅で、[YAMLの編集] をクリックします。
adapter-config ConfigMapに次の設定を追加します。
rules: - metricsQuery: sum by (rpc) (sum_over_time(<<.Series>>{rpc="/demo/queryUser/{id}",service="arms-demo:arms-k8s-demo",prpc="__all__",ppid="__all__",endpoint="__all__",destId="__all__",<<.LabelMatchers>>}[1m])) name: as: ${1}_per_second_queryuser matches: ^(.*)_count resources: namespaced: false seriesQuery: arms_app_requests_count
完全なサンプルコード:
クラスター内のメトリクスを照会します。
次のコマンドを実行して、arms_app_requests_per_second_queryuserメトリックが存在するかどうかを確認します。
kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1"
期待される出力:
{"kind":"APIResourceList","apiVersion":"v1","groupVersion":"external.metrics.k8s.io/v1beta1","resources":[{"name":"k8s_workload_memory_working_set","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"k8s_workload_memory_rss","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"sls_ingress_latency_p9999","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"slb_l7_qps","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"cost_memory_usage","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"slb_l4_traffic_rx","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"sls_ingress_inflow","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"slb_l7_upstream_rt","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"cost_ratio","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"slb_l4_traffic_tx","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"slb_l4_packet_rx","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"ahas_sentinel_pass_qps","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"cost_memory_request","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"sls_ingress_latency_avg","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"slb_l4_max_connection","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"cost_cpu_limit","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"cost_day","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"cost_month","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"slb_l4_connection_utilization","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"slb_l7_status_5xx","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"k8s_workload_cpu_request","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"k8s_workload_network_rx_rate","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"k8s_workload_network_rx_errors","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"cost_week","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"k8s_workload_memory_cache","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"cost_cpu_request","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"cost_percorepricing","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"sls_ingress_qps","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"slb_l4_packet_tx","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"slb_l7_status_4xx","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"slb_l7_upstream_5xx","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"k8s_workload_cpu_limit","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"ahas_sentinel_block_qps","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"cost_cpu_utilization","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"sls_alb_ingress_qps","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"cost_memory_utilization","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"sls_ingress_latency_p95","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"slb_l4_active_connection","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"k8s_workload_memory_limit","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"cost_hour","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"slb_l7_status_2xx","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"slb_l7_status_3xx","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"k8s_workload_cpu_util","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"k8s_workload_memory_usage","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"k8s_workload_network_tx_rate","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"ahas_sentinel_total_qps","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"cost_cpu_usage","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"k8s_workload_network_tx_errors","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"slb_l7_rt","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"cost_min","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"sls_ingress_latency_p50","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"sls_ingress_latency_p99","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"slb_l7_upstream_4xx","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"k8s_workload_memory_request","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"ahas_sentinel_avg_rt","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"cost_memory_limit","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]},{"name":"arms_app_requests_per_second_queryuser","singularName":"","namespaced":true,"kind":"ExternalMetricValueList","verbs":["get"]}]}
出力は、arms_app_requests_per_second_queryuserメトリックが存在することを示します。
次のコマンドを実行して、リアルタイムメトリック値を表示します。
kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1/namespaces/arms-demo/arms_app_requests_per_second_queryuser"| jq .
期待される出力:
{ "kind": "ExternalMetricValueList", "apiVersion": "external.metrics.k8s.io/v1beta1", "metadata": {}, "items": [ { "metricName": "arms_app_requests_per_second_queryuser", "metricLabels": { "rpc": "/demo/queryUser/10" }, "timestamp": "2022-11-09T07:49:07Z", "value": "6" } ] }
出力は、メトリック値が期待どおりに返されたことを示します。
手順5: APMメトリックに基づいてアプリケーションを自動的にスケーリングするようにHPAを設定する
hpa.yamlという名前のファイルを作成し、次の内容をファイルに追加します。
説明hpa.yamlファイルで指定するメトリック名は、前の手順でack-alibaba-cloud-metrics-adapterで定義したものと同じである必要があります。
hpa.yamlファイルの
target
パラメーターは、スケールアウトしきい値を指定します。 この例では、QPSが40を超えると、HPAはアプリケーションをスケールアウトします。
apiVersion: autoscaling/v2beta2 kind: HorizontalPodAutoscaler metadata: name: test-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: arms-springboot-demo minReplicas: 1 maxReplicas: 10 metrics: - type: External external: metric: name: arms_app_requests_per_second_queryuser # You can specify only thresholds of the Value or AverageValue type for external metrics. target: type: AverageValue averageValue: 40
次のコマンドを実行して、arm-springboot-demoアプリケーションにHPAをデプロイします。
kubectl apply -f hpa.yaml
次のコマンドを実行して、メトリックの変更を照会します。
kubectl get --raw "/apis/external.metrics.k8s.io/v1beta1/namespaces/arms-demo/arms_app_requests_per_second_queryuser"| jq .
期待される出力:
{ "kind": "ExternalMetricValueList", "apiVersion": "external.metrics.k8s.io/v1beta1", "metadata": {}, "items": [ { "metricName": "arms_app_requests_per_second_queryuser", "metricLabels": { "rpc": "/demo/queryUser/10" }, "timestamp": "2022-11-09T07:53:16Z", "value": "4216" } ] }
次のコマンドを実行して、HPAに関する詳細情報を照会します。
kubectl get hpa -n arms-demo
期待される出力:
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE test-hpa Deployment/arms-springboot-demo 300m/40 (avg) 1 10 10 148m
HPAがデプロイされていることを示す値が [ターゲット] 列に表示されます。
ストレステストを実行してアプリケーションスケーリングを検証する
次のコマンドを実行して、デモアプリケーションでストレステストを実行します。
ab -c 50 -n 2000 http://47.94.XX.XX:8080/demo/queryUser/10
説明47.94.XX.XX:8080
arms-demo-svcサービスの外部エンドポイントです。メトリック値が指定されたしきい値を超えたときにアプリケーションがスケーリングされているかどうかを確認します。
ストレステストを実行した後、アプリケーションのAPIへのリクエスト数が急増したことをARMSコンソールで確認できます。 次のイメージは例を示しています。
次のPrometheusダッシュボードは、アプリケーションのAPIのQPSが指定されたスケーリングしきい値を超えると、HPAがアプリケーションをスケーリングすることを示しています。
アプリケーションのAPIのQPSが指定されたスケーリングしきい値を超えると、デモアプリケーション用に作成されたレプリケートされたポッドの数がHPAによってスケールアウトされます。
kubectl describe hpa test-hpa -n arms-demo
コマンドを実行して、スケーリングイベントを照会できます。