LoginSignup
9
5

More than 1 year has passed since last update.

Kubernetes 1.22: Metrics Changes と SIG Instrumentation の変更内容

Last updated at Posted at 2021-08-20

はじめに

ここでは、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 のため、デフォルトでは無効となっています。

FeatureGate 名からも分かるとおり、kube-apiserver コンポーネントの分散トレーシング機能のため、kube-controller-manager コンポーネントなど、他のコンポーネントは対象外です。

kube-apiserver へのリクエスト処理をデバッグするために v1.21 以前でも簡易的なトレース機能はありました。ですが、OpenTelemetry Trace の仕様を利用することで、既存のエコシステムが利用できます。この標準的な仕様を利用することでより使いやすく、より分析が容易となる環境が構築できます。またこの取り組みにより Admission Webhooks などにコンテキストを伝播することで、kube-apiserver へのリクエストに紐つけたトレースデータを収集できるようになります(私は未確認です :pray:)。

トレースしたデータは、kube-apiserver に設定されたエンドポイントへ、OpenTelemetry Protocol (OTLP)/gRPC を使って送信されます。今回は OpenTelemetry Collector を利用し Jaeger で、kube-apiserver のトレーシングデータを確認していきます。他にも、OTLP/gRPC、または OpenTelemetry Collector の Exporter として対応したクラウドのサービスであれば、バックエンドストアとして活用できます。

まずは kind でクラスタ作成するための設定ファイルを作成します。
分散トレーシングを利用するためには、FeatureGate 以外にも kube-apiserver の引数で設定ファイルを指定します。私の環境の場合、ローカル PC(macOS)で作成した設定ファイルを Node と Pod に参照させるため、次のような設定ファイルとなります。

config.yaml
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 に指定する分散トレーシングの設定ファイルを作成します。

config.yaml
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
otel-collector.yaml
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
jaeger.yaml
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(最も古くから待っているリクエスト)から処理中の推定値を減算した最小値と最大値
  • 認証ロジックを 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 リクエストの処理時間
  • 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

kubelet

  • kubelet の /metrics/resource エンドポイントにコンテナの起動時刻を記録します(#102444, @￰sanwishe)
    • Gauge: container_start_time_seconds
    • Labels: ["container", "pod", "namespace"]

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"]

component-base

  • component-base に クライアントサイドの Rate Limiter のレイテンシーを記録するメトリクスを追加しました(#100311, @￰IonutBajescu)
    • Histogram: rest_client_rate_limiter_duration_seconds
      • Labels: ["verb", "url"]

変更

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]
  • 次のメトリクスの StabilityLevel が Stable になりました(#100754, @￰liggitt)
    • Gauge: apiserver_requested_deprecated_apis

修正

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"]

メトリクス以外の変更

機能追加(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 というキーで記録するようになりました :tada: (#102437, @￰MadhavJivrajani)
    • ex) {"ts":1629262280084.1306,"caller":"kubelet/kubelet.go:2149","msg":"SyncLoop (housekeeping) end","v":4}
  • 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)
9
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
5