アプリの耐障害性を高めるための開発とテスト

Red Hat OpenShift on IBM Cloud がコントロールプレーンのメンテナンスをどのように処理するか、メンテナンス更新が稼働中のワークロードにどのような影響を与えるか、そしてアプリケーションの耐障害性を高めるためのテストやアーキテクチャ設計の方法について学びましょう。

クラスタのアーキテクチャと役割の概要

Red Hat OpenShift on IBM Cloud は、管理対象の Kubernetes サービスです。 すべてのクラスタにおいて、アーキテクチャは、それぞれ [異なる所有責任](/docs/openshift?topic=openshift-responsibilities_Kubernetes Service) を持つ2つのプレーンに分かれています:

コントロール・プレーン
運営: IBM。 Kubernetes APIサーバー、 etcd、コントローラーマネージャー、およびスケジューラーが含まれます。
データ・プレーン
あなた自身が管理します。 ワーカーノード、アプリケーションポッド、ストレージ構成、およびネットワークアドオンが含まれます。
クラスタのコントロールプレーンおよびデータプレーンに関する所有者の責任
飛行機 管理サービス コンポーネント
コントロール・プレーン IBM APIサーバー、 etcd、コントローラーマネージャー、スケジューラー
データ・プレーン You ワーカーノード、アプリケーションポッド、ストレージ、ネットワークアドオン

IBM コントロールプレーンに対して、定期的にパッチバージョンの更新を適用しています。 これらのパッチは、セキュリティの脆弱性を修正し、重大なバグの修正を適用するとともに、クラスタが IBM のセキュリティ要件に準拠し続けることを保証します。 これらのパッチがどのように適用されるかを理解することで、アプリケーションのアーキテクチャについて、十分な情報に基づいた判断を下すことができます。

クラウド環境で実行されるアプリケーションは、一時的なネットワーク障害、ホスティングインフラのメンテナンス、サードパーティサービスの遅延など、動的な状況の影響を受けます。 あらゆる状況下での耐障害性を考慮した設計とテストを行うことで、信頼性の高い本番環境のワークロードを確保できます。

IBM によるコントロールプレーンのパッチ適用方法

すべての Red Hat OpenShift on IBM Cloud クラスタのコントロールプレーンコンポーネントは、高可用性(HA)構成で実行されます。 各コンポーネントの複数のレプリカが独立したアベイラビリティゾーンに分散配置されているため、コントロールプレーン内に単一障害点が存在しません。

パッチのアップグレードが適用されると、 IBM はローリング再作成戦略を採用します。 レプリカは順次更新されます:

  • アップグレード中も、 Kubernetes APIサーバーには引き続きアクセス可能です。
  • スケジューリング、オートスケーリング、ヘルスチェックなどのクラスタ操作は、中断されることなく継続されます。
  • IBM ポッドが削除される前に、進行中の接続が完了できるよう、 graceful shutdown の遅延時間を設定します。

コントロールプレーンのパッチによるアップグレードは、データプレーン上で実行されているユーザーアプリケーションに影響を与えないように設計されています。 このプロセス全体を通じて、ポッド、サービス、およびワークロードはワーカーノード上で通常通り実行され続けます。

コントロールプレーンの更新時のワークロードへの影響

データプレーンはユーザーによって管理されるため、 IBM のコントロールプレーンパッチによって、ワーカーノードや実行中のアプリケーションポッドが再起動、再スケジューリング、または変更されることはありません。

ただし、 Kubernetes API に対して頻繁かつ直接的に呼び出しを行うアプリケーションやツール(カスタムコントローラー、オペレーター、CI/CD パイプライン、クラスターの状態を監視するモニタリングエージェントなど)は、一時的な API エラーに対して適切に対処する必要があります。 Kubernetes の一般的なベストプラクティスに従ってください:

  • すべてのAPI呼び出しに対して、指数関数的バックオフを用いたリトライロジックを実装する。
  • 再接続ロジックがない場合、APIサーバーへの永続的なオープン接続に依存することは避けてください。

シナリオをシミュレートしてアプリケーションの耐障害性を検証する

アプリケーションの耐障害性に対する信頼性を高めるため、定期メンテナンスや予期せぬ障害が発生する前に、本番環境以外の環境で本番環境の障害状況をシミュレートしてください。

シミュレーション中は、アプリケーションを監視し、予期せぬポッドの再起動、エラーログの急増、応答時間の悪化、クライアントリクエストの損失など、障害の兆候がないか確認してください。 これらの観察結果を活用して、再試行ロジックの改良、ヘルスプローブの調整、あるいはレプリカのトポロジーの調整を行ってください。

クラスタ管理コマンド(マスターのリフレッシュやワーカープールのサイズ変更など)を実行するには、プラットフォームへの「管理者」または「オペレーター」のアクセス権と、クラスタ管理サービスの権限が必要です。 クラスタインフラストラクチャへのアクセス権限を持たないアプリケーション開発者の場合は、クラスタ管理者と連携して、これらのシミュレーションを実行してください。

コントロールプレーンのリフレッシュを用いたコントロールプレーンパッチのシミュレーション

コントロールプレーンの更新をトリガーすると、 IBM がパッチアップグレードの際に使用するローリングアップデートプロセスが開始されます。 このテストでは、アプリケーションとツールがコントロールプレーンのレプリカ移行を円滑に処理できるかどうかを確認します。

  1. クラスターでコントロールプレーンの更新を実行します。

    ibmcloud oc cluster master refresh --cluster CLUSTER_NAME_OR_ID
    
  2. アプリケーションが中断することなくトラフィックの処理を継続していること、およびクライアント向けエンドポイントが引き続き応答していることを確認してください。

