Kubernetesを本番環境で使用した3年間の経験から学んだこと

Kubernetesを本番環境で使用した3年間の経験から学んだこと

[編集者注] Kubernetes の旅から得られた主な教訓。

私たちは 2017 年にバージョン 1.9.4 で最初の Kubernetes クラスターの作成を開始しました。クラスターは 2 つあり、1 つはベアメタル RHEL VM 上で実行され、もう 1 つは AWS EC2 上で実行されます。

現在、当社の Kubernetes インフラストラクチャは、複数のデータセンターに分散された 400 台以上の VM で構成されています。このプラットフォームは、約 4,000 万のアクティブ デバイスを備えた大規模なリアルタイム ネットワークを管理するための、可用性の高いミッション クリティカルなアプリケーションとシステムを多数ホストします。

[[416051]]

Kubernetes は最終的に私たちの生活を楽にしてくれましたが、それは困難なプロセスでした。完全に変化したのは、私たちのスキルやツールセットだけではありません。デザインや考え方も変化しました。私たちは複数の新しいテクノロジーを導入し、チームとインフラストラクチャの能力を拡張するために多額の投資をする必要がありました。

過去 3 年間に渡り Kubernetes を本番環境で使用してきた経験を振り返り、いくつかの重要な教訓をまとめました。

Javaアプリケーションの奇妙な問題

マイクロサービスとコンテナ化に関しては、主にメモリ管理の悪名が高いため、エンジニアは Java スタックを避ける傾向があります。しかし、状況は変わり、Java のコンテナ互換性は長年にわたって向上してきました。結局のところ、Apache Kafka や Elasticsearch などのユビキタス システムは Java 上で実行されます。

2017-18 年には、Java 8 バージョンで実行されるアプリケーションがいくつかありました。 Docker などのコンテナ環境を理解するのが困難な場合が多く、ヒープ メモリの問題や異常なガベージ コレクション メカニズムが原因でクラッシュすることがよくあります。これらはすべて、コンテナ化技術の中核である JVM と Linux の cgroup と名前空間の問題によって発生していることがわかりました。

しかし、その後も Oracle はコンテナ分野での Java の互換性の改善を続け、Java 8 のその後のパッチでもこれらの問題を解決するために実験的な JVM フラグ XX:+UnlockExperimentalVMOptions と XX:+UseCGroupMemoryLimitForHeap が導入されました。

しかし、これらの改善にもかかわらず、Java は Python や Go などの同業言語と比べて、メモリ使用量が多く、起動時間が遅いという評判が依然として悪いのは否定できません。これは主に、JVM のメモリ管理とクラス ローダーによって発生します。

ここで、Java を選択する必要がある場合は、Java 11 バージョン以上であることを確認します。 Kubernetes のメモリ制限は、JVM の最大ヒープ メモリ (-Xmx) に予約用の 1 GB を加えた値に基づいて構成されます。たとえば、JVM がヒープ メモリに 8 GB を使用する場合、そのアプリケーションに対する Kubernetes のリソース制限は 9 GB になります。これにより、アプリケーションはより安定します。

Kubernetes ライフサイクルのアップグレード

アップグレードや機能強化などの Kubernetes ライフサイクル管理は、特にクラスターがベアメタル デバイスまたは VM 上に構築されている場合は面倒になる可能性があります。アップグレードの場合、最も簡単な方法は、最新バージョンで新しいクラスターを立ち上げ、古いクラスターから新しいクラスターにワークロードを移行することだとわかりました。インプレース ノード アップグレードの労力と計画は価値がありません。

Kubernetes には、一緒にアップグレードする必要がある複数の可動部分があります。 Docker から Calico や Flannel などの CNI プラグインまで、動作させるには慎重に組み合わせる必要があります。 Kubespray、Kubeone、Kops、Kubeaws など、作業を容易にするツールはありますが、いずれも欠点があります。

Kubespray を使用して、RHEL 仮想マシン上にクラスターを構築します。 Kubespray は優れており、クラスターの設定、ノードの追加と削除、バージョンの更新など、Kubernetes を本番環境で運用するために必要なほぼすべてのプレイブックが備わっています。ただし、アップグレードのプレイブックには、マイナー バージョンをスキップできないようにする免責事項が付属しています。したがって、ターゲット バージョンのアップグレードを完了するには、すべての中間バージョンのアップグレードを実行する必要があります。

Kubernetes の使用を計画している場合、またはすでに使用している場合は、ライフサイクル アクティビティと、ソリューションでそれらに対処する方法について検討してください。クラスターの構築と実行は比較的簡単ですが、ライフサイクル管理は多くの可動部分を伴うまったく新しい問題です。

ビルドとデプロイ

ビルドとデプロイメントのパイプライン全体を再設計する準備をしましょう。 Kubernetes 環境に適応するために、ビルド プロセスとデプロイメントを完全に変革する必要がありました。リファクタリング作業には、Jenkins パイプラインだけでなく、Helm などの新しいツールの使用、新しい Git プロセスとビルド戦略への調整、Docker イメージのタグ付け、バージョン管理された Helm デプロイメント チャートも含まれます。

