Containers & Kubernetes

GKE のベスト プラクティス: 高可用性クラスタの設計と構築

google cloud containers

※この投稿は米国時間 2020 年 7 月 16 日に、Google Cloud blog に投稿されたものの抄訳です。

多くの組織が Google Kubernetes Engine(GKE)環境などのシステムの稼働を継続するために、さまざまなリスク管理とリスク軽減の戦略を採用しています。こうした戦略は、予測可能なシステム停止時でも予測不可能なシステム停止時でもビジネスの継続性を確保するものです。特に、パンデミックによるビジネスへの影響を抑制するために取り組んでいる現在こそ重要です。 

この 2 回にわたるブログ投稿の最初の記事では、可用性の高い GKE クラスタを、いわゆる Day 0 の段階で設定する方法についての推奨事項とベスト プラクティスをご紹介します。そして 2 回目の投稿では、クラスタを稼働させた後の、Day 2 の高可用性のベスト プラクティスについて説明します。 

GKE クラスタの高可用性について考えるとき、多くの人は中断やメンテナンスは長期的な Day 2 運用の一部であると考えているため、Day 0 は見過ごされがちです。しかし実際は、ワークロードをデプロイする前に、GKE クラスタのトポロジと構成を慎重に計画することが必要です。

ワークロードに適したトポロジ、スケール、ヘルスチェックを選択する

GKE 環境を作成してワークロードをデプロイする前に、いくつかの重要な設計ポイントを決定する必要があります。 

クラスタに適したトポロジを選択する

GKE では、リージョンおよびゾーンという 2 種類のクラスタを提供しています。ゾーンクラスタのトポロジでは、クラスタのコントロール プレーンとノードがすべて、クラスタ作成時に指定した単一のコンピューティング ゾーンで実行されます。リージョン クラスタでは、コントロール プレーンとノードが、単一リージョン内の複数のゾーンに複製されます。 

リージョン クラスタは、3 つのKubernetes コントロール プレーン クォーラムで構成されているため、ゾーンクラスタよりもクラスタのコントロール プレーン API に提供できる可用性が高くなります。また、コントロール プレーンが利用できない場合でも、ノードで実行されている既存のワークロードは影響を受けませんが、一部のアプリケーションはクラスタ API の可用性に大きく依存しています。そのようなワークロードについては、リージョン クラスタ トポロジを使用する方が良いでしょう。 

もちろん、リージョン クラスタを選択するだけでは、GKE クラスタを保護するのに十分ではありません。Pod のスケーリング、スケジュール、置換は、コントロール プレーンの役割です。また、コントロール プレーンが利用できない場合、クラスタの信頼性に影響を与える可能性があります。これは、コントロール プレーンが再び利用可能になったときにのみ再開できます。 

また、リージョン クラスタにはノードだけでなく冗長なコントロール プレーンもあること覚えておく必要があります。リージョン トポロジでは、ノードが異なるゾーン間で冗長化されているため、費用の高いクロスゾーン ネットワーク トラフィックが発生する可能性があります。 

最後に、リージョン クラスタの自動スケーリングは、リソースを 3 つのゾーンにベスト エフォートに分散しますが、スケールアップやスケールダウンが発生しない限り、こうした分散バランスが自動的に再調整されることはありません。 

以上をまとめると、Kubernetes API の可用性を向上させ、コントロール プレーンでのメンテナンス時にクラスタの中断を最小限に抑えるためには、3 つの異なる可用性ゾーンにノードをデプロイしてリージョン クラスタをセットアップすることと、自動スケーリングに注意を払うことをおすすめします。 

水平方向、垂直方向のスケーリング

キャパシティ プランニングは大事ですが、すべてを予測することは不可能です。負荷のピーク時にワークロードを正常に機能させ、通常時や低負荷時にコストをコントロールするためには、ご自分のニーズに最適な GKE の自動スケーリング機能を模索することをおすすめします。 

