はじめに(What’s New の内容含む)
ここでは、Kubernetes 1.20 の CHANGELOG から Metrics の変更と SIG Instrumentation の取り組みについてまとめています。
Kubernetes v1.20 で SIG Instrumentation が扱うテーマは 2 つあります。では順番に確認していきます。
Runtime log sanitation
ログは機密データの漏洩を防ぐため、ランタイムの保護機能を設定できるようになりました。 この実験的な機能の詳細はドキュメントに記載されています。
簡単にこの機能を説明すると、Kubernetes component から出力されるログにパスワードやトークンなどが含まれていた場合、ログの出力を抑制し機密データの漏洩を防ぐ機能となります。この機能は次の KEP で検討されています。
この KEP のノンゴールにも記載されている通り、「Kubernetes システムコンポーネントログを介し、セキュリティ上の機密データを公開するリスクを完全に排除する」ことは困難ですので、あくまで保険的な機構となります。
こちらの機能は --experimental-logging-sanitization
フラグを使って有効にします。
ドキュメントを確認してみると「ログのサニタイズにはかなりの計算オーバーヘッドが発生する可能性があるため、本番環境では有効にしないでください」とあります。
KEP ではその他に補完的な解決方法として静的コード分析も検討されています。
Pod resource metrics
オンデマンドのメトリクスが /metrics/resources から利用できるようになりました。この機能を有効にすると実行中の Pod のリソースリクエストが取得できます。
公式リリースの内容を補足すると、kube-scheduler のエンドポイントに /metrics/resource
が追加され、そこから Pod のリソースリクエストのメトリクスが取得できる機能になります。このメトリクスでキャパシティプランニングを実行し、ダッシュボードなどからリソース不足のためにスケジュールできないワークロードをすばやく特定できます。
すでに kube-state-metrics で実現できていますが、後ほど背景や違いについて確認していきます。
こちらは実際にどのようなメトリクスが取得できるか確認した方が理解しやすいのでクラスタを作成して、メトリクスを取得してみます。
# Kubernetes クラスタの作成
# メトリクスを簡単に確認するため bind-address、port も設定し起動する
❯❯ minikube version
minikube version: v1.16.0
commit: 9f1e482427589ff8451c4723b6ba53bb9742fbb1
❯❯ minikube start \
--kubernetes-version 1.20.0 \
--vm-driver hyperkit \
--extra-config 'scheduler.v=6' \
--extra-config 'scheduler.show-hidden-metrics-for-version=1.20' \ # v1.20 では指定なしでも取得可
--extra-config 'scheduler.bind-address=0.0.0.0' \
--extra-config 'scheduler.port=10251'
😄 minikube v1.16.0 on Darwin 10.15.7
✨ Using the hyperkit driver based on existing profile
👍 Starting control plane node minikube in cluster minikube
🔥 Creating hyperkit VM (CPUs=2, Memory=4000MB, Disk=20000MB) ...
🐳 Preparing Kubernetes v1.20.0 on Docker 20.10.0 ...
▪ scheduler.v=6
▪ scheduler.show-hidden-metrics-for-version=1.20
🔎 Verifying Kubernetes components...
🌟 Enabled addons: storage-provisioner, default-storageclass
❗ /Users/wmatsui/.local/bin/kubectl is version 1.18.5, which may have incompatibilites with Kubernetes 1.20.0.
▪ Want kubectl v1.20.0? Try 'minikube kubectl -- get pods -A'
🏄 Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default
proxy 経由で /metrics/resources
エンドポイントにアクセスすると、kube_pod_resource_request
と kube_pod_resource_limit
のメトリクスが取得できます。
# proxy 経由でアクセスするためバックグラウンドで実行
❯❯ kubectl proxy --port 8080 &
# proxy 経由で `/metrics/resources` エンドポイントにアクセス
❯❯ curl -sLf http://localhost:8080/api/v1/namespaces/kube-system/pods/kube-scheduler-minikube:10251/proxy/metrics/resources
# HELP kube_pod_resource_limit [ALPHA] Resources limit for workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.
# TYPE kube_pod_resource_limit gauge
kube_pod_resource_limit{namespace="kube-system",node="minikube",pod="coredns-74ff55c5b-sxp44",priority="2000000000",resource="memory",scheduler="default-scheduler",unit="bytes"} 1.7825792e+08
# HELP kube_pod_resource_request [ALPHA] Resources requested by workloads on the cluster, broken down by pod. This shows the resource usage the scheduler and kubelet expect per pod for resources along with the unit for the resource if any.
# TYPE kube_pod_resource_request gauge
kube_pod_resource_request{namespace="kube-system",node="minikube",pod="coredns-74ff55c5b-sxp44",priority="2000000000",resource="cpu",scheduler="default-scheduler",unit="cores"} 0.1
kube_pod_resource_request{namespace="kube-system",node="minikube",pod="coredns-74ff55c5b-sxp44",priority="2000000000",resource="memory",scheduler="default-scheduler",unit="bytes"} 7.340032e+07
kube_pod_resource_request{namespace="kube-system",node="minikube",pod="etcd-minikube",priority="2000001000",resource="cpu",scheduler="default-scheduler",unit="cores"} 0.1
kube_pod_resource_request{namespace="kube-system",node="minikube",pod="etcd-minikube",priority="2000001000",resource="ephemeral-storage",scheduler="default-scheduler",unit="bytes"} 1.048576e+08
kube_pod_resource_request{namespace="kube-system",node="minikube",pod="etcd-minikube",priority="2000001000",resource="memory",scheduler="default-scheduler",unit="bytes"} 1.048576e+08
kube_pod_resource_request{namespace="kube-system",node="minikube",pod="kube-apiserver-minikube",priority="2000001000",resource="cpu",scheduler="default-scheduler",unit="cores"} 0.25
kube_pod_resource_request{namespace="kube-system",node="minikube",pod="kube-controller-manager-minikube",priority="2000001000",resource="cpu",scheduler="default-scheduler",unit="cores"} 0.2
kube_pod_resource_request{namespace="kube-system",node="minikube",pod="kube-scheduler-minikube",priority="2000001000",resource="cpu",scheduler="default-scheduler",unit="cores"} 0.1
# バックグラウンドの job を終了(ctrl + c)
❯❯ fg
^C
メトリクスを見やすくするために YAML フォーマットにして、値を value ラベルで表示した CoreDNS のメトリクスを見てましょう。
kube_pod_resource_limit:
namespace: kube-system
node: minikube
pod: coredns-74ff55c5b-sxp44
priority: 2000000000
resource: memory
scheduler: default-scheduler
unit: bytes
value: 1.7825792e+08
kube_pod_resource_request:
namespace: kube-system
node: minikube
pod: coredns-74ff55c5b-sxp44
priority: 2000000000
resource: cpu
scheduler: default-scheduler
unit: cores
value: 0.1
kube_pod_resource_request:
namespace: kube-system
node: minikube
pod: coredns-74ff55c5b-sxp44
priority: 2000000000
resource: memory
scheduler: default-scheduler
unit: bytes
value: 7.340032e+07
実際の CoreDNS Pod の Spec は次のとおりです。
❯❯ kubectl -n kube-system get pod coredns-74ff55c5b-sxp44 -ojson | jq '.spec.containers[].resources'
{
"limits": {
"memory": "170Mi"
},
"requests": {
"cpu": "100m",
"memory": "70Mi"
}
}
pod.spec.resrouces の値がメトリクスとして kube-scheduler から取得できました。ただ多くの kubernetes 利用者は既に kube-state-metrics のメトリクスである kube_pod_container_resource_requests
と kube_pod_container_resource_limits
を利用しているはずです。このメトリクスが kube-scheduler に実装された背景はこちらの KEP に記載されています。
こちらの KEP から背景や概要を簡単に説明します。
現在の kube-state-metrics から取得できるメトリクスから、実際に要求されたクラスタの全リソースリクエストを確認することは困難です。
例えば次のようなマニフェストがあるとします。この Pod の配置に必要な CPU のリソースリクエストは、単純に全てのコンテナの resources.request.cpu を合算した値である 150m ではなく 300m です。これは initContainers 単独で実行出来るリソースリクエストを確保をする必要があるためです。
metadata:
name: nginx
spec:
initContainers:
- name: copy-files
...
resources:
limits:
cpu: 100m
- name: generate-config
...
resources:
requests:
cpu: 300m
containers:
- name: proxy
...
resources:
requests:
cpu: 50m
- name: sidecar-logging
...
resources:
requests:
cpu: 100m
またクラスタの全リソースリクエストを確認するには Spec だけではなく Pod の Status も考慮する必要があります。例えば Job などを実行し Pod が Completed になっているとその Pod の情報は除外する必要があります。私の場合は kube_pod_container_resource_requests
と kube_pod_status_phase{phase="Running"}
のメトリクスを結合しリソースリクエストを確認しています。
kube-state-metrics のメトリクスにラベルを追加し、initConntainer や Status を考慮できる PromQL を実行するのも一つの解決方法です。ですが、それはカーディナリティが増加し不要なメトリクスで Disk サイズを圧迫する問題を生じさせます。kube-state-metrics のメトリクスにある個々のコンテナ情報からリソースリクエストを計算するのは大変であり、これらは正確なキャパシティプランニングを阻害するものです。
実際に Pod をスケジュールするのは kube-scheduler であり、上記のような考慮も kube-scheduler には実装されているわけです。そこで KEP により kube-scheduler がリソースメトリクスを持つ提案がされ、今回 Alpha feature state として実装されました。
この実装が進めば将来的に、属性を主眼に置いたメトリクスを生成する kube-state-metrics からリソースメトリクスが削除される可能性があります。
それでは恒例の Metrics Changes
について説明していきます。
v1.19 から引き続き ChangeLog から Metrics Changes
の項目は削除されているため、私の方で Changes by Kind
からメトリクスの変更に関連するものを抜粋した内容を Metrics Changes
としてまとめました。
メトリクスの変更(Metrics Changes)
追加
kube-apiserver
- リクエストフィルターのレイテンシーを計測するため、次のメトリクスが追加されました(#95207, @tkashem)
- Histogram:
apiserver_request_filter_duration_seconds
- lables: {"filter"}
- Histogram:
- 自身へのリクエストを記録する、次のメトリクスが追加されました(#94288, @LogicalShark)
- Counter:
apiserver_selfrequest_total
- lables: {"verb", "resource", "subresource"}
- Counter:
- 中断したリクエストを記録する、次のメトリクスが追加されました(#95002, @p0lyn0mial)
- Counter:
apiserver_request_aborts_total
- labels: {"verb", "group", "version", "resource", "subresource", "scope"}
- Counter:
- Node Authorizer への負荷を見積もるために使用する次のメトリクスが追加されました(#92466, @mborsz)
- Histogram:
node_authorizer_graph_actions_duration_seconds
- lables: {"operation"}
- Histogram:
kubelet
- 新しい
vSphere
のメトリクスが追加されました。これは関連するサーバーバージョンとvCenter
ホスト名を記録します(#94526, @Danil-Grigorev)- Gauge:
cloudprovider_vsphere_vcenter_versions
- labels: {"hostname", "version", "build"}
- Gauge:
-
/metrics/resource
エンドポイントに、次の CPU とメモリのメトリクスが追加されました(#95839, @egernst)- Gauge:
pod_cpu_usage_seconds_total
- labels: {"pod", "namespace"}
- Gauge:
pod_memory_working_set_bytes
- labels: {"pod", "namespace"}
-
kube-scheduler の Pod Resoruce Metrics と同じく、こちらも既存の
container_memory_working_set_bytes
やcontainer_cpu_usage_seconds_total
メトリクスと異なり、Pod 単位のメトリクスになっています。
- Gauge:
- Pod Resources API のリクエストの総数を記録する、次のメトリクスが追加されました(#92165, @RenaudWasTaken)
- Counter:
kubelet_pod_resources_endpoint_requests_total
- labeles: {"server_api_version"}
- Counter:
- Network Plugin の操作を記録する、次のメトリクスが追加されました(#93066, @AnishShah)
- Counter:
kubelet_network_plugin_operations_total
- labels: {"operation_type"}
- Counter:
kubelet_network_plugin_operations_errors_total
- labels: {"operation_type"}
- Counter:
kube-controller-manager
- Plugin 名と Volume Mode をラベルに持ち、PV の総数をカウントする次のメトリクスが追加されました(#95719, @tsmetana)
- Counter:
pv_collector_total_pv_count
- labels: {"plugin_name", "volume_mode"}
- Counter:
その他
- [Cloud Provider] Azure サービスの操作(Route/Loadbalancer)を記録する、次のメトリクスが追加されました(#94124, @nilo19)
-
services_ensure_loadbalancer
- Histogram:
cloudprovider_azure_op_duration_seconds
- labels: {"request", "resource_group", "subscription_id", "source"}
- Counter:
cloudprovider_azure_op_failure_count
- labels: {"request", "resource_group", "subscription_id", "source"}
- Histogram:
-
変更
kube-apiserver
- API Priority and Fairness で記録されているメトリクスのラベル名を snake_case に変更しました(#96236, @adtac)
- 変更したラベル
- flowSchema => flow_schema
- priorityLevel => priority_level
- 利用しているメトリクス
apiserver_flowcontrol_rejected_requests_total
apiserver_flowcontrol_dispatched_requests_total
apiserver_flowcontrol_current_inqueue_requests
apiserver_flowcontrol_request_queue_length_after_enqueue
apiserver_flowcontrol_request_concurrency_limit
apiserver_flowcontrol_ecuting_requests
apiserver_flowcontrol_request_wait_duration_seconds
apiserver_flowcontrol_request_execution_seconds
- 変更したラベル
kubelet
- 再帰的なアクセス許可の変更を処理する時間を、次のメトリクスの operation_name ラベルに volume_fsgroup_recursive_apply という値で計測するようになりました(#95866, @JornShen)
- Histogram:
storage_operation_duration_seconds
- Histogram:
storage_operation_status_count
- Histogram:
storage_operation_errors_total
- Histogram:
- 次のメトリクスのバケットが変更されました(#96054, @alvaroaleman)
-
kubelet_runtime_operations_duration_seconds
- buckets: [0.005 0.0125 0.03125 0.078125 0.1953125 0.48828125 1.220703125 3.0517578125 7.62939453125 19.073486328125 47.6837158203125 119.20928955078125 298.0232238769531 745.0580596923828]
- impliment: prometheus.ExponentialBuckets(.005, 2.5, 14)
-
非推奨
kube-scheduler
- Stability Level が Alpha だった、次のメトリクスが非推奨となりました。これらのメトリクスは
scheduler_framework_extension_point_duration_seconds
を利用し、前者は PostFilter として、後者は Bind プラグインとしてカバーされています。1.21 で削除される予定です(#95001, @arghya88)。scheduler_binding_duration_seconds
scheduler_scheduling_algorithm_preemption_evaluation_seconds
削除
kube-scheduler
- 次の非推奨なメトリクスが削除されました(#94884, @arghya88)
scheduler_scheduling_duration_seconds
scheduler_scheduling_algorithm_predicate_evaluation_seconds
scheduler_scheduling_algorithm_priority_evaluation_seconds
修正
kube-apiserver
- CRD オブジェクトのメトリクスについて誤って記録されていた verbs ラベルの内容を修正しました(#93523, @wojtek-t)
- GET の代わりに LIST が記録されたメトリクスを修正し、verbs と scope のラベルが正しく記録されるようになりました(#95562, @wojtek-t)
kube-proxy
- Endpoints/EndpointSlice が削除され、正しいタイムスタンプが持たない場合のメトリクスを修正しました(#95363, @wojtek-t)
kubeproxy_network_programming_duration_seconds
その他
- 修正前は呼び出しの大部分が Inf バケットに分類されていたため、バケットを修正しレイテンシが正しく記憶できるようにしました(#94873, @marwanad)
cloudprovider_azure_api_request_duration_seconds
- 削除された apiservices に対してメトリクスが記録されるバグを修正しました(#96421, @dgrisonnet)
aggregator_unavailable_apiservice
種類別の変更点(Changes by Kind)
API の変更(API changes)
- kubelet により提供される GPU メトリクスは、デフォルトで無効となりました(#95184, @RenaudWasTaken)
非推奨(Deprecation)
- kubelet の非推奨エンドポイント
metrics/resource/v1alpha1
は削除されました。metrics/resource
エンドポイントを利用してください(#94272, @RainbowMango)- 取得できるメトリクスは同じです。
機能追加(Feature)
component-base
-
--experimental-logging-sanitization
フラグが追加されました。ログからの機密データ漏洩を低減します(#96370, @serathius)。
kube-scheduler
- kube-scheduler の
/metrics/resources
エンドポイントからメトリクスが取得できるようなりました。このメトリクスを利用することで、管理者は Resource の状態(Pod 上のすべての Resource Requests と Resource Limits)を簡単に確認し、実際に Pod が利用している Resource 使用量、または Node Capacity と比較できます(#94866, @smarterclayton)。
終わりに
KEP-1748: Expose Pod Resource Request Metrics で 、Ephemeral Storage の対応が書かれていないので、kube-state-metrics からの移行には課題がありそうです。
他には、現在作業が進められている KEP: Dynamic Cardinality Enforcement があります。これは私自身何度も苦しめられたことがある、メトリクスによる Memory Leak について検討している KEP です。Allow List を定義する方法は骨が折れる作業ですが、どのような結果になるか楽しみです。