はじめに
ここでは、Kubernetes v1.22 の CHANGELOG から Metrics の変更と SIG Instrumentation の取り組みについてまとめています。
今回 Kubernetes v1.22 で SIG Instrumentation が扱う主要なテーマはありませんが、注目すべき機能として Alpha feature の API Server Tracing
が記載されています。
API Server Tracing
======追記======
2021-09-03 に Etcd、Mutating Webhook のトレーシングを含めたブログが公式から出ています。
API Server Tracing については次のリンクを参照してみてください。
======追記終わり======
API Server Tracing
は Kubernetes v1.22 から利用できるようになった FeatureGate です。ステージは Alpha のため、デフォルトでは無効となっています。
- enhancements/keps/sig-instrumentation/647-apiserver-tracing · kubernetes/enhancements
- Traces For Kubernetes System Components | Kubernetes
FeatureGate 名からも分かるとおり、kube-apiserver コンポーネントの分散トレーシング機能のため、kube-controller-manager コンポーネントなど、他のコンポーネントは対象外です。
kube-apiserver へのリクエスト処理をデバッグするために v1.21 以前でも簡易的なトレース機能はありました。ですが、OpenTelemetry Trace の仕様を利用することで、既存のエコシステムが利用できます。この標準的な仕様を利用することでより使いやすく、より分析が容易となる環境が構築できます。またこの取り組みにより Admission Webhooks などにコンテキストを伝播することで、kube-apiserver へのリクエストに紐つけたトレースデータを収集できるようになります(私は未確認です )。
トレースしたデータは、kube-apiserver に設定されたエンドポイントへ、OpenTelemetry Protocol (OTLP)/gRPC を使って送信されます。今回は OpenTelemetry Collector を利用し Jaeger で、kube-apiserver のトレーシングデータを確認していきます。他にも、OTLP/gRPC、または OpenTelemetry Collector の Exporter として対応したクラウドのサービスであれば、バックエンドストアとして活用できます。
まずは kind でクラスタ作成するための設定ファイルを作成します。
分散トレーシングを利用するためには、FeatureGate 以外にも kube-apiserver の引数で設定ファイルを指定します。私の環境の場合、ローカル PC(macOS)で作成した設定ファイルを Node と Pod に参照させるため、次のような設定ファイルとなります。
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraMounts:
- hostPath: __current_dir_path__/tracing # __current_dir_path__ はローカル PC(macOS)の作業パスを指定
containerPath: /tracing # Node のマウント先
kubeadmConfigPatches:
- |
kind: ClusterConfiguration
metadata:
name: config
apiServer:
extraVolumes:
- name: api-server
hostPath: /tracing
mountPath: /tracing
extraArgs:
tracing-config-file: /tracing/config.yaml
featureGates:
"APIServerTracing": true
次に、kube-apiserver の引数オプション --tracing-config-file
に指定する分散トレーシングの設定ファイルを作成します。
apiVersion: apiserver.config.k8s.io/v1alpha1
kind: TracingConfiguration
# 後ほど作成する ClusterIP をエンドポイントとして設定します
# フォーマットには [RPC Name Resolution](https://github.com/grpc/grpc/blob/master/doc/naming.md) が利用できます
endpoint: 10.96.176.117:4317
# 100 万ごとのサンプリング数を設定します。今回はテストのため全ての処理をトレーシングします
# デフォルト値は 0 となります
samplingRatePerMillion: 1000000
作成した設定ファイルを元に、Kubernetes v1.22.0 でクラスタを作成します。
$ kind create cluster --config=config.yaml --image kindest/node:v1.22.0 --name kind-1.22
Creating cluster "kind-1.22" ...
✓ Ensuring node image (kindest/node:v1.22.0) 🖼
✓ Preparing nodes 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
Set kubectl context to "kind-kind-1.22"
You can now use your cluster with:
kubectl cluster-info --context kind-kind-1.22
Have a nice day! 👋
クラスタが作成できたら、OpenTelemetry Collector と Jaeger をデプロイします。
トレースデータは次のように送信され、Jaeger の Web UI でトレーシングしたデータを確認できます。
kube-apiserver => OpenTelemetry Collector => Jaeger
OpenTelemetry Collector
apiVersion: v1
kind: ConfigMap
metadata:
name: otel-collector-conf
labels:
app: opentelemetry
component: otel-collector-conf
data:
otel-collector-config: |
receivers:
otlp:
protocols:
grpc:
http:
processors:
batch:
memory_limiter:
ballast_size_mib: 683
limit_mib: 1500
spike_limit_mib: 512
check_interval: 5s
extensions:
health_check: {}
zpages: {}
exporters:
jaeger:
endpoint: "jaeger-collector.kube-system.svc.cluster.local:14250"
insecure: true
service:
extensions: [health_check, zpages]
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter, batch]
exporters: [jaeger]
---
apiVersion: v1
kind: Service
metadata:
name: otel-collector
labels:
app: opentelemetry
component: otel-collector
spec:
type: ClusterIP
clusterIP: 10.96.176.117
clusterIPs:
- 10.96.176.117
ports:
- name: otlp
port: 4317
protocol: TCP
targetPort: 4317
selector:
component: otel-collector
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: otel-collector
labels:
app: opentelemetry
component: otel-collector
spec:
selector:
matchLabels:
app: opentelemetry
component: otel-collector
replicas: 1
template:
metadata:
labels:
app: opentelemetry
component: otel-collector
spec:
containers:
- command:
- "/otelcol"
- "--config=/conf/otel-collector-config.yaml"
- "--mem-ballast-size-mib=683"
image: ghcr.io/watawuwu/opentelemetry-collector-dev:test
name: otel-collector
ports:
- containerPort: 4317
volumeMounts:
- name: otel-collector-config
mountPath: /conf
livenessProbe:
httpGet:
path: /
port: 13133
readinessProbe:
httpGet:
path: /
port: 13133
volumes:
- name: otel-collector-config
configMap:
name: otel-collector-conf
items:
- key: otel-collector-config
path: otel-collector-config.yaml
$ kubectl -n kube-system apply -f otel-collector.yaml
configmap/otel-collector-conf created
service/otel-collector created
deployment.apps/otel-collector created
Jaeger
apiVersion: apps/v1
kind: Deployment
metadata:
name: jaeger
labels:
app.kubernetes.io/name: jaeger
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app.kubernetes.io/name: jaeger
template:
metadata:
labels:
app.kubernetes.io/name: jaeger
spec:
containers:
- image: jaegertracing/all-in-one
name: jaeger
ports:
- containerPort: 16686
protocol: TCP
- containerPort: 14250
protocol: TCP
readinessProbe:
httpGet:
path: "/"
port: 14269
initialDelaySeconds: 5
---
apiVersion: v1
kind: Service
metadata:
name: jaeger-query
labels:
app.kubernetes.io/name: jaeger-query
spec:
type: LoadBalancer
ports:
- name: query-http
port: 80
protocol: TCP
targetPort: 16686
selector:
app.kubernetes.io/name: jaeger
---
apiVersion: v1
kind: Service
metadata:
name: jaeger-collector
labels:
app.kubernetes.io/name: jaeger-collector
spec:
type: ClusterIP
ports:
- name: jaeger-collector-grpc
port: 14250
protocol: TCP
targetPort: 14250
selector:
app.kubernetes.io/name: jaeger
$ kubectl -n kube-system apply -f jaeger.yaml
deployment.apps/jaeger created
service/jaeger-query created
service/jaeger-collector created
トレーシング関連のコンポーネントをデプロイしたら、Jaeger の Jaeger UI に接続しトレーシングできていることを確認します。
$ kubectl -n kube-system port-forward svc/jaeger-query 8080:80 &
Forwarding from 127.0.0.1:8080 -> 16686
Forwarding from [::1]:8080 -> 16686
# ブラウザで http://localhost:8080 を確認してください(以下は macOS の例)
$ open http://localhost:8080
Jaeger UI の Service に apiserver が含まれていれば成功です。
試しに 1 つの Trace を参照してみると、kube-apiserver の呼び出しと etcd client の処理時間が計測されていることが確認できます。
これらの単体の処理時間はメトリクスでも確認できますが、Admission Webhooks などと連携したトレースデータを含め、1 つのトレース情報(コンテキスト)として参照できるのは嬉しいですね。
それでは恒例の Metrics Changes
について説明していきます。
メトリクスの変更
は、私が全ての変更点からメトリクスの変更に関連するものを抜粋した内容となります。
メトリクスの変更(Metrics Changes)
追加
kube-apiserver
- API Priority and Fairness のメトリクスを追加しました(#102859, @MikeSpreitzer)
- Gauge:
apiserver_flowcontrol_current_r
- Labels: ["priority_level"]
- Help: R(キューの状態が最後に変化したタイムスタンプ)
- Gauge:
apiserver_flowcontrol_dispatch_r
- Labels: ["priority_level"]
- Help: R(最新のリクエストが発信されたタイムスタンプ)
- Gauge:
apiserver_flowcontrol_latest_s
- Labels: ["priority_level"]
- Help: S(最後に発信されたリクエスト)
- Gauge:
apiserver_flowcontrol_next_s_bounds
- Labels: ["priority_level", "bound"]
- Help: キュー上で S(最も古くから待っているリクエスト)の最小値と最大値
- Gauge: apiserver_flowcontrol_next_discounted_s_bounds
- Labels: ["priority_level", "bound"]
- Help: キュー上で S(最も古くから待っているリクエスト)から処理中の推定値を減算した最小値と最大値
- Gauge:
- 認証ロジックを kube-apiserver に委譲する拡張 API で使用されるメトリクスを追加しました(#99364, #100339 @p0lyn0mial)
- Counter:
apiserver_delegated_authn_request_total
- Labels: ["code"]
- Help: 委譲された HTTP リクエスト数
- Histogram:
apiserver_delegated_authn_request_duration_seconds
- Labels: ["code"]
- Help: 委譲された HTTP リクエストの処理時間
- Counter:
apiserver_delegated_authz_request_total
- Labels: ["code"]
- Help: 委譲された HTTP リクエスト数
- Histogram:
apiserver_delegated_authz_request_duration_seconds
- Labels: ["code"]
- Help: 委譲された HTTP リクエストの処理時間
- Counter:
- SAN(Subject Alternative Names) を持たない証明書を使用する Webhooks/Aggregated API への接続数を記録します。将来的にホスト名の検証に CN(Common Names)は使用されなくなります。このメトリクスがゼロではない場合、将来的に機能しなくなる可能性があるため、SAN を持つ証明書に移行が必要です(#95396, @stlaz)。
- Counter:
apiserver_kube_aggregator_x509_missing_san_total
- Counter:
apiserver_webhooks_x509_missing_san_total
- Counter:
kubelet
- kubelet の
/metrics/resource
エンドポイントにコンテナの起動時刻を記録します(#102444, @sanwishe)- Gauge:
container_start_time_seconds
- Labels: ["container", "pod", "namespace"]
- Gauge:
kube-controller-manager
- Job が正常な状態で動作しているかどうかを監視します(#101292, @AliceZhang2016、#102022, @adtac)
- Histogram:
job_controller_job_sync_duration_seconds
- Labels: ["completion_mode", "result", "action"]
- Counter:
job_controller_job_sync_total
- Labels: ["completion_mode", "result", "action"]
- Counter:
job_controller_job_finished_total
- Labels: ["completion_mode", "result"]
- Histogram:
component-base
- component-base に クライアントサイドの Rate Limiter のレイテンシーを記録するメトリクスを追加しました(#100311, @IonutBajescu)
- Histogram:
rest_client_rate_limiter_duration_seconds
- Labels: ["verb", "url"]
- Histogram:
変更
kube-apiserver
- 次のメトリクスに
namespace
ラベルを追加し、*_duration_seconds
メトリクスにはバケットを追加しました(#101208, @voutcn)- Histogram:
apiserver_admission_*
- Labels: ["type", "operation", "rejected", "namespace"]
- Histogram:
apiserver_admission_*_duration_seconds
- Labels: ["type", "operation", "rejected", "namespace"]
- Buckets: [0.005, 0.025, 0.1, 0.5, 2.5, 5.0, 10.0]
- Histogram:
- 次のメトリクスの StabilityLevel が Stable になりました(#100754, @liggitt)
- Gauge:
apiserver_requested_deprecated_apis
- Gauge:
修正
kube-apiserver
- 次のメトリクスの Label 値に記録される値を修正しました。Namespaced な Object を GET した場合、
verb
にはLIST
ではなくGET
を、scope
にはnamespace
ではなくresource
となるように値を修正(#103565, @zhan849)- Gauge:
apiserver_longrunning_gauge
- Labels: ["verb", "group", "version", "resource", "subresource", "scope", "component"]
- Gauge:
apiserver_request_terminations_total
- Labels: ["verb", "group", "version", "resource", "subresource", "scope", "component", "code"]
- Gauge:
メトリクス以外の変更
機能追加(Feature)
-
APIServerTracing
FetureGate を有効にすると、kube-apiserver
で分散トレーシングの機能が利用できます(#94942, @dashpole)- FeatureGate: APIServerTracing, Stage: alpha, Since: 1.22
- kube-apiserver に
--tracing-config-file
のオプションが追加されています
- etcd クライアントの呼び出しから span を記録し、コンテキストを etcd に伝播します(#103216, @dashpole)
-
kube-apiserver
の分散トレーシングで、リエントラントな API リクエストをトレースできるようになりました(#103218, @dashpole)- リエントラントな API についてはこちらを参照してください
- JSON ロギングフォーマットは GA ではないため、component-base/logs ライブラリの JSON ロギングフォーマットのデフォルトを
text
に変更しました。コンポーネント作成者は必要に応じてロギングフォーマットをjson
に変更する必要があります(#102869, @mengjiao-liu)。
- Metrics server の nanny コンテナのポーリング周期を 5 分から 30 秒に変更し、Metrics server のスケーリングを高速化しました(#101869, @olagacek)
不具合の修正(Bug or Regression)
- controller-manager から insecure port が削除されたため、メトリクスのエンドポイントも secure port でアクセスする必要があります。メトリクスを取得するアプリケーションは、nonResourceURLs である
/metrics
へのアクセスが許可された専用のサービスアカウントを使用する必要があります(#96216, @knight42)。
-
DisableAcceleratorUsageMetrics
の FeatureGate を有効にした場合、cAdvisor を使って Accelerator メトリクスが収集されないように修正されました(#101712, @SergeyKanzhelev)
- [Addon] Metrics Server アドオンの addon-resizer コンテナのバージョンを 1.8.14 に更新しました(#103541, @jbartosik)
そのほか(Cleanup or Flake)
- JSON ロギングフォーマットが有効な場合は、
go.uber.org/zap
ロギングライブラリの機能である Sampling を無効化しました(#102620, @serathius)
- JSON ロギングフォーマットでソースコードの位置情報を
caller
というキーで記録するようになりました (#102437, @MadhavJivrajani)- ex)
{"ts":1629262280084.1306,"caller":"kubelet/kubelet.go:2149","msg":"SyncLoop (housekeeping) end","v":4}
- ex)
-
proxy/ipvs/proxier.go
のログを構造化ロギングに移行しました(#97796, @JornShen)
-
staging/src/k8s.io/apiserver/pkg/registry
のログを構造化ロギングに移行しました(#98287, @lala123912)
-
pkg/volume/plugins.go
の一部のログを構造化ロギングに移行しました(#101510, @huchengze)
-
pkg/volume/volume_linux.go
の一部のログを構造化ロギングに移行しました(#99566, @huchengze)