ワーカーノードの追加および削除によるネットワークルーティング更新のシミュレーション

ワーカーノードの追加や削除を行うと、 Kubernetes はクラスタ全体の内部ネットワークルーティングロジックを更新し、インフラストラクチャのメンテナンス中にノードが再起動する際と同様の状況をシミュレートします。

  1. ワーカープールのサイズを変更して、一時的なワーカーノードを追加してください。

    ibmcloud oc worker-pool resize --cluster CLUSTER_NAME_OR_ID --worker-pool WORKER_POOL_NAME --size-per-zone NEW_SIZE
    
  2. 新しいワーカーノードが初期化され、クラスタネットワークに参加する間、アプリケーションのログと応答遅延を監視してください。

  3. テストが完了したら、テスト用ワーカーノードを削除してください。

    手順 1 で作成した特定のワーカーノードをターゲットとして削除するには、次の手順を実行します:

    1. ワーカーノードを削除する前に、そのノードをコルドーン化し、データを排出することで、ワークロードが正常に再スケジューリングされるようにしてください。
       oc cordon NODE_NAME
       oc drain NODE_NAME --ignore-daemonsets --delete-emptydir-data
    
    1. クラスターからワーカーノードを削除します。
       ibmcloud oc worker rm --cluster CLUSTER_NAME_OR_ID --worker WORKER_ID
    
    1. ibmcloud oc worker-pool resize コマンドを使用し、元の --size-per-zone の値を指定して、ワーカープールの容量を元の状態に戻してください。

    より限定的な対象を絞らない代替手段として、特定のノードを明示的に削除することなく、手順 1 の「 ibmcloud oc worker-pool resize 」コマンドを使用して、ワーカープールを元のサイズに戻すこともできます。

ワークロードの耐障害性に関する推奨事項

クラスタイベント発生時のアプリケーションの回復力は、ワークロードの設計および構成方法によって異なります。 Kubernetes のワークロード仕様には、以下の推奨事項を適用してください:

すべてのワークロードに対して複数のレプリカを実行する

シングルレプリカ構成では、障害への耐性がありません。 spec.replicas を少なくとも 2 に設定してください(本番環境のワークロードでは、 3 以上が推奨されます)。これにより、単一のポッドが失われたり、再スケジューリングされたりしても、ダウンタイムが発生しないようにします。

レプリカを各ゾーンおよびワーカーノードに分散させる

デプロイメント設定で、 topologySpreadConstraints またはポッドのアンチアフィニティルールを設定します。 ポッドを複数のアベイラビリティゾーンやワーカーノードに分散させることで、単一のゾーンでの障害やノードのメンテナンス作業によって、すべてのレプリカが同時に停止することを防ぐことができます。

Pod ディスラプション・バジェット(PDB)の設定

PodDisruptionBudget リソースは、ノードのドレインやクラスタの更新など、意図的な中断が発生している間も利用可能な状態を維持しなければならないポッドの最小数または割合を指定します。 重要なワークロードごとにPDBを定義し、管理作業によってアプリケーションが許容できる数以上のポッドがエヴィクションされないようにします。

レディネス・プローブおよびライブネス・プローブを定義する

コンテナの仕様で、レディネス・プローブとライブネス・プローブを設定します:

  • 準備状態のプローブ: Kubernetes が、初期化が完了し、リクエストを処理できる状態にあるポッドにのみトラフィックをルーティングするようにします。
  • ライブネスプローブ: Kubernetes が、デッドロック状態または不健全な状態になったコンテナを自動的に再起動するように設定します。

適切なリソースの要求と制限を設定する

各コンテナについて、現実的なCPUおよびメモリの要求値と上限値を指定してください。 リクエストにより、 Kubernetes スケジューラが、十分な容量を持つノードにポッドを配置するよう保証されます。 制限を設けることで、単一のコンテナが過度のリソースを消費し、同じワーカーノード上で実行されている他のワークロードのパフォーマンスを低下させることを防ぎます。

正常なシャットダウン処理を実装する

ポッドが終了する際、 Kubernetes は、 SIGKILL を送信する前に、 SIGTERM シグナルを送信します。 アプリケーションを設計する際は、 SIGTERM を捕捉し、新規接続の受け入れを停止し、進行中のトランザクションを完了させ、正常に終了するようにしてください。 アプリケーションがトラフィックを適切に処理し終えるのに十分な時間を確保できるよう、Podの仕様で適切な terminationGracePeriodSeconds を設定してください。

APIサーバーへの長期にわたる接続に依存することは避けてください

Kubernetes ウォッチリクエストやストリーミング接続( oc exec、ポートフォワード、カスタムAPIクライアントによるウォッチなど)は、特定のコントロールプレーンレプリカに直接接続されます。 パッチのアップグレード中にそのレプリカがサイクルすると、接続が切断されます。 ワークロードおよびツールは、指数関数的バックオフを用いた自動再接続ロジックを実装しなければならない。

リトライロジックとサーキットブレーカーを使用する

アプリケーションが Kubernetes API、外部データベース、または下流のマイクロサービスとやり取りを行う場合は、指数関数的なバックオフとジッターを備えたリトライロジックを実装してください。 上流または下流の依存関係が一時的に利用できなくなった場合に、連鎖的な障害を防ぐために、サーキットブレーカーのパターンを活用します。

次のステップ