世界と神々を震撼させたKubernetesの大きなバグ

世界と神々を震撼させたKubernetesの大きなバグ

Kubernetes は 3 月に本番環境と非本番環境で完全にリリースされたため、デプロイメントの問題については一安心できると思いました。しかし、本番環境と非本番環境で断続的に奇妙な問題が見つかりました。今週3日間デバッグして、諦めかけた時に原因を見つけました。この欠陥は、GitHub の現在のマスター ブランチを含む、現在 (2018-5-23) までのすべての Kubernetes バージョンに影響します (以下の誇張された更新を参照)。その結果、特定の状況下では Kubernetes サービスがサービスを提供できなくなり、非常に悪い影響が生じます。

この問題の現象は、1 つ以上の Kubernetes サービスに対応する Kubernetes エンドポイントが数分から数十分の間消え、その後再び現れ、その後再び消えるというケースがあるというものです。 「kubectl get ep --all-namespaces」で継続的にクエリを実行すると、AGE が分単位の一部のエンドポイントが突然消えたり、AGE が約 1 分から突然減少したりすることが確認できます。エンドポイントが不安定になると、必然的に、対応する Kubernetes サービスが安定したサービスを提供できなくなります。誰かが Github で問題を報告しましたが、開発者はそれに気付かず、解決もしていません。

まず、Kubernetes の一般的な実装メカニズムについて説明します。これにより、次のケース解決プロセスを理解するのに役立ちます。

Kubernetes の実装原理は、CFengine、Ansible、Salt などの構成管理ツールと非常によく似ています。つまり、構成の収束です。つまり、予想される構成と実際の構成を常に比較し、実際の構成を修正して予想される構成に収束させます。

Kubernetes の主要なシステム サービスは、api-server、scheduler、controller-manager です。 api-server は、Kubernetes システムのアクセス ポイントとして、また etcd ストレージのプロキシ サーバーとして機能します。 Service、Deployment、ReplicaSet、DaemonSet、Pod、Endpoint、ConfigMap、Secret など、Kubernetes 内のすべてのリソース オブジェクトは、protobuf 形式でシリアル化され、api-server によって形式がチェックされた後、etcd に保存されます。これは「期待される構成」を記述するプロセスです。

コントローラー マネージャー サービスには、さまざまなリソース タイプに対応する多数のコントローラー インスタンスが含まれています。


v1.12.0-alpha.0/cmd/kube-controller-manager/app/controllermanager.go#L317

これらのコントローラーが行うことは収束です。api-server の watch API を介して間接的に etcd を監視し、etcd 内のデータの変更ログを収集し、変更された (ADD、DELETE、UPDATE を含む) リソース (つまり、予想される「構成」) を kubelet + Docker によって収集された情報 (実際の「構成」) と 1 つずつ比較して、差異を修正します。

たとえば、Pod リソースが etcd に追加されると、コントローラーはスケジューラーにスケジュールを要求し、次に kubelet に Pod の作成を要求します。サービス リソースが etcd から削除されると、対応するエンドポイント リソースも削除され、このエンドポイント削除操作は kube-proxy によって監視され、実際の iptables コマンドがトリガーされます。

コントローラが watch を介して変更ログを取得するのは、単なる実装の最適化であることに注意してください。すべてのリソース オブジェクトを定期的に取り出して、1 つずつ判断するわけではありません。クラスターの規模が大きい場合、このような完全な収束は非常に遅くなり、クラスターのスケジューリングと自己修復も非常に遅くなります。

全体像を理解していれば、エンドポイントが誤って削除された場所を簡単に見つけることができます。


v1.12.0-alpha.0/pkg/コントローラ/エンドポイント/endpoints_controller.go#L396

では、どのような状況で Services(namespace).Get(name) がエラーを返すのかという疑問が生じます。コメントから、サービスが削除されると、397 行目に移動して不要なエンドポイントが削除されることがわかります。エンドポイントはサービス用であり、サービスが存在しない場合はエンドポイントが存在する意味がないためです。

そこで疑問が生じます。 「kubectl get svc」を実行すると、問題発生期間中、サービス リソースは常に存在しており、再構築も新規展開も行われていないことがわかります。実際、数か月間にわたって多くのサービス リソースが作成されています。対応するエンドポイントが誤って削除され、再構築されるのはなぜですか?この問題は2か月間私を悩ませてきました。かなりの時間と脳細胞を費やしました。今日、諦めかけていた時に、突然大きな発見がありました。

