世界と神々を震撼させた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 とどのように衝突するかをご覧ください

推薦する

調査では未来が危機に瀕していると予測

レポートによると、エッジ コンピューティングには、速度の向上、レイテンシの短縮、データ セキュリティ...

女性消費者から女性向け電子商取引サイトへの20の参照

女性はお金が儲かりやすい、女性は衝動買いをする、女性向け商品は利益率が高いなどと言われています。しか...

李開復氏:米国機関による中国株の悪質な空売りは容認できない

新華社、北京9月5日(曹凱記者、王愛華記者)イノベーションワークスの李開復会長(微博)は5日、新華社...

Baidu によってウェブサイトが降格された後の 3 つの経験

最近の12月のBaiduのアップデートでは、ある日突然、ウェブサイトのホームページがダウングレードさ...

A5マーケティング:企業のウェブマスターによる同業ウェブサイトの基本的なSEO状況を分析する方法

かつて、競合他社のウェブサイトの最適化を分析して、自分のウェブサイトを改善したいと思ったことはありま...

Baidu のスナップショットが多くのウェブマスターを困惑させる

最近、ウェブマスターの間で「Baiduスナップショット」という話題が話題になっています。Baiduス...

デバイス・エッジ・クラウドの連携: クラウドからエッジへ

SDX は Software Defined X の略で、ソフトウェア定義パラダイムを意味し、ソフト...

簡単な分析: マーケティングプロモーションの3つの基本ルール

AAA Xiaomi のハングリー戦略の下では、他のすべてのプロモーション マーケティング手法は影を...

カメラウェブサイトの運営中にソフト記事を活用してトラフィックを増やす方法

淘宝牌牌とは、淘宝と牌牌でのコンバージョン率を頼りにお金を稼ぐウェブマスターを指します。このタイプの...

301リダイレクトについての説明

301 リダイレクトとは、あるドメイン名から別のドメイン名にジャンプすることを指します。同じドメイン...

10,000 から 500,000 までの予算に対応したブランド マーケティングのアイデア!

今日は、10,000 から 500,000 までの予算でのマーケティングのアイデアを簡単に紹介します...

世界最大のドメイン名サービスプロバイダーGoDaddyが1億ドルの資金調達の目論見書を提出

世界最大のドメイン名サービスプロバイダーGoDaddyが目論見書を提出新浪科技ニュース:北京時間6月...

ウェブサイトの重量を改善する際に注意すべきこと

ウェブサイトの重量を改善することは、すべてのウェブマスターが日夜望んでいる夢です。多くのウェブマスタ...

SEOサイト全体の最適化について

当社は長年の実践経験を通じて、お客様が複数のロングテールキーワードを選択して、より直接的なオンライン...