皆さん、こんにちは!本日は、Google Kubernetes Engine を使用して Kubernetes クラスタを管理した経験を共有したいと思います。過去 3 年間、本番環境で使用してきましたが、これらのクラスターを自分で管理することを心配する必要がなくなったことを嬉しく思います。
現在、すべてのテスト環境と独自のインフラストラクチャ クラスターが Kubernetes の制御下にあります。今日は、テスト クラスターで問題が発生した経緯と、この記事が他の人の時間と労力を節約できることを願っていることについてお話ししたいと思います。
問題を完全に理解するには、テスト インフラストラクチャに関する情報を提供する必要があります。 5 つ以上の恒久的なテスト環境があり、要求に応じて開発者向けの環境を展開しています。平日のモジュール数は日中に 6000 に達し、増加し続けています。負荷が不安定なため、モジュールを非常に密集してコストを節約し、リソースを再販することが最善の戦略です。
この構成は、アラートを受け取って名前空間を削除できなかったある日まで、うまく機能していました。名前空間の削除に関して受け取ったエラー メッセージは次のとおりです。
$ kubectl delete namespace arslanbekov Error from server (Conflict): Operation cannot be fulfilled on namespaces "arslanbekov": The system is ensuring all content is removed from this namespace. Upon completion, this namespace will automatically be purged by the system.
強制削除オプションを使用しても問題は解決しませんでした:
$ kubectl get namespace arslanbekov -o yaml apiVersion: v1 kind: Namespace metadata: ... spec: finalizers: - kubernetes status: phase: Terminating
動かなくなった名前空間の問題を解決するために、 ガイドに従いました。それでも、開発者は名前空間の抽象化を使用して環境を自由に作成および削除できるはずだったため、この一時的なソリューションは理想的ではありませんでした。
より良い解決策を見つけようと決心したため、さらに調査することにしました。アラートはメトリックの問題を示しており、次のコマンドを実行して確認しました。
$ kubectl api-resources --verbs=list --namespaced -o name error: unable to retrieve the complete list of server APIs: metrics.k8s.io/v1beta1: the server is currently unable to handle the request
metrics-server ポッドでメモリ不足 (OOM) エラーとパニック エラーがログに記録されていることがわかりました。
apiserver panic'd on GET /apis/metrics.k8s.io/v1beta1/nodes: killing connection/stream because serving request timed out and response had been started goroutine 1430 [running]:
理由は、ポッドのリソースの制限にありました。
コンテナーは、次のような定義が原因でこれらの問題に遭遇していました (制限ブロック)。
resources: limits: cpu: 51m memory: 123Mi requests: cpu: 51m memory: 123Mi
問題は、コンテナに51m CPUしか割り当てられていないことでした。これは、 1 つのコア CPU の 0.05にほぼ相当し、これは非常に多数のポッドのメトリクスを処理するには不十分でした。主に CFS スケジューラが使用されます。
通常、このような問題の修正は簡単で、Pod により多くのリソースを割り当てるだけです。ただし、GKE では、このオプションは UI や gcloud CLI では使用できません。これは、Google がシステム リソースが変更されないように保護しているためです。これは、すべての管理が Google 側で行われていることを考えると理解できます。
この問題に直面しているのは私たちだけではないことを発見し、作成者がポッド定義を手動で変更しようとした同様の問題を発見しました。彼は成功しましたが、私たちは成功しませんでした。 YAML ファイルでリソース制限を変更しようとすると、GKE はすぐにそれらをロールバックしました。
別の解決策を見つける必要がありました。
最初のステップは、リソース制限がこれらの値に設定された理由を理解することでした。 Pod は、 metrics-server
とaddon-resizer
2 つのコンテナーで構成されていました。後者は、ノードがクラスターに追加またはクラスターから削除されたときにリソースを調整し、クラスターの垂直自動スケーリングの世話人のように機能しました。
コマンドラインの定義は次のとおりです。
command: - /pod_nanny - --config-dir=/etc/config - --cpu=40m - --extra-cpu=0.5m - --memory=35Mi - --extra-memory=4Mi ...
この定義では、CPU とメモリはベースライン リソースを表し、 extra-cpu
とextra-memory
ノードごとの追加リソースを表します。 180 ノードの計算は次のようになります。
0.5m * 180 + 40m=~130m
同じロジックがメモリ リソースに適用されます。
残念ながら、リソースを増やす唯一の方法はノードを追加することでしたが、これはやりたくありませんでした。そこで、他のオプションを検討することにしました。
問題を完全に解決することはできませんが、展開をできるだけ早く安定させたいと考えていました。 YAML 定義の一部のプロパティは、GKE によってロールバックされずに変更できることがわかりました。これに対処するために、レプリカの数を 1 から 5 に増やし、ヘルス チェックを追加し、 この記事に従ってロールアウト戦略を調整しました。
これらのアクションは、メトリクス サーバー インスタンスの負荷を軽減するのに役立ち、メトリクスを提供できる動作中のポッドが常に少なくとも 1 つあることを確認しました。私たちは時間をかけて問題を再考し、考えを新たにしました。解決策は、振り返ってみるとシンプルで明白なものになりました。
addon-resizer の内部を詳しく調べたところ、構成ファイルとコマンド ライン パラメーターを使用して構成できることがわかりました。一見すると、コマンド ライン パラメーターで設定値をオーバーライドする必要があるように見えましたが、そうではありませんでした。
調査の結果、構成ファイルが addon-resizer コンテナーのコマンド ライン パラメーターを介して Pod に接続されていることがわかりました。
--config-dir=/etc/config
構成ファイルは、システムの名前空間でmetrics-server-config
という名前の ConfigMap としてマッピングされており、GKE はこの構成をロールバックしません。
次のように、この構成を介してリソースを追加しました。
apiVersion: v1 data: NannyConfiguration: |- apiVersion: nannyconfig/v1alpha1 kind: NannyConfiguration baseCPU: 100m cpuPerNode: 5m baseMemory: 100Mi memoryPerNode: 5Mi kind: ConfigMap metadata:
そしてそれは働いた!これは私たちにとって勝利でした。
クラスターのサイズを変更している間、ヘルス チェックとゼロ ダウンタイム戦略を備えた 2 つのポッドを残しましたが、これらの変更を行った後、アラートを受け取ることはありませんでした。