コンテンツにスキップ

metrics-server@ハードウェアリソース管理

はじめに

本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。


01. metrics-serverの仕組み

アーキテクチャ

metrics-serverは、拡張APIサーバー、ローカルストレージ、スクレイパー、といったコンポーネントから構成される。

PodとNodeのメトリクスのデータポイントを収集し、kubectl topコマンドでこれを取得できる。

また必須ではないが、HorizontalPodAutoscalerとVerticalPodAutoscalerを作成すれば、Podの自動水平スケーリングや自動垂直スケーリングを実行できる。

KubernetesのNodeとPod (それ以外のKubernetesリソースは対象外) のメトリクスのデータポイントを収集しつつ、収集したデータポイントを拡張APIサーバーで公開する。

似た名前のツールにkube-metrics-serverがあるが、こちらはExporterとして稼働する。

(1)

クライアント (kubectl topコマンド実行者、HorizontalPodAutoscaler、VerticalPodAutoscaler) がmetrics-serverのAPIからメトリクスを参照しようとする。

(2)

クライアントは、kube-apiserverにリクエストが送信する。

(3)

kube-apiserverは、metrics-serverのプロキシ (APIService) にリクストを転送する。

(4)

APIServiceは、クライアントにメトリクスを返信する。

kubernetes_metrics-server


拡張APIサーバー

▼ 拡張APIサーバーとは

拡張APIサーバーは、ServiceとAPIServiceを介して、クライアント (kubectl topコマンド実行者、HorizontalPodAutoscaler、VerticalPodAutoscaler) からのリクエストを受信し、メトリクスのデータポイントを含むレスポンスを返信する。

データポイントはローカルストレージに保管している。


ローカルストレージ

ローカルストレージは、クライアント (kubectl topコマンド実行者、HorizontalPodAutoscaler、VerticalPodAutoscaler) 宛先となっているPodやNodeのメトリクスのデータポイントを保管する。


スクレイパー

スクレイパーは、kubeletのデーモンからPodやNodeからメトリクスのデータポイントを定期的に収集し、ローカルストレージに保管する。

kubeletのデーモンはメトリクス収集用エンドポイント (例:/metrics/resource/stats、など) を持ち、これがスクレイパーの収集対象になる。

そのため、PodやNodeにメトリクス収集用エンドポイント (例:/metrics) を設ける必要はない。

metrics-server_scraper


01-02. マニフェスト

Deployment配下のPod

記入中...

apiVersion: apps/v1
kind: Pod
metadata:
  name: metrics-server
  namespace: kube-system
spec:
  containers:
    - name: metrics-server
      image: registry.k8s.io/metrics-server/metrics-server:v0.6.3
      imagePullPolicy: IfNotPresent
      args:
        - --cert-dir=/tmp
        - --secure-port=4443
        - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
        - --kubelet-use-node-status-port
        # メトリクスの収集間隔を最小にする。
        # https://github.com/kubernetes-sigs/metrics-server/blob/master/FAQ.md#how-often-metrics-are-scraped
        - --metric-resolution=15s
      resources:
        requests:
          cpu: 100m
          memory: 200Mi
      ports:
        - name: https
          containerPort: 4443
          protocol: TCP
      readinessProbe:
        httpGet:
          path: /readyz
          port: https
          scheme: HTTPS
        periodSeconds: 10
        failureThreshold: 3
        initialDelaySeconds: 20
      livenessProbe:
        httpGet:
          path: /livez
          port: https
          scheme: HTTPS
        periodSeconds: 10
        failureThreshold: 3
        # metrics-serverの準備完了を待たずにReadinessProbeヘルスチェックを実施しないように、初回のヘルスチェックを開始するまでの待機時間を延長する
        # https://github.com/kubernetes-sigs/metrics-server/issues/1056#issuecomment-1288198994
        initialDelaySeconds: 80
      securityContext:
        readOnlyRootFilesystem: "true"
        runAsNonRoot: "true"
        runAsUser: 1000
      volumeMounts:
        - mountPath: /tmp
          name: tmp-dir
  priorityClassName: system-cluster-critical
  serviceAccountName: metrics-server
  volumes:
    - emptyDir: {}
      name: tmp-dir


APIService

記入中...

apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
  labels:
    k8s-app: metrics-server
  name: v1beta1.metrics.k8s.io
spec:
  group: metrics.k8s.io
  groupPriorityMinimum: 100
  insecureSkipTLSVerify: "true"
  service:
    name: metrics-server
    namespace: kube-system
  version: v1beta1
  versionPriority: 100


02. kubectl topコマンド

node

▼ nodeとは

Nodeのハードウェアリソースの消費量を取得する。

# Nodeのメトリクスを取得
$ kubectl top node

NAME       CPU(cores)   CPU%   MEMORY(bytes)   MEMORY%
foo-node   174m         2%     8604Mi          30%
bar-node   2917m        82%    16455Mi         57%
baz-node   352m         4%     9430Mi          33%