自社で構築したKubernetesクラスタではX509認証とRBAC権限制御が有効になっているため、簡単に確認できるようkube-apiserverの監査ログを有効にしました。問題が発生すると、監査ログに特別なパターンが記録されます。


jq コマンドを使用して抽出された監査ログ スニペット

監査ログでは、各エンドポイントの削除と作成が発生する前に、「/api/v1/services...watch=true」の監視呼び出しが行われます。前述のように、コントローラー マネージャーは etcd 内のリソースの変更ログを継続的にクロールする必要があります。ここでの奇妙な問題は、この呼び出しの「resourceVersion=xxx」のバージョン値が変更されないままであることです。 resourceVersion が増加し続けているため、変更ログの最後からクロールし続けるべきではないでしょうか?

苦労して推測した後、ついに「変更ログをクロールする」コードを見つけました。


v1.12.0-alpha.0/ステージング/src/k8s.io/client-go/tools/cache/reflector.go#L394

上記のコードにおける resourceVersion の処理ロジックは、イベント リストをトラバースし、現在のイベントの「resourceVersion」フィールドをクロールする新しい「開始 resourceVersion」として取得することです。そのため、トラバースが完了した後、「開始 resourceVersion」は最後のイベントの「resourceVersion」であることは明らかです。

さて、イベント リストがどのようになっているか見てみましょう。上記の api-server リクエストをコピーすると確認できます。

  1. kubectl プロキシ
  2. curl -s localhost:8001/api/v1/services?resourceVersion=xxxx&timeoutSeconds=yyy&watch=t


/api/v1/services の出力は参考用です。上記の監査ログと同じ期間ではないことに注意してください。

resourceVersion が増加していないことは明らかです。

この非増分的な問題は、実は非常に簡単に理解できます。 ResourceVersion はイベントのシリアル番号ではなく、Kubernetes リソース自体のバージョン番号です。 etcd を Subversion と見なすと、どちらもグローバルに増加するバージョン番号を持ち、Kubernetes リソースは Subversion に保存されたファイルと見なします。ファイル A を svn リビジョン = 100 で保存すると、A のバージョンは 100 になります。その後、他のファイルへの変更を svn に送信し続け、特定のバージョンで A を削除します。この時点では、svn log で確認できる関連ファイルの「自身の最終変更バージョン」は増分ではなく、最初のエントリの「自身の最終変更バージョン」は 100 です。

つまり真実が明らかになったのです。 etcd の「changelog」をトラバースする reflector.go のコードは、イベント シーケンスの resourceVersion が増加していると誤って認識しますが、ほとんどの場合はこれが当てはまります。このコードは普遍的であり、すべてのリソースが影響を受けるため、非常に深刻なバグです。多くの人が報告しているのを見てきました (私自身も遭遇しました)。controller-manager がエラー「reflector.go:341] k8s.io/kubernetes/pkg/controller/bootstrap/bootstrapsigner.go:152: watch of *v1.ConfigMapended with: too old resource version:」を報告しています。これはおそらく、非常に古いリソース バージョンから etcd の「変更ログ」を誤ってクロールしているが、etcd は古すぎる変更ログをすでに「圧縮」しているために発生します。

***このバグをトリガーして回避する方法をまとめると次のようになります。

トリガー

Kubernetes サービス オブジェクトが次々に作成、削除、作成され、その後、「kubectl delete svc xxx」を使用して、作成時刻が古いサービスが削除されます。つまり、より小さい resourceVersion を持つレコードがサービス イベント リストの最後に挿入され、これにより、コントローラー マネージャーは、すでにクロールされているサービス イベント リストからクロールして再生し、その後、サービスの ADDED イベントと DELETED イベントを再生します。その結果、コントローラー マネージャー メモリにキャッシュされたサービス オブジェクトが削除され、EndpointController は「存在しない」サービスに対応するエンドポイントを削除します。

バイパス

docker restart を使用して kube-controller-manager コンテナを再起動し、イベント リスト *** の位置から強制的にクロールを開始します。

resourceVersion が etcd の最新のグローバル バージョン番号となるサービスを作成します。この ADDED イベントはイベント リストの最後に表示されるため、コントローラー マネージャーはこの最新のリソース バージョンからクロールを開始します。

