

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# コントロールプレーンのモニタリング
<a name="control_plane_monitoring"></a>

## API サーバー
<a name="_api_server"></a>

API サーバーを見るときは、その関数の 1 つがインバウンドリクエストをスロットリングしてコントロールプレーンの過負荷を防ぐことを覚えておくことが重要です。API サーバーレベルでボトルネックのように見えるものは、実際にはより深刻な問題から保護している可能性があります。システムを移動するリクエストの量を増やすことの長所と短所を考慮する必要があります。API サーバーの値を増やす必要があるかどうかを判断するために、注意すべき事項の小さなサンプリングを次に示します。

1. システムを通過するリクエストのレイテンシーはどれくらいですか?

1. このレイテンシーは API サーバー自体ですか、それとも etcd のような「ダウンストリーム」ですか?

1. API サーバーキューの深さはこのレイテンシーの要因ですか?

1. API Priority and Fairness (APF) キューは、必要な API コールパターンに対して正しく設定されていますか?

## 問題はどこにありますか?
<a name="_where_is_the_issue"></a>

まず、 API レイテンシーの メトリクスを使用して、API サーバーがサービスリクエストにどれだけかかるかを把握できます。以下の PromQL と Grafana ヒートマップを使用して、このデータを表示しましょう。

```
max(increase(apiserver_request_duration_seconds_bucket{subresource!="status",subresource!="token",subresource!="scale",subresource!="/healthz",subresource!="binding",subresource!="proxy",verb!="WATCH"}[$__rate_interval])) by (le)
```

