kubernetesのDeploymentにPrometheusからカスタムメトリクスを登録してみる
背景と目的
kubernetesのカスタムメトリクスは Pod
のオートスケールでよく用いられる。
Pod
それぞれのメトリクスなどをベースにスケールさせたい場合については、Prometheus Adapterのドキュメントに整理されている。
一方、Pod
のメトリクスに関係なくオートスケールしたい状況(たとえば、事前にスケジュールしたい場合など)も想定される。
外部(External)メトリクスとして登録することもできるが、 Pod
を取りまとめる Deployment
に関連するメトリクスであるため、Deployment
に登録したい。
本記事では Deployment
に簡単なカスタムメトリクスを登録する方法について試した設定例をもとに述べる。
実際に使えるかどうかは未検討である。
次のようなポイントがある:
- Prometheus + Prometheus Adapter + kube-state-metricsを構成する。
- kube-state-metricsの
Deployment
に関するメトリクス(kube_deployment_created
など)を使う。 - Prometheus Adapterに
Deployment
リソースの参照権限を付与する。
試した設定例
helm
コマンドがインストール済みで、kubernetesに cluster-admin
として接続可能な環境で、次のコマンドを実行する(各ファイルの中身については後述する):
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm upgrade -i prometheus prometheus-community/prometheus -f prometheus-values.yaml --version 25.20.0
helm upgrade -i prometheus-adapter prometheus-community/prometheus-adapter -f prometheus-adapter-values.yaml --version 4.10.0
kubectl create role prometheus-adapter-deployment-reader --verb get,list,watch --resource deployments.apps
kubectl create rolebinding prometheus-adapter-deployment-reader --role prometheus-adapter-deployment-reader --serviceaccount default:prometheus-adapter
Prometheus AdapterのHelmチャートで作成される ClusterRole
には Deployment
に対する権限がないため、付与する。
今回は ClusterRole
でなく Role
としているが、他のネームスペースの Deployment
にもカスタムメトリクスを紐づける必要があれば、 ClusterRole
を作成する。
PrometheusのHelmチャートの設定ファイルでは、次のようにレコーディングルールの設定と、不要なコンポーネントの無効化を行う:
serverFiles:
recording_rules.yml:
groups:
- name: schedule
rules:
- record: schedule_desired_replicas
expr: |
(
timestamp(vector(0))
+ ignoring(deployment, namespace) group_right
0 * sum(kube_deployment_created{namespace!="", deployment!="") by (deployment, namespace)
-
1714194827
) / 100
nodeExporter:
enabled: false
prometheus-pushgateway:
enabled: false
alertmanager:
enabled: false
prometheus-node-exporter:
enabled: false
レコーディングルールには、ネームスペースや Deployment
リソース名が設定されたラベルがないと、後続のPrometheus Adapterでカスタムメトリクスに紐づけられなくなる。
これらのラベルがクエリ対象のメトリクスに付いていない場合は、 ignoring
と group_right
で無理やり付与できたが、よりうまいやり方があるかもしれない。
kube_deployment_created
の値に0を乗じて消し、 timestamp
の値(その時点のUNIX時間)だけを残している。
設定例では、徐々にスケールアウトだけさせる想定で、適当な数に調整している。
Prometheus AdapterのHelmチャートの設定ファイルでは、次のようにPrometheusサーバの接続設定と、レコーディングルールを Deployment
に紐づける設定を行う:
prometheus:
url: http://prometheus-server
port: 80
rules:
default: false
custom:
- seriesQuery: schedule_desired_replicas{namespace!="", deployment!=""}
resources:
overrides:
namespace: {resource: namespace}
deployment: {group: apps, resource: deployment}
name:
matches: ^(.*)$
metricsQuery: <<.Series>>
次のように動作確認ができる:
kubectl create deploy --image nginx
kubectl get --raw '/apis/custom.metrics.k8s.io/v1beta1'
kubectl get --raw '/apis/custom.metrics.k8s.io/v1beta1/namespaces/default/deployments/nginx/schedule_desired_replicas'
出力は次のようになる:
{"kind":"APIResourceList","apiVersion":"v1","groupVersion":"custom.metrics.k8s.io/v1beta1","resources":[{"name":"deployments.apps/schedule_desired_replicas","singularName":"","namespaced":true,"kind":"MetricValueList","verbs":["get"]},{"name":"namespaces/schedule_desired_replicas","singularName":"","namespaced":false,"kind":"MetricValueList","verbs":["get"]}]}
{"kind":"MetricValueList","apiVersion":"custom.metrics.k8s.io/v1beta1","metadata":{},"items":[{"describedObject":{"kind":"Deployment","namespace":"default","name":"nginx","apiVersion":"apps/v1"},"metricName":"schedule_desired_replicas","timestamp":"2024-04-27T07:44:07Z","value":"89902m","selector":null}]}
このカスタムメトリクスをもとにした HorizontalPodAutoscaler
は次のようになる:
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx
minReplicas: 1
maxReplicas: 20
metrics:
- type: Object
object:
describedObject:
apiVersion: apps/v1
kind: Deployment
name: nginx
metric:
name: schedule_desired_replicas
target:
type: AverageValue
averageValue: 1
schedule_desired_replicas
の値を Pod
の数で割った値が1になるように調整される設定ということはつまり、 Pod
の数が schedule_desired_replicas
の値になるように調整される。
今後の検討事項
今回は事前にスケールアウトの計画を立てたい場合を想定していたが、そこで実用するには次の事項を検討しなければならない:
-
Deployment
ごとにスケールアウトするタイミングが異なる場合のメトリクスの設定方法 - スケールアウトさせた後の管理方法
- スケールインさせる方法:スケジュールでスケールインさせるだけなら、そういうクエリを書けばよいが、アクセス増にそなえてスケールアウトさせたのであれば、アクセスが収まってからスケールインすべきなので、スケジュールでスケールインさせることは少ないと考えられる。
クエリの設定箇所について
今回はカスタムメトリクスのクエリをPrometheusのレコーディングルールとして設定したが、Prometheus Adapterの設定として書くこともできる。
Helmチャートでデプロイ・更新することを想定すると、Prometheus Adapterは変更時に再起動が必要だが、Prometheusは再起動せずにConfig Reloaderでクエリの更新が可能な構成を取れる。
レコーディングルールを用いる場合は、ルール評価タイミングがずれ、Prometheusメトリクスとして保存される分、ストレージを消費することになる。
Discussion