垂直 Pod 自動スケーリング(VPA)をノードの自動プロビジョニング(NAP、またはノードプールの自動プロビジョニング)と併用する。GKE が水平(Pod)にも垂直(ノード)にもクラスタを効率的にスケーリングできるようになります。VPA では、CPU の値、メモリ リクエスト、コンテナの上限が自動的に設定されます。NAP ではノードプールが自動管理され、ユーザーが作成したノードプールのセットからのみ新しいノードが開始されるというデフォルトの制約が取り除かれます。 

上記の推奨事項は、コストの削減に役立ちます。たとえば、NAP では、十分に活用されていない期間にノードを停止することにより、費用が削減されます。しかし、費用を気にせず、レイテンシと可用性を重視している場合は、最初から大規模なクラスタを作成し、GCP 予約を使用して目的の容量を確保できます。ただし、これは費用が高くなる傾向があります。 

デフォルトのモニタリング設定を確認する

Kubernetes はワークロードの動作を詳細に観察し、ワークロードを均等に分散することを確実にします。そのため、ワークロードからの特定のシグナルを Kubernetes で捉えられるようにすれば、ワークロードの可用性をさらに最適化できます。たとえば、Readiness や Liveness など、ワークロードの詳細情報を伝えるシグナルを使用すれば、ワークロードが正常に動作しているかどうか、ワークロードがトラフィックを受信可能な状態であるかを判定できるようになります。Readiness Probe と Liveness Probe の違いを見てみましょう。 

アプリケーションの動作はそれぞれ異なります。開始に時間がかかるアプリケーションや、バッチ処理を長い時間実行するせいで使用不可な状態であると誤解されるアプリケーションもあります。Readiness Probe と Liveness Probe は、まさにこうした状況を想定したものであり、許容できるワークロードの動作を Kubernetes に伝える役割を果たします。たとえば、アプリケーションの起動に時間がかかり、トラフィックを処理する準備ができていない場合、Kubernetes が顧客のトラフィックを送信し始めないようにする必要があります。Readiness Probe を使用すると、アプリケーションが初期化を完了し、エンドユーザーにサービスを提供する準備が整ったときに、Kubernetes に正確な信号を提供できます。 

ワークロードがトラフィックを受信する準備が本当にできているかどうかを Kubernetes に確実に伝えるには、Readiness Probe を設定しましょう。同様に、Liveness Probe を設定して、ワークロードが本当に応答不可なのか、CPU で集中的に処理が実行されているだけなのかを知らせましょう。 

最後に、Readiness Probe と Liveness Probe は、定義に従ってコーディングどおりに動作するだけなので、作成した Probe は必ずテストして検証するようにしてください。

Kubernetes Deployment を正しく設定する

各アプリケーションは、さまざまな特性の集合体であり、バッチ ワークロードのものがあれば、ステートレス マイクロサービスに基づくもの、またはステートフル データベースに基づくものもあります。Kubernetes がアプリケーションの制約を認識できるようにするために、Kubernetes Deployment を使用してワークロードを管理できます。Deployment で正常な状態を定義すると、この正常な状態になるように、Kubernetes と動作して実際の状態を変化させます。 

お使いのアプリケーションがステートフルかどうか

アプリケーションがセッション間でその状態を保存する必要がある場合(データベースなど)は、StatefulSet の使用を検討してください。StatefulSet は、ステートフル アプリケーションの固有の特性を適切に処理しながら、Pod を管理して維持する Kubernetes コントローラです。これは、ReplicaSet や Deployment など、Pod を管理する他の Kubernetes コントローラと似ています。ただし、Deployment とは異なり、StatefulSet は Pod が交換可能であることを想定していません。 

StatefulSet では、「状態」を維持するために永続ボリュームも必要です。それにより、ホステッド アプリケーションを再起動したときにデータを保存、復元することが可能となります。Kubernetes では、ストレージ クラス、永続ボリューム、永続ボリュームの要求が、Google Cloud Storage の上位の抽象化レイヤとして提供されます。 

Pod のアフィニティを理解する

