はじめに
1年ぶりです。おとです。 2022年12月に、New Relic を使った Kubernetes (以下、「k8s」という。) の監視についての記事を書きました。
今回もNew Relicとk8sを絡めたお話をしたいと思います。
k8sはコンテナオーケストレーションツールであり、自動スケーリング機能があります。 リソースの効率的な利用とアプリケーションのパフォーマンス維持に不可欠な機能です。
この記事では、k8sの自動スケーリング機能の1つであるHorizontal Pod Autoscaler (HPA) の基本から、New Relicを利用した外部メトリクスによるスケーリングの実装までを紹介します。
HPAの基本
HPAは、指定したメトリクスに基づいてPodの数を自動で調整するk8sの機能です。
(PodやDeploymentといったk8sの用語についてはリンク先のk8s公式サイトをご確認ください。)
k8sの標準メトリクスでは、CPUやメモリの使用率が閾値を超えたときにPodの数を増やし、逆に使用率が下がったら減らす、ということができます。
しかし、標準メトリクスだけでは、アプリケーションのパフォーマンス維持に十全に対応できるわけではありません。
カスタムメトリクスの必要性
例えば、アプリケーションのアクセス数が急増した際に適切にスケーリングするには、CPUやメモリ以外の指標が必要です。
このような場合、カスタムメトリクスに基づいてスケーリングできるようにする必要がありますが、これを実現するためにはメトリクスアダプターが必要になります。
メトリクスソリューションの選択
カスタムメトリクスの収集・管理には多くのツールがありますが、k8s公式から提供されているものはなく、よく使われているのはPrometheusのようです。
しかし、今回はせっかくなのでNew Relicが提供しているメトリクスアダプターを使ってみました。
New Relic メトリクスアダプターの導入と設定
New Relicのメトリクスアダプターをk8sに導入する過程は比較的シンプルです。
New Relicの公式ドキュメントに導入手順が用意されています。
Kubernetes を使用してインフラストラクチャを自動スケールする | New Relic Documentation
以下のコードはk8sクラスターとNew Relicエージェントをデプロイするためのマニフェストファイルの該当箇所を一部抜粋したものです。
--- apiVersion: helm.toolkit.fluxcd.io/v2beta1 kind: HelmRelease metadata: name: newrelic-bundle namespace: newrelic spec: releaseName: newrelic-bundle chart: spec: chart: nri-bundle reconcileStrategy: ChartVersion sourceRef: kind: HelmRepository name: newrelic values: newrelic-k8s-metrics-adapter: lowDataMode: true personalAPIKey: "New RelicのAPIキー" config: accountID: "New RelicのアカウントID" externalMetrics: requests_count: query: "SELECT COUNT(*) FROM Log SINCE 5 minutes ago"
「requests_count」という名前で外部メトリクスを定義しています。
次に、HPA側の設定をします。
apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: api-front-hpa spec: minReplicas: 1 maxReplicas: 3 metrics: - type: External external: metric: name: requests_count selector: matchLabels: proxy_upstream_name: demo1-api-service target: type: AverageValue averageValue: 50 scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: demo1-api-deployment
メトリック名に先ほど定義した「requests_count」を指定します。
matchLabelsに指定したKeyValueは、NRQLのWHERE条件として適用されるので、New Relicに発行されるクエリは
SELECT COUNT(*) FROM Log WHERE proxy_upstream_name = 'demo1-api-service' SINCE 5 minutes ago
となり、この取得結果をアクセス数とします。
(今回はIngress-Nginxを使用してPodへの通信をルーティングさせており、Ingress-NginxのログもNew Relicに連携しています。
proxy_upstream_name
はIngress-Nginxのログの属性の1つであり、Podに紐づくServiceの名前が入っています。
'demo1-api-service'を指定することで、demo1-api-deploymentのPodへのアクセスログの件数をアクセス数として取得しています。)
targetをAverageValueとしているので、アクセス数をPodの数で除算した値を閾値と比較して、いくつまでスケールするかを決めることができます。
今回の例でいうと、averageValueが50でmaxReplicasが3なので以下のような挙動となります。
- 現在のPod数=1、アクセス数>50 ⇒ 50÷1=50となり、Pod数が2に増える
- 現在のPod数=2、アクセス数=50 ⇒ 50÷2=25となり、Pod数は2のまま
- 現在のPod数=2、アクセス数>100 ⇒ 100÷2=50となり、Pod数が3に増える
- 現在のPod数=3、アクセス数=100 ⇒ 100÷3=33となり、Pod数は3のまま
- 現在のPod数=3、アクセス数>150 ⇒ 150÷3=50となるが、Max=3なのでPod数は3のまま
実装結果
アクセス数の増加に伴い、自動的にPodの数を増減させることができました。
今回は実験として閾値を50としましたが、実際の運用ではアプリケーションのアクセス状況をもとに閾値を試行錯誤する必要があります。
おわりに
今回は、New Relicを利用した外部メトリクスによるHPAの実装例を紹介しました。
HPAを利用することで予期せぬアクセス集中が発生したときも、自動でスケールすることができるのでアプリケーションのパフォーマンスを維持することができます。
機会があればPrometheusも試してみたいと思います。