**注記**  
この記事で使用されている API ダッシュボードを使用して API サーバーをモニタリングする方法の詳細については、次の[ブログ](https://aws.amazon.com/blogs/containers/troubleshooting-amazon-eks-api-servers-with-prometheus/)を参照してください。

![API リクエスト期間ヒートマップ](http://docs.aws.amazon.com/ja_jp/eks/latest/best-practices/images/scalability/api-request-duration.png)


これらのリクエストはすべて 1 秒単位です。これは、コントロールプレーンがリクエストをタイムリーに処理していることを示しています。しかし、そのようにならなかったらどうでしょうか。

上記の API リクエスト期間で使用している形式はヒートマップです。ヒートマップ形式の良い点は、デフォルトで API のタイムアウト値 (60 秒) を示すことです。ただし、実際に知っておく必要があるのは、タイムアウトしきい値に達する前に、この値をどのしきい値にする必要があるかということです。許容されるしきい値の大まかなガイドラインについては、[こちら](https://github.com/kubernetes/community/blob/master/sig-scalability/slos/slos.md#steady-state-slisslos)にあるアップストリーム Kubernetes SLO を使用できます。

**注記**  
このステートメントの最大関数に注目しますか? 複数のサーバー (デフォルトでは EKS 上の 2 つの API サーバー) を集約するメトリクスを使用する場合は、それらのサーバーをまとめて平均化しないことが重要です。

### 非対称トラフィックパターン
<a name="_asymmetrical_traffic_patterns"></a>

1 つの API サーバー [pod] が軽くロードされ、もう 1 つの API サーバーが頻繁にロードされた場合どうなりますか? この 2 つの数値を一緒に平均すると、何が起こっているかを誤って解釈する可能性があります。たとえば、3 つの API サーバーがありますが、すべての負荷はこれらの API サーバーの 1 つにあります。スケールとパフォーマンスの問題を投資するときは、原則として、 etcd サーバーや API サーバーなど、複数のサーバーを持つものをすべて分割する必要があります。

![処理中のリクエストの合計数](http://docs.aws.amazon.com/ja_jp/eks/latest/best-practices/images/scalability/inflight-requests.png)


API Priority and Fairness への移行では、システム上のリクエストの総数は、API サーバーがオーバーサブスクライブされているかどうかを確認する 1 つの要素にすぎません。システムは一連のキューで動作するようになったため、これらのキューのいずれかが満杯かどうか、およびそのキューのトラフィックがドロップされているかどうかを確認する必要があります。

次のクエリを使用して、これらのキューを見てみましょう。

```
max without(instance)(apiserver_flowcontrol_nominal_limit_seats{})
```

**注記**  
API A&F の仕組みの詳細については、以下の[ベストプラクティスガイド](https://docs.aws.amazon.com/eks/latest/best-practices/scale-control-plane.html#_api_priority_and_fairness)を参照してください。

ここでは、デフォルトでクラスターに表示される 7 つの異なる優先度グループを示します。

![共有同時実行数](http://docs.aws.amazon.com/ja_jp/eks/latest/best-practices/images/scalability/shared-concurrency.png)


次に、その優先度グループの何パーセントが使用されているかを確認し、特定の優先度レベルが飽和しているかどうかを理解できるようにします。ワークロードの低いレベルでリクエストをスロットリングするのが望ましいかもしれませんが、リーダー選挙レベルの低下は望ましくないでしょう。

API Priority and Fairness (APF) システムには多くの複雑なオプションがあり、これらのオプションの一部は意図しない結果をもたらす可能性があります。フィールドに表示される一般的な問題は、キューの深さを、不要なレイテンシーの追加を開始する時点まで増やすことです。この問題は、 `apiserver_flowcontrol_current_inqueue_request`メトリクスを使用してモニタリングできます。を使用してドロップを確認できます`apiserver_flowcontrol_rejected_requests_total`。これらのメトリクスは、バケットが同時実行数を超えた場合、ゼロ以外の値になります。

![使用中のリクエスト](http://docs.aws.amazon.com/ja_jp/eks/latest/best-practices/images/scalability/requests-in-use.png)


キューの深さを増やすと、API Server がレイテンシーの大きな原因になる可能性があるため、注意が必要です。作成されたキューの数を慎重に検討することをお勧めします。たとえば、EKS システム上の共有数は 600 です。キューの作成数が多すぎると、リーダー選択キューやシステムキューなどのスループットを必要とする重要なキューの共有を減らすことができます。余分なキューを作成すると、キューのサイズを正しく設定することが困難になる可能性があります。

APF で実行できる単純な影響のある変更に集中するには、使用率の低いバケットから共有を取得し、最大使用量のバケットのサイズを増やします。これらのバケット間で共有をインテリジェントに再分散することで、ドロップの可能性を減らすことができます。

詳細については、「EKS ベストプラクティスガイド」の[「API Priority and Fairness settings](https://docs.aws.amazon.com/eks/latest/best-practices/scale-control-plane.html#_api_priority_and_fairness)」を参照してください。

### API と etcd のレイテンシー
<a name="_api_vs_etcd_latency"></a>

API サーバーのメトリクス/ログを使用して、API サーバーに問題があるか、API サーバーのアップストリーム/ダウンストリームに問題があるか、またはその両方の組み合わせであるかどうかを判断する方法。これをよりよく理解するために、API Server と etcd の関連性と、間違ったシステムのトラブルシューティングがどれほど簡単かを見てみましょう。

次の図では、API サーバーのレイテンシーを示していますが、グラフのバーにレイテンシーのほとんどが etcd レベルで表示されるため、このレイテンシーの大部分は etcd サーバーと相関しています。同時に 15 秒の etcd レイテンシーがあり、同時に 20 秒の API サーバーのレイテンシーがある場合、レイテンシーの大部分は実際には etcd レベルになります。

フロー全体を見ると、API Server のみに焦点を当てるのではなく、etcd が圧縮されている (適用カウンターが遅くなる) ことを示すシグナルを探すことが賢明であることがわかります。一目で適切な問題領域にすばやく移動できるため、ダッシュボードが強力になります。

**注記**  
セクションのダッシュボードは、https://github.com/RiskyAdventure/Troubleshooting-Dashboards/blob/main/api-troubleshooter.json にあります。

![ETCD の圧縮](http://docs.aws.amazon.com/ja_jp/eks/latest/best-practices/images/scalability/etcd-duress.png)


### コントロールプレーンとクライアント側の問題
<a name="_control_plane_vs_client_side_issues"></a>

このグラフでは、その期間に完了するのに最も時間がかかった API コールを探しています。この場合、カスタムリソース (CRD) が 05:40 の間に最も潜在的な呼び出しである APPLY 関数を呼び出していることがわかります。

![最も遅いリクエスト](http://docs.aws.amazon.com/ja_jp/eks/latest/best-practices/images/scalability/slowest-requests.png)


このデータを使用して、Ad-Hoc PromQL または CloudWatch Insights クエリを使用して、その期間中に監査ログから LIST リクエストをプルし、これがどのアプリケーションであるかを確認できます。

### CloudWatch を使用したソースの検索
<a name="_finding_the_source_with_cloudwatch"></a>

メトリクスは、調査する問題領域を見つけ、問題の時間枠と検索パラメータの両方を絞り込むのに最適です。このデータを取得したら、より詳細な時間とエラーのログに移行します。これを行うには、[CloudWatch Logs Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AnalyzingLogData.html) を使用してログをメトリクスに変換します。

例えば、上記の問題を調査するために、次の CloudWatch Logs Insights クエリを使用して userAgent と requestURI をプルし、このレイテンシーの原因となっているアプリケーションをピンダウンできるようにします。

**注記**  
Watch で通常のリスト/再同期動作をプルしないようにするには、 として適切なカウントを使用する必要があります。

```
fields @timestamp, @message
| filter @logStream like "kube-apiserver-audit"
| filter ispresent(requestURI)
| filter verb = "list"
| parse requestReceivedTimestamp /\d+-\d+-(?<StartDay>\d+)T(?<StartHour>\d+):(?<StartMinute>\d+):(?<StartSec>\d+).(?<StartMsec>\d+)Z/
| parse stageTimestamp /\d+-\d+-(?<EndDay>\d+)T(?<EndHour>\d+):(?<EndMinute>\d+):(?<EndSec>\d+).(?<EndMsec>\d+)Z/
| fields (StartHour * 3600 + StartMinute * 60 + StartSec + StartMsec / 1000000) as StartTime, (EndHour * 3600 + EndMinute * 60 + EndSec + EndMsec / 1000000) as EndTime, (EndTime - StartTime) as DeltaTime
| stats avg(DeltaTime) as AverageDeltaTime, count(*) as CountTime by requestURI, userAgent
| filter CountTime >=50
| sort AverageDeltaTime desc
```

このクエリを使用すると、2 つの異なるエージェントが多数の高レイテンシーリストオペレーションを実行していることがわかりました。Splunk および CloudWatch エージェント。データを使用して、このコントローラーを削除、更新、または別のプロジェクトに置き換えることができます。

![クエリ結果](http://docs.aws.amazon.com/ja_jp/eks/latest/best-practices/images/scalability/query-results.png)


**注記**  
このトピックの詳細については、次の[ブログ](https://aws.amazon.com/blogs/containers/troubleshooting-amazon-eks-api-servers-with-prometheus/)を参照してください。

## スケジューラー
<a name="_scheduler"></a>

EKS コントロールプレーンインスタンスは別の AWS アカウントで実行されるため、これらのコンポーネントをメトリクス用にスクレイピングすることはできません (API サーバーは例外です）。ただし、これらのコンポーネントの監査ログにアクセスできるため、これらのログをメトリクスに変換して、いずれかのサブシステムがスケーリングのボトルネックを引き起こしているかどうかを確認することができます。CloudWatch Logs Insights を使用して、スケジューラキューにあるスケジュールされていないポッドの数を確認しましょう。

### スケジューラログのスケジュールされていないポッド
<a name="_unscheduled_pods_in_the_scheduler_log"></a>

セルフマネージド Kubernetes (Kops など) でスケジューラメトリクスを直接スクレイプするアクセス権がある場合、次の PromQL を使用してスケジューラのバックログを理解します。

```
max without(instance)(scheduler_pending_pods)
```

EKS では上記のメトリクスにアクセスできないため、以下の CloudWatch Logs Insights クエリを使用して、特定の期間中にスケジュールできなかったポッドの数を確認してバックログを確認します。その後、ピーク時にメッセージをさらに詳しく調べて、ボトルネックの性質を理解できます。例えば、ノードが十分に速くスピンアップしない、またはスケジューラ自体のレートリミッターなどです。

```
fields timestamp, pod, err, @message
| filter @logStream like "scheduler"
| filter @message like "Unable to schedule pod"
| parse @message  /^.(?<date>\d{4})\s+(?<timestamp>\d+:\d+:\d+\.\d+)\s+\S*\s+\S+\]\s\"(.*?)\"\s+pod=(?<pod>\"(.*?)\")\s+err=(?<err>\"(.*?)\")/
| count(*) as count by pod, err
| sort count desc
```

ここでは、ストレージ PVC が使用できなかったためにポッドがデプロイされなかったというスケジューラのエラーが表示されます。

![CloudWatch Logs クエリ](http://docs.aws.amazon.com/ja_jp/eks/latest/best-practices/images/scalability/cwl-query.png)


**注記**  
この関数を有効にするには、コントロールプレーンで監査ログ記録を有効にする必要があります。また、時間の経過とともにコストが不必要に増加しないように、ログの保持を制限することもベストプラクティスです。以下の EKSCTL ツールを使用してすべてのログ記録機能を有効にする例。

```
cloudWatch:
  clusterLogging:
    enableTypes: ["*"]
    logRetentionInDays: 10
```

## Kube コントローラーマネージャー
<a name="_kube_controller_manager"></a>

Kube Controller Manager には、他のすべてのコントローラーと同様に、一度に実行できるオペレーションの数に制限があります。これらのパラメータを設定できる KOPS 設定を見て、これらのフラグの一部を確認しましょう。

```
  kubeControllerManager:
    concurrentEndpointSyncs: 5
    concurrentReplicasetSyncs: 5
    concurrentNamespaceSyncs: 10
    concurrentServiceaccountTokenSyncs: 5
    concurrentServiceSyncs: 5
    concurrentResourceQuotaSyncs: 5
    concurrentGcSyncs: 20
    kubeAPIBurst: 30
    kubeAPIQPS: "20"
```

これらのコントローラーには、クラスターの解約率が高いときにいっぱいになるキューがあります。この場合、レプリカセットセットコントローラーのキューに大きなバックログがあります。

![[キュー]](http://docs.aws.amazon.com/ja_jp/eks/latest/best-practices/images/scalability/queues.png)


このような状況に対処するには、2 つの異なる方法があります。セルフマネージドを実行すると、同時ゴルーチンを増やすことができますが、KCM でより多くのデータを処理することで etcd に影響します。もう 1 つのオプションは、デプロイ`.spec.revisionHistoryLimit`で を使用するレプリカセットオブジェクトの数を減らして、ロールバックできるレプリカセットオブジェクトの数を減らし、このコントローラーの負荷を軽減することです。

```
spec:
  revisionHistoryLimit: 2
```

他の Kubernetes 機能は、高チャーンレートシステムの負荷を軽減するために調整またはオフにすることができます。たとえば、ポッド内のアプリケーションが k8s API に直接話す必要がない場合、それらのポッドに射影されたシークレットをオフにすると、ServiceaccountTokenSyncs の負荷が軽減されます。これは、可能であればこのような問題に対処するより望ましい方法です。

```
kind: Pod
spec:
  automountServiceAccountToken: false
```

メトリクスにアクセスできないシステムでは、ログを再度確認して競合を検出できます。コントローラーごとまたは集計レベルで処理されているリクエストの数を確認するには、次の CloudWatch Logs Insights クエリを使用します。

### KCM によって処理された合計ボリューム
<a name="_total_volume_processed_by_the_kcm"></a>

```
# Query to count API qps coming from kube-controller-manager, split by controller type.
# If you're seeing values close to 20/sec for any particular controller, it's most likely seeing client-side API throttling.
fields @timestamp, @logStream, @message
| filter @logStream like /kube-apiserver-audit/
| filter userAgent like /kube-controller-manager/
# Exclude lease-related calls (not counted under kcm qps)
| filter requestURI not like "apis/coordination.k8s.io/v1/namespaces/kube-system/leases/kube-controller-manager"
# Exclude API discovery calls (not counted under kcm qps)
| filter requestURI not like "?timeout=32s"
# Exclude watch calls (not counted under kcm qps)
| filter verb != "watch"
# If you want to get counts of API calls coming from a specific controller, uncomment the appropriate line below:
# | filter user.username like "system:serviceaccount:kube-system:job-controller"
# | filter user.username like "system:serviceaccount:kube-system:cronjob-controller"
# | filter user.username like "system:serviceaccount:kube-system:deployment-controller"
# | filter user.username like "system:serviceaccount:kube-system:replicaset-controller"
# | filter user.username like "system:serviceaccount:kube-system:horizontal-pod-autoscaler"
# | filter user.username like "system:serviceaccount:kube-system:persistent-volume-binder"
# | filter user.username like "system:serviceaccount:kube-system:endpointslice-controller"
# | filter user.username like "system:serviceaccount:kube-system:endpoint-controller"
# | filter user.username like "system:serviceaccount:kube-system:generic-garbage-controller"
| stats count(*) as count by user.username
| sort count desc
```

ここで重要なのは、スケーラビリティの問題を調べるとき、詳細なトラブルシューティングフェーズに進む前に、パスのすべてのステップ (API、スケジューラ、KCM など) を調べることです。多くの場合、本番環境では、Kubernetes の複数の部分を調整して、システムが最もパフォーマンスの高い機能を発揮できるようにします。はるかに大きなボトルネックの単なる症状 (ノードタイムアウトなど) を誤ってトラブルシューティングするのは簡単です。

## ETCD
<a name="_etcd"></a>

etcd はメモリマップファイルを使用してキーと値のペアを効率的に保存します。2、4、8GB の制限で一般的に設定されるこのメモリ容量のサイズを設定する保護メカニズムがあります。データベース内のオブジェクトが少ないということは、オブジェクトが更新され、古いバージョンをクリーンアウトする必要がある場合に行う必要があるクリーンアップ etcd が少なくなることを意味します。オブジェクトの古いバージョンをクリーンアウトするこのプロセスは、圧縮と呼ばれます。多数の圧縮操作の後、デフラグと呼ばれる使用可能なスペースを回復する後続のプロセスがあり、特定のしきい値を超えるか、一定のスケジュールで発生します。

Kubernetes 内のオブジェクトの数を制限し、圧縮とデフラグの両方のプロセスの影響を減らすために実行できるユーザー関連の項目がいくつかあります。たとえば、Helm は高い を保持します`revisionHistoryLimit`。これにより、システム上の ReplicaSets などの古いオブジェクトがロールバックを実行できるようになります。履歴制限を 2 に設定することで、オブジェクト (ReplicaSets など) の数を 10 個から 2 個に減らすことができ、システムへの負荷を軽減できます。

```
apiVersion: apps/v1
kind: Deployment
spec:
  revisionHistoryLimit: 2
```

モニタリングの観点から、システムレイテンシーのスパイクが時間で区切られたセットパターンで発生した場合は、このデフラグプロセスがソースであるかどうかをチェックすると便利です。これは CloudWatch Logs を使用して確認できます。

デフラグの開始/終了時刻を確認するには、次のクエリを使用します。

```
fields @timestamp, @message
| filter @logStream like /etcd-manager/
| filter @message like /defraging|defraged/
| sort @timestamp asc
```

![クエリのデフラグ](http://docs.aws.amazon.com/ja_jp/eks/latest/best-practices/images/scalability/defrag.png)