すべてのレプリカを同じノードでスケジュールしますか。そのノードに障害が発生した場合はどうなりますか。一度にすべてのレプリカが失われても問題はないでしょうか。Kubernetes Pod のアフィニティ ルールと反アフィニティ ルールを使用して、Pod とそのレプリカの配置を制御できます。 

単一障害点を避けるには、Pod の反アフィニティを利用し、同じノードに Pod が配置されないように Kubernetes に指示します。ステートフル アプリケーションでは、この配置が重要な構成になる可能性があります。特に、ステートフル アプリケーションを適切に実行するためにレプリカの数(つまり、クォーラム)が必要な場合に重要になります。 

たとえば、ZooKeeper はデータにミューテーションを正しく適用するためにサーバーのクォーラムが必要です。3 台構成のアンサンブルの場合、2 台のサーバーが正常でなければ書き込みは成功しません。そこで、復元力のあるデプロイメントでは、サーバーが障害発生ドメイン全体にデプロイされる必要があります。

そのため、ノードの損失などによる停止を回避するには、アプリケーションの複数のインスタンスを同じマシン上に配置しないことをおすすめします。これを行うには、Pod 反アフィニティを使用します。 

反対に、複数の Pod を同じノードに配置した方が良い場合もあります。複数の Pod を同じマシンに配置すると、局所性によるメリットが得られるため、相互に通信する必要がある場合にレイテンシが短くなり、パフォーマンスが改善します。これを実現するには、Pod アフィニティを使用します。 

たとえば、別のステートフル アプリケーションである Redis ではウェブ アプリケーションにメモリ内キャッシュを利用できる場合があります。このデプロイメントでは、レイテンシを回避してパフォーマンスを改善するために、ウェブサーバーをできるだけキャッシュと同じ場所に配置する必要があります。

中断を予想する

GKE クラスタとその上で実行されるアプリケーションを構成したら、負荷の増加または中断が発生した場合の対応方法を検討します。 

デジタル化を徹底するにはキャパシティ プランニングの改善が必要

GKE で Kubernetes クラスタを実行すると、物理インフラストラクチャとそのスケーリングについて考える手間が省けます。それでもなお、特に負荷の増加が予想される場合は、キャパシティ プランニングを実行することを強くおすすめします。

リソース需要の急増が予想される場合の担保として、予約済みインスタンスの使用を検討しましょう。GKE では、特定の(マシンタイプと仕様)予約と不特定の予約がサポートされています。予約を設定すると、お客様向けに独自に予約されたリソースのポーリングにより、バックグラウンドのノードで予約が自動的に使用されます。

サポート計画を立てる

Google Cloud サポートは世界中のエンジニアからなるチームで、発生する問題のサポートを 24 時間年中無休で提供しています。さて、本稼働に入る前に、問題が発生した場合に役立つ適切なクラウド サポート計画を確保しておきましょう。

  • サポートプランを見直して、貴社のビジネスに適したパッケージであることを確認してください。
  • サポート ユーザーの構成を確認し、チームメンバーがサポートケースを開けるようにしてください。
  • GKE の Monitoring と Logging がKubernetes Engine の Monitoring と Logging がクラスタで有効になっていることを確認してください。テクニカル サポート エンジニアがお客様のシステムのトラブルシューティングを行うには、ログや指標が必要です。
  • GKE の Monitoring と Logging が有効になっていない場合は、新しいベータシステムのみのログ機能を有効にして、トラブルシューティングに重要なログのみを収集することを検討してください。

まとめ

コンテナ化されたアプリケーションは、移植可能で、デプロイとスケーリングが容易です。GKE を利用すると、さまざまなクラスタ管理機能により、手間をかけずにワークロードを実行しやすくなります。あなたのアプリケーションについて最も精通しているのはあなたご自身です。上記の推奨事項に従えば、クラスタの可用性と健全性を大幅に向上させることができるでしょう。他にもアイデアやおすすめの方法がございましたら、お知らせください。また、このシリーズの第 2 回にもご期待ください。本番クラスタの問題に対処する方法について説明します。

- プロダクト マネージャー Kobi Magnezi