また、クライアントがHorizontalPodAutoscalerやVerticalPodAutoscalerの場合は、kube-apiserverを介して、拡張APIサーバーからNodeやPodのメトリクスを取得し、Podのオートスケーリングする。

horizontal-pod-autoscaler

▼ デバッグ

metrics-serverが正しく動作していない場合、Nodeのハードウェアリソースの消費量が<unknown>になる。

$ kubectl top node

NAME      CPU(cores)  CPU%       MEMORY(bytes)  MEMORY%
master-1  192m        2%         10874Mi        68%
node-1    582m        7%         9792Mi         61%
node-2    <unknown>   <unknown>  <unknown>      <unknown>


pod

▼ podとは

Podのハードウェアリソースの消費量を取得する。

$ kubectl top pod -n foo-namespace

NAME      CPU(cores)   MEMORY(bytes)
foo-pod   5m           104Mi

▼ --containers

Podのコンテナに関して、ハードウェアリソースの消費量を取得する。

コンテナのKubernetesリソース使用量を足した値が、Pod内で使用するリソース消費量になる。

$ kubectl top pod --container -n foo-namespace

POD       NAME            CPU(cores)   MEMORY(bytes)
foo-pod   foo-container   1m           19Mi
foo-pod   istio-proxy     5m           85Mi

▼ デバッグ

metrics-serverが正しく動作していない場合、Podのハードウェアリソースの消費量が<unknown>になる。

$ kubectl top pod

NAME       CPU(cores)  CPU%       MEMORY(bytes)  MEMORY%
foo-pod    <unknown>   <unknown>  <unknown>      <unknown>


03. Podの自動水平スケーリング/自動垂直スケーリング

HorizontalPodAutoscaler

▼ HorizontalPodAutoscalerとは

Deployment、StatefulSet、ReplicaSet、の単位でPodの自動水平スケーリングを実行する。

metrics-serverから取得したPodに関するメトリクス値とターゲット値を比較し、kubeletを介して、Podをスケールアウト/スケールインさせる。

設定されたターゲットを超過しているようであればスケールアウトし、反対に下回っていればスケールインする。

HorizontalPodAutoscalerを使用するためには、metrics-serverも別途インストールしておく必要がある。

horizontal-pod-autoscaler

▼ 最大Pod数の求め方

オートスケーリング時の現在のPod数は、次の計算式で算出される。

算出結果に基づいて、スケールアウト/スケールインが実行される。

(必要な最大Pod)
= (現在のPod) x (現在のPodCPU平均使用率) ÷ (現在のPodCPU使用率のターゲット値)

例えば、『現在のPod数 = 5』『現在のPodのCPU平均使用率 = 90』『現在のPodのCPU使用率のターゲット値 = 70』だとすると、『必要な最大Pod数 = 7』となる。

算出結果と比較して、現在のPod数不足しているため、スケールアウトが実行される。

▼ デバッグ

Deployment配下のPodで、.spec.containers[*]resourcesキーに要求量を設定すると、HorizontalPodAutoscalerが要求量に対する使用量 (Target列) を取得できるようになる。

一方でこれを取得できていない場合、設定が無いか、metrics-serverが正しく動作していない可能性がある。

$ kubectl get hpa -A

NAMESPACE  NAME             REFERENCE                   TARGETS         MINPODS   MAXPODS   REPLICAS   AGE
foo        foo-deployment   Deployment/foo-deployment   <unknown>/80%   1         1         1          391d
bar        bar-deployment   Deployment/bar-deployment   <unknown>/80%   1         1         1          391d
baz        baz-deployment   Deployment/baz-deployment   <unknown>/80%   1         1         1          391d

▼ レプリカ数との衝突

Deploymentのレプリカ数よりも、HorizontalPodAutoscalerが優先される。

そのため、もしDeploymentにレプリカ数が設定されていると、マニフェストをデプロイした場合に一度レプリカ数に戻される。

HorizontalPodAutoscalerを使用する場合、Deploymentのレプリカ数の設定を削除する。

▼ メトリクスでのPodの増減

メトリクス上では、既存のPodが削除されて、新しいPodが作成されていることを確認できる。


VerticalPodAutoscaler

▼ VerticalPodAutoscalerとは

Podの垂直スケーリングを実行する。

▼ Podの再作成のない垂直スケーリング

執筆時点 (2022/12/31) の仕様では、Podを垂直スケーリングする場合に、Podの再作成が必要になる。

これを解決するために、いくつかの方法が提案されている。

方法 説明
マニフェストの新しい設定値の追加 マニフェストに、垂直スケーリング時のルールに関する設定値 (例:.spec.containers[*].resources[*].resizePolicyキー) を追加する。
eBPFによるインプレース変更 ハードウェアリソースの不足が検知された時に、eBPFを使用して、Podのマニフェストを変更するJSONPatch処理をフックする。