コードだけでなく、Kubernetes デプロイメント ファイル、Dockerfile、Docker イメージ、Helm チャートも維持し、それらすべてを接続する新しい方法を考案するための戦略が必要になります。

数回の繰り返しを経て、次のデザインに落ち着きました。

  • アプリケーション コードと対応する Helm チャートは異なる Git リポジトリに保存されるため、バージョンを個別に管理できます。
  • リリースを追跡するために、アプリケーション バージョンを含むチャート バージョンの組み合わせを保持します。たとえば、app-1.2.0 は charts-1.1.0 とともにデプロイされます。 Helm 値ファイルのみが変更された場合は、チャートのパッチ バージョンのみが変更されます (たとえば、1.1.0 から 1.1.1 へ)。これらのバージョン番号はすべて、各リポジトリ内のリリース ノート ファイル RELEASE.txt によって決定されます。
  • Apache Kafka や Redis などのシステム アプリケーションは、コードをビルドしたり変更したりする必要がないため、動作が異なります。つまり、Docker タグは Helm チャート バージョン管理の一部であるため、2 つの Git リポジトリを使用する必要はありません。アップグレードにより Docker タグを変更する場合は、チャート タグ内のメジャー バージョン番号もアップグレードします。 ### 生存性プローブと準備性プローブ(これは諸刃の剣です)

Kubernetes の準備プローブと生存プローブは、システムの問題を自動的に解決するための優れた機能です。障害発生時にコンテナを再起動し、異常なインスタンスからトラフィックをリダイレクトできます。しかし、特定の障害条件下では、これらのプローブは諸刃の剣となり、アプリケーション、特にメッセージング プラットフォームやデータベースなどのステートフル アプリケーションの起動と回復に影響を及ぼします。

私たちの Kafka システムはこの問題の被害者でした。 replicationFactor: 3、minInSyncReplica: 2 で 3 Broker 3 ZooKeeper ステートフル クラスターを実行しました。予期しないシステム障害とクラッシュの後に Kafka が起動したときに問題が発生しました。これにより、起動時に破損したインデックスを修復するための追加のスクリプトが実行され、プログラムの重大度に応じて 10 ~ 30 分かかることがあります。この余分な起動時間により、活性プローブは失敗し続け、Kafka を再起動させる Kill シグナルがトリガーされます。これにより、Kafka がインデックスを修復して完全に起動できなくなります。

唯一の解決策は、コンテナの起動後に評価を遅らせるために、サバイバル プローブ検出で initialDelaySeconds 構成を構成することです。しかし、問題は、特定の値を想定することが難しいことです。回復プロセスには最大 1 時間かかる場合があり、これを考慮して十分なスペースを確保する必要があります。ただし、initialDelaySeconds 値が大きいほど、起動に失敗したときに Kubernetes がコンテナの起動を完了するまでに時間がかかるため、サービスの回復が遅くなります。

したがって、妥協策としては、Kubernetes で求める回復力と、あらゆる障害状況 (ディスク障害、ネットワーク障害、システム クラッシュなど) 下でアプリケーションが正常に起動するまでにかかる時間のバランスをより適切に取る initialDelaySeconds フィールドの値を評価することです。

新しいバージョンの Kubernetes を使用している場合は、3 番目のプローブ タイプである「スタートアップ プローブ」を使用できます。コンテナの起動プロセスが中断されないよう、コンテナが正常に起動する前に、生存性および準備状況のプローブを無効にします。

外部IP露出を利用する

静的な外部 IP を使用してサービスを公開すると、カーネルの接続追跡メカニズムに大きな負担がかかることがわかりました。慎重に計画しなければ、大規模な崩壊が起きる恐れがあります。

私たちのクラスターは Calico CNI を使用し、エッジ ルーターとピアリングしながら Kubernetes のルーティング プロトコルとして BGP を使用します。 Kube-proxy では、IPTables モードを使用します。私たちは、外部 IP 経由で公開され、1 日に数百万件のリクエストを処理する大規模なサービスを Kubernetes でホストしました。 SDN からのすべての SNAT とマスカレードにより、Kubernetes にはこれらすべての論理フローを追跡するメカニズムが必要になります。これを実現するために、カーネル内でConntrackを使用する。

そして、これらの外部接続を静的 IP に管理するための netfilter ツールが、内部サービス IP に変換され、さらに Pod IP に変換されます。これらはすべて、conntrack テーブルと IPTables を通じて実現されます。

ただし、conntrack テーブルには制限があり、制限がトリガーされると、Kubernetes クラスター (OS カーネルの下) は新しい接続を受け入れることができなくなります。 RHEL システムでは、次のコマンドを実行して確認できます。

  1. $ sysctl net.netfilter.nf_conntrack_count net.netfilter.nf_conntrack_maxnet.netfilter.nf_conntrack_count = 167012  
  2. ネット.netfilter.nf_conntrack_max = 262144