「kubectl edit」を使用してサービスを変更し、意味のないラベルなどを追加して保存します。これにより、リソース バージョンも更新されます。原理は以前の回避策と同じです。

間違った方向

  • 「kubectl delete pod/xxx」: サービスイベントリストには影響しません
  • 「kubectl delete deploy/xxxx」: サービスイベントリストには影響しません

サービス、構成マップ、シークレットなど、作成後に基本的に変更されない Kubernetes 内のすべてのリソースがこれによって影響を受けます。バージョン番号が非常に古いため、いずれか 1 つを削除するとこのバグが発生します。たとえば、configmaps は繰り返し更新される可能性があり、コンテナーにマップされた config ファイルも継続的に更新されます。構成ホットリロードをサポートしていないサービスには影響はありません。構成ホット リロードをサポートするサービスの場合、構成ファイルが頻繁にリロードおよび再初期化されるため、予期しない問題が発生する可能性があります。

バグの修正は非常に簡単です。イベント リストを走査して resourceVersion を選択するときは、常に max(event.resourceVersion, currentResourceVersion) を取得します。 Kubernetes 担当者にプルリクエストを送信しました。私の大まかな修正によって新たな問題が起こらないことを願っています。

<<:  クラウドコンピューティングのコスト見積もりで無視できないいくつかの要素

>>:  主流の分散ストレージ Ceph がプライベートクラウドのリーダー VMware とどのように衝突するかをご覧ください

推薦する

hncloudはどうですか?ワーナークラウドシンガポール専用サーバーの簡単なレビュー

hncloudはシンガポールのデータセンターにあります。現在、シンガポールのクラウドサーバーとシンガ...

エンタープライズウェブサイト変革マーケティング戦略

企業のウェブサイトは、従来のマーケティングからオンライン マーケティングへと移行中です。インターネッ...

JD.com の商品一覧ページのユーザー エクスペリエンスとマーケティング手法の簡単な分析 (パート 2)

昨日の「JD.comの商品一覧ページのユーザーエクスペリエンスとマーケティング手法の簡単な分析(パー...

Kubectl 経由でポッドを再起動する 6 つの方法

51CTOウェブサイトコンテンツ調査に参加するにはクリックしてくださいkubectl には rest...

velocihost - $199 / GPU サーバー / ハイエンド グラフィック カード サーバー / デュアル カード クロスファイア

velocihost は、米国フロリダ州のホスティング プロバイダーです。主な業務は、通常のサーバー...

ソーシャル メディア マーケティング - 聞くことを学ぶ

失望は常に希望とともにやって来る。人々があなたの製品やサービスに頼るようになると、あなたの製品が彼ら...

frontrangehosting-ブラックフライデー、すべてのVPS(KVM/OPENVZ)が50%オフ

ブラック フライデーが近づいています。frontrangehosting のすべての VPS が 5...

ウェブデザインにおけるオレンジの使用に関するケーススタディ

オレンジはオレンジイエローやオレンジとも呼ばれます。浸透力は赤に次いで強く、赤よりも暖色系です。ウェ...

SEO最適化におけるウェブサイトの読み込み速度の重要性

ウェブサイトの読み込み速度に関して、誰もが最も直感的に感じるものはウェブページを開く速度だと思います...

ネット有名人は“設定”を崩したいがMCNは無力?

いわゆる「人格」が崩壊したのは、近年、彼が亡くなった妻と子供を利用して被害者の「人格」を作り、大多数...

AI がエッジ コンピューティングと IoT をよりスマートにする方法

[[391125]]エッジで AI を導入すると、ネットワークの遅延と運用コストが削減されるだけでな...

広告チャネルのコスト、最適化、テクニック!

広告に関しては、参考までにいくつかの経験談をシェアさせていただきました。今日はいくつかのポイントを皆...

パンデミックがクラウドコンピューティングの災害復旧について教えてくれること

クラウド コンピューティングは、オンデマンドのインフラストラクチャと「無制限」の規模で予期しない状況...

[.4.23] 老舗クラウドサーバーベンダーのLinodeが、新規ユーザーに100ドルのトライアルクレジットを提供します。

Linode オペレーティングシステムに Ubuntu 21.04 が追加されたため、公式が 4 時...

Pinduoduo: スーパーイベントからスーパーポータルへ

唐王朝が強大だった理由は、世界中から人々が朝貢に訪れるほどの「政治的民主主義」の繁栄だけでなく、部分...