この問題の解決策としては、複数のノードをエッジ ルーターでピアリングして、静的 IP への接続をクラスター全体に分散させるというものがあります。したがって、クラスターに多数のマシンがある場合は、累積的に、大量の着信接続を処理するための大きな conntrack テーブルが存在するように見えます。

この質問は、私たちが2017年に事業を開始した当時、非常に困惑していましたが、最近では、Calico が 2019 年にこの問題に関する詳細な調査レポートを公開しました。そのレポートには、「conntrack がもはやあなたの味方ではない理由」という適切なタイトルが付けられています。

自己分析の質問: Kubernetes は絶対に必要ですか?

3年経った今でも、私たちは毎日新しいことを発見し、学び続けています。これは、特に環境の構築と維持のオーバーヘッドなど、独自の問題を抱えた複雑なプラットフォームです。設計、考え方、アーキテクチャが変わり、変革の要求を満たすためにチームのスキルと規模を拡大する必要があります。

ただし、クラウド上で Kubernetes を「サービス」として利用できる場合は、「社内ネットワークの CIDR を拡張するにはどうすればよいか」といったプラットフォームのメンテナンス作業に伴うオーバーヘッドのほとんどを軽減できます。または「Kubernetes のバージョンをアップグレードするにはどうすればよいですか?」

さて、自分自身に最初に尋ねるべき質問は「Kubernetes は絶対に必要ですか?」であることがわかりました。これは、問題と Kubernetes がそれをどの程度解決できるかを評価するのに役立ちます。

Kubernetes の変革は簡単ではありません。支払う価格は、使用事例を正当化するものであり、プラットフォームに実際にプラスの影響を与えることができるものでなければなりません。答えが「はい」であれば、Kubernetes は生産性を大幅に向上させることができると言えます。

覚えておいてください。テクノロジーをテクノロジーのために使用しても意味がありません。

<<:  Canalys: アマゾン、マイクロソフト、グーグルがクラウドサービス市場の60%を占める

>>:  Red HatとNutanixが協力してオープンハイブリッドマルチクラウドソリューションを提供

推薦する

AWS、Microsoft、Googleがガートナーのクラウドサービス部門マジッククアドラントをリード

ガートナー社の最新の戦略的クラウド プラットフォーム サービスに関するマジック クアドラント レポー...

セルフメディアパーソンになるには、ストーリーを語ることができなければならない

今日、こんな文章を見ました。「コンテンツ マーケティングを行う人は、優れたストーリーテラーでなければ...

クラウド インフラストラクチャ ソフトウェア: 仮想化とコンテナー、どちらが勝つでしょうか?

従来の IT アーキテクチャでは、オペレーティング システムはコンピューターのハードウェアとソフトウ...

企業サイトのBaiduプロモーションコストを節約する方法について簡単に説明します

中小規模の企業ウェブサイトの場合、最短時間で成果を出したい場合、最も効果的な方法は百度プロモーション...

滴滴出行と快滴行の合併の噂の背景にある3つの分析ポイント

楽しみに、楽しみに、春の足音が近づいてきています。今年もバレンタインデーがやってきました。例年通り、...

新しいウェブサイトにロングテールワードとロングテールワードのレイアウトを選択する方法

今日は、著者の周旭生がロングテールキーワード戦略の知識についてお話しします。皆さんの応援をお願いしま...

SEO実践ウェブサイト内部構造設計最適化

検索エンジン最適化は、広告ウェブサイトを宣伝するための最も低コストで最も効果的な方法です。効果的なユ...

この記事はJVMについて深く理解するのに役立ちます

[[278753]] 1. JVMとは何かJVM は Java Virtual Machine の略...

ホームページ最適化の詳細な手順

これまで、ホームページの質の悪さが原因でユーザーが離脱してしまったウェブサイトは数え切れないほどあり...

「少ないほど豊か」がクラウド コンピューティングの秘訣である理由

クラウドネイティブコンピューティングには何が欠けているのでしょうか?結果、コード、状態、信頼。 [[...

ウェブサイト成功の秘訣:天山七剣士

すべてのウェブマスターは自分のウェブサイトが成功することを望んでいますが、成功の基準は最終的には影響...

パシフィック・ダイレクト・パーチェス・ネットワークのカスタマーサービスは、資金は凍結されており、BMCモデルは依然として無視されていると述べた。

ある弁護士は、中国ではBMCモデルに関する具体的な法的定義はなく、依然として境界上にあると述べた。 ...

友好的なリンクを交換する際に注意すべき「型破りな」側面(I)

ウェブサイトの最適化プロセスにおいて、友好リンクの交換は最も重要な部分の一つです。友好リンクを交換す...

ドメイン名を登録する際にURLの履歴に注目しましたか?

多くの場合、ウェブマスターはドメイン名を登録するときに、思いついたドメイン名をそのまま登録します。し...