実際の運用アプリケーションでは複数のコンテナが必要になります。これらのコンテナは複数のサーバー ホストに展開する必要があります。コンテナ セキュリティには多層的な展開が必要であり、複雑になる可能性があります。しかし、Kubernetes はこの問題の解決に役立ちます。 Kubernetes は、これらのワークロード向けにコンテナを大規模にデプロイするために必要なオーケストレーションおよび管理機能を提供します。 Kubernetes オーケストレーションを使用すると、複数のコンテナにわたってアプリケーション サービスを構築し、これらのコンテナをクラスター全体でスケジュールおよびスケーリングし、これらのコンテナの健全性を長期にわたって管理できます。 Kubernetes を使用すると、IT セキュリティを向上させるために実行できる実際の手順があります。 高可用性 (HA) とは、アプリケーション システムが中断することなく実行される能力のことであり、通常はシステムのフォールト トレランスを向上させることで実現できます。一般的に、レプリカを設定してアプリケーションのコピーを複数作成すると、アプリケーションのフォールト トレランスは適切に向上しますが、アプリケーションの高可用性が実現されるわけではありません。 ご存知のとおり、Kubernetes 環境に使用可能なアプリケーションをデプロイするのは簡単です。しかし一方で、フォールト トレラントで信頼性が高く、使いやすいアプリケーションを導入しようとすると、必然的に多くの問題に遭遇することになります。この記事では、Kubernetes での高可用性アプリケーションのデプロイについて説明し、簡潔に紹介します。この記事では、Kubernetes で高可用性アプリケーションをデプロイする際に注意する必要がある原則と対応するソリューションについても重点的に説明します。 既存の展開シナリオは使用しないことに注意してください。また、特定の CD ソリューションにコミットすることはなく、テンプレートから Kubernetes マニフェストを生成する問題も省略します。この記事では、クラスターにデプロイされたときの Kubernetes マニフェストの最終的な内容についてのみ説明し、他の部分については詳しく説明しません。 1. コピー数通常、アプリケーションの最低限の高可用性を確保するには、少なくとも 2 つのレプリカが必要です。しかし、なぜ単一のレプリカで高可用性を実現できないのかと疑問に思うかもしれません。問題は、Kubernetes 内の多くのエンティティ (Node、Pod、ReplicaSet、Deployment など) が非永続的であることです。つまり、特定の条件下では、それらが自動的に削除または再作成される可能性があります。したがって、Kubernetes クラスター自体とその中で実行されるアプリケーション サービスの両方でこれを考慮する必要があります。 たとえば、オートスケーラー サービスを使用してノードの数をスケールダウンすると、そのノード上で実行されているポッドを含む一部のノードが削除されます。アプリケーションにインスタンスが 1 つしかなく、削除されたノードで実行されている場合、対応する Pod が新しいノードで再作成されるため、通常は短時間ですが、この時点でアプリケーションが使用できなくなることがあります。 一般的に、アプリケーションのコピーが 1 つしかない場合、予期しない停止が発生するとダウンタイムが発生します。つまり、単一障害点を防ぐために、実行中のアプリケーションのコピーを少なくとも 2 つ維持する必要があります。 レプリカの数が多いほど、一部のレプリカに障害が発生した場合でもアプリケーションの計算能力の低下が少なくなります。たとえば、レプリカが 2 つあり、そのうちの 1 つがノード上のネットワークの問題により失敗したとします。アプリケーションが処理できる負荷は半分になります (2 つのレプリカのうち 1 つだけが使用可能になります)。もちろん、新しいレプリカが新しいノードにスケジュールされ、アプリケーションの負荷容量は完全に回復されます。しかし、それまでは負荷の増加によってサービスが中断される可能性があるため、いくつかのレプリカを保持する必要があります。 上記の推奨事項は、HorizontalPodAutoscaler が使用されていない場合に該当します。複数のレプリカを持つアプリケーションの場合、最善の代替策は、HorizontalPodAutoscaler を構成してレプリカの数を管理させることです。 HorizontalPodAutoscaler については、この記事の最後で詳しく説明します。 2. アップデート戦略デプロイメントのデフォルトの更新戦略では、古い ReplicaSet Pod と新しい ReplicaSet Pod の数を更新前の数の 75% に減らす必要があります。そのため、更新プロセス中に、アプリケーションの計算能力が通常レベルの 75% まで低下し、部分的な障害 (アプリケーション パフォーマンスの低下) が発生する可能性があります。 strategy.RollingUpdate.maxUnavailable パラメータを使用すると、更新中に使用できなくなる可能性のある Pod の最大割合を設定できます。したがって、25% の Pod が利用できない場合でもアプリケーションがスムーズに実行できるようにするか、maxUnavailable パラメータを下げてください。 maxUnavailable パラメータは丸められることに注意してください。 デフォルトの更新戦略 (RollingUpdate) にはちょっとしたトリックがあります。アプリケーションのローリング更新中は、マルチコピー戦略が有効なままになり、すべてのアプリケーションが更新されるまで、古いバージョンと新しいバージョンが同時に存在します。ただし、何らかの理由でアプリケーションの異なるレプリカや異なるバージョンを並行して実行できない場合は、strategy.type: Recreate パラメータを使用できます。再作成戦略では、新しい Pod を作成する前に既存の Pod がすべて削除されます。これにより、短時間のダウンタイムが発生します。 多くの場合、他のデプロイメント戦略 (ブルーグリーン、カナリアなど) の方が、RollingUpdate 戦略よりも優れた代替手段となります。ただし、それらの実装はアプリケーションの展開に使用されるソフトウェアに依存するため、このホワイト ペーパーではそれらについては考慮しません。 3. ノード間での均一なレプリカ分散Kubernetes の設計哲学は、ノードは信頼できないと想定することです。ノードの数が増えるほど、ソフトウェアまたはハードウェアの障害によってノードが使用できなくなる可能性が高くなります。したがって、通常はアプリケーションに複数のレプリカを展開し、実際の状況に応じてレプリカの値を調整する必要があります。値が 1 の場合、単一障害点が存在することになります。値が 1 より大きい場合でも、すべてのレプリカが同じノードにスケジュールされている場合は、単一点障害を回避できません。 単一障害点を回避するには、適切な数のレプリカを用意し、異なるレプリカを異なるノードにスケジュールする必要があります。これを行うには、同じノード上で同じデプロイメントの複数のポッドを起動しないようにスケジューラに指示します。
requiredDuringScheduling の代わりに preferredDuringSchedulingaffinity を使用することをお勧めします。後者の場合、新しいポッドに必要なノードの数が利用可能なノードの数より多いと、新しいポッドの起動に失敗する可能性があります。ただし、ノードとアプリケーション レプリカの数が事前にわかっていて、2 つの Pod が同じノードに配置されないようにする必要がある場合は、requiredDuringScheduling アフィニティが役立ちます。 4. 優先順位priorityClassName は Pod の優先度を表します。スケジューラはこれを使用して、どの Pod を最初にスケジュールするか、ノード上に Pod 用のスペースが残っていない場合にどの Pod を最初に削除するかを決定します。 複数の PriorityClass(https://kubernetes.io/docs/concepts/configuration/Pod-priority-preemption/#priorityclass) タイプのリソースを追加し、priorityClassName を使用する必要があります。 PriorityClasses がどのように変化するかの例を次に示します。
優先順位を設定すると、重要なコンポーネントが突然削除されるのを防ぐことができます。さらに、ノード リソースが不足している場合、重要なアプリケーションは重要度の低いアプリケーションを排除します。 5. コンテナ内のプロセスを停止するSTOPSIGNAL で指定されたシグナル (通常は TERM シグナル) がプロセスに送信され、プロセスが停止します。ただし、一部のアプリケーションはこれを適切に処理できず、正常にシャットダウンできません。 Kubernetes で実行されるアプリケーションでも同様です。 たとえば、以下で説明するように、nginx を正しくシャットダウンするには、次のような preStop フックが必要です。
上記の簡単な説明:
STOPSIGNAL がどのように処理されるかは、アプリケーション自体によって異なります。実際には、ほとんどのアプリケーションでは、STOPSIGNAL の処理方法を Google などで調べる必要があります。信号が適切に処理されない場合は、preStop フックを使用して問題を解決できます。もう 1 つのオプションは、STOPSIGNAL を、アプリケーションが正しく処理できる (そして正常にシャットダウンできる) シグナルに置き換えることです。 terminationGracePeriodSeconds は、アプリケーションをシャットダウンするためのもう 1 つの重要なパラメーターです。アプリケーションが正常にシャットダウンする期間を指定します。アプリケーションがこの時間枠内 (デフォルトでは 30 秒) に終了しない場合は、KILL 信号が受信されます。したがって、preStop フックの実行やアプリケーション STOPSIGNAL の終了に 30 秒以上かかる可能性がある場合は、terminateGracePeriodSeconds パラメータを増やす必要があります。たとえば、Web サービス クライアントからの一部の要求 (大きなファイルのダウンロードを含む要求など) が完了するまでに長い時間がかかる場合は、この値を増やす必要がある場合があります。 preStop フックにはロック メカニズムがあり、つまり、STOPSIGNAL シグナルは preStop フックの実行が完了した後にのみ送信できることに注意してください。一方、preStop フックの実行中は、terminationGracePeriodSeconds のカウントダウンが継続されます。フックによって開始され、コンテナ内で実行されているすべてのプロセスは、TerminationSeconds が期限切れになると終了します。 さらに、一部のアプリケーションには、期限を設定する特定の設定があり、期限が過ぎるとアプリケーションを終了する必要があります (たとえば、Sidekiq の --timeout オプション)。したがって、アプリケーションにこの構成がある場合は、その値が terminationGracePeriodSeconds よりわずかに小さくなるようにする必要があります。 6. リソースを確保するスケジューラは、Pod の resources.requests を使用して、どのノードに Pod をスケジュールするかを決定します。たとえば、Pod のリソース要求を満たすのに十分な空き (つまり、要求されていない) リソースがないノードでは、Pod をスケジュールすることはできません。一方、resources.limits を使用すると、それぞれのリクエストを大幅に超過する Pod のリソース消費を制限できます。 良いアプローチは、リクエストと同じ制限を設定することです。リクエストよりもはるかに高い制限を設定すると、一部のノード上の Pod が要求されたリソースを取得できない状況が発生する可能性があります。これにより、ノード上の他のアプリケーション (またはノード自体) が失敗する可能性があります。 Kubernetes は、リソース提案に基づいて各 Pod に QoS クラスを割り当てます。次に、K8s は QoS クラスを使用して、どの Pod をノードから削除するかを決定します。 したがって、CPU とメモリの両方に対して要求と制限を設定する必要があります。 Linux カーネルのバージョンが 5.4 より前の場合 (https://engineering.indeedblog.com/blog/2019/12/cpu-throttling-regression-fix/)。場合によっては省略できるのは CPU 制限のみです (EL7/CentOS7 の場合、制限をサポートするにはカーネル バージョンが 3.10.0-1062.8.1.el7 より大きい必要があります)。 さらに、一部のアプリケーションのメモリ消費量は無制限に増加する傾向があります。良い例としては、キャッシュ用の Redis や、基本的に「スタンドアロン」で実行されるアプリケーションが挙げられます。ノード上の他のアプリケーションへの影響を制限するために、消費するメモリの量に制限を設定できます (設定する必要があります)。 唯一の問題は、アプリケーションがこの制限に達すると、アプリケーションが強制終了されることです。アプリケーションはこのシグナルを予測/処理できないため、正常にシャットダウンできない可能性があります。そのため、Kubernetes の制限に加えて、アプリケーション自体に固有のメカニズムを使用してメモリ消費を制限し、Pod の limits.memory パラメータで設定された値を超えないように (またはそれに近づかないように) することを強くお勧めします。 この問題を解決するのに役立つ Redis 構成の例を次に示します。
Sidekiq に関しては、Sidekiq ワーカー キラー (https://github.com/klaxit/sidekiq-worker-killer) を使用できます。
明らかに、これらすべてのケースでは、上記のメカニズムをトリガーするには、limits.memory がしきい値を超えている必要があります。 7. プローブKubernetes では、プローブ (ヘルス チェック) を使用して、トラフィックをアプリケーションに切り替えることができるかどうか (準備プローブ)、およびアプリケーションを再起動する必要があるかどうか (稼働プローブ) を判断します。これらは、デプロイメントの更新と新しいポッドの起動において重要な役割を果たします。 まず、すべてのプローブ タイプに対して、timeoutSeconds パラメータに高い値を設定するという提案をします。デフォルト値の 1 秒は短すぎるため、準備プローブと生存プローブに重大な影響を及ぼします。 timeoutSeconds が低すぎると、アプリケーションの応答時間の増加 (通常はサービス負荷分散によりすべての Pod で同時に発生) により、それらの Pod がロードバランサーから削除される (準備プローブが失敗した場合) か、さらに悪いことに、カスケード コンテナーの再起動 (活性プローブが失敗した場合) が発生する可能性があります。 7.1.生体プローブ実際には、活性プローブは思ったほど広く使用されていません。その目的は、アプリケーションがフリーズしたときにコンテナを再起動することです。ただし、現実には、アプリケーションのデッドロックは定期的に発生するものではなく、例外的なものです。何らかの理由でアプリケーションがこの異常な動作を引き起こす場合 (たとえば、データベースの切断後にデータベースへの接続を復元できない場合)、活性プローブに基づく回避策を「追加」するのではなく、アプリケーション内で問題を修正する必要があります。 活性プローブを使用してこれらの状態を確認することはできますが、デフォルトでは活性プローブを使用しないか、TCP 接続のプローブなどの基本的な活性検出のみを実行することをお勧めします (タイムアウト値を大きく設定することを忘れないでください)。この方法では、アプリケーションは、無限の再起動ループ (つまり、再起動しても何も行われない) に入るのではなく、明らかなデッドロックに応じて再起動します。 不適切な活性プローブの設定によって生じるリスクは非常に深刻です。最も一般的なケースでは、活性プローブは、アプリケーションの負荷の増加 (タイムアウト パラメータで指定された時間内に完了できないだけ) または現在チェック中の外部依存関係の状態 (直接的または間接的) が原因で失敗します。 後者の場合、すべてのコンテナが再起動されます。 最良の場合、これによって何も起こりませんが、最悪の場合、アプリケーションが完全に使用できなくなり、場合によっては長期間使用できなくなる可能性があります。ポッドのコンテナのほとんどが短期間内に再起動されると、アプリケーションが長時間完全に使用できなくなる可能性があります (レプリカの数が多い場合)。一部のコンテナは他のコンテナよりも早く READY になる可能性があり、全体的な負荷は限られた数の実行中のコンテナ間で分散されます。これにより、最終的に活性プローブがタイムアウトになり、さらに再起動がトリガーされることになります。 また、アプリケーションに確立された接続の数の制限があり、その制限に達した場合は、活性プローブが応答を停止しないようにしてください。通常、このような問題を回避するには、活性プローブ用に別のアプリケーション スレッド/プロセスを用意する必要があります。たとえば、アプリケーションに 11 個のスレッド (クライアントごとに 1 つ) がある場合、クライアントの数を 10 に制限して、活性プローブに使用できる空きスレッドを確保できます。 また、もちろん、ライブネス プローブに外部依存関係チェックを追加しないでください。 7.2.準備状況調査readinessProbe の設計はあまり成功していないことが判明しました。 readinessProbe は 2 つの異なる機能を組み合わせています。
実際には、最初の機能はほとんどの場合に必要ですが、2 番目の機能は活性プローブと同じ頻度でのみ使用されます。不適切に構成された準備プローブは、活性プローブと同様の問題を引き起こす可能性があります。最悪の場合、アプリケーションが長期間使用できなくなる可能性もあります。 準備プローブが失敗すると、Pod はトラフィックの受信を停止します。ほとんどの場合、トラフィックは通常、Pod 間でほぼ均等に分散されるため、この動作は役に立ちません。したがって、一般的に、準備プローブはどこでも機能するか、同時に多数の Pod では機能しません。場合によっては、このような動作が役に立つことがあります。しかし、私の経験では、これは主に特定の特殊なケースで役立ちます。 それでも、準備プローブには別の重要な機能があります。それは、まだ準備ができていないアプリケーションに負荷を転送しないように、新しく作成されたコンテナーがいつトラフィックを処理できるかを判断するのに役立ちます。この準備プローブ機能はいつでも必要になります。 つまり、準備プローブの 1 つの機能は需要が高いのに対し、もう 1 つの機能はまったく必要ありません。スタートアップ プローブの導入により、この問題は解決されます。これは Kubernetes 1.16 で初めて登場し、v1.18 でベータ版となり、v1.20 で安定しました。したがって、Kubernetes バージョン 1.18 未満では準備プローブを使用してアプリケーションの準備ができているかどうかを確認するのが適切ですが、Kubernetes バージョン 1.18 以上では起動プローブを使用してアプリケーションの準備ができているかどうかを確認することをお勧めします。同様に、アプリケーションの起動後に単一の Pod へのトラフィックを停止する必要がある場合は、Kubernetes 1.18 以降で準備プローブを使用できます。 7.3.プローブの開始起動プローブは、コンテナ内のアプリケーションの準備ができているかどうかを確認します。次に、現在のポッドをトラフィックを受信する準備ができたものとしてマークするか、デプロイメントの更新/再起動を続行します。準備プローブとは異なり、起動プローブはコンテナの起動後に動作を停止します。 スタートアップ プローブを使用して外部依存関係を確認することはお勧めしません。失敗するとコンテナの再起動がトリガーされ、最終的に Pod が CrashLoopBackOff 状態になる可能性があります。この状態では、失敗したコンテナの再起動を試行する間の遅延は最大 5 分になる可能性があります。これにより、アプリケーションは再起動の準備ができているにもかかわらず、コンテナは CrashLoopBackOff による再起動の試行期間が経過するまで待機し続けるため、不要なダウンタイムが発生する可能性があります。 アプリケーションがトラフィックを受信し、Kubernetes バージョンが 1.18 以上の場合は、スタートアップ プローブを使用する必要があります。 また、initialDelaySeconds を設定するのではなく、failureThreshold 構成を増やすことがプローブを構成するための推奨される方法であることにも注意してください。これにより、コンテナはできるだけ早く利用できるようになります。 8. 外部依存関係を確認するご存知のように、準備プローブは外部依存関係 (データベースなど) をチェックするためによく使用されます。このアプローチは必要ですが、外部依存関係をチェックするメソッドと、Pod 内のアプリケーションがフル稼働しているかどうかをチェックするメソッド (およびアプリケーションへのトラフィックを遮断するメソッド) を分離することもお勧めします。 メイン コンテナの startupProbe/readinessProbe を実行する前に、initContainers を使用して外部依存関係を確認できます。当然ながら、この場合、準備プローブを使用して外部依存関係を確認する必要はなくなります。 initContainers ではアプリケーション コードを変更する必要はありません。アプリケーション コンテナー内の外部依存関係を検査するために追加のツールを埋め込む必要はありません。通常、実装はかなり簡単です。
9. 完全な例以下は、上記の推奨事項をすべて組み込んだステートレス アプリケーションの運用レベルのデプロイメントの完全な例です。どなたにも参考になる内容です。 Kubernetes 1.18 以上と、カーネル バージョン 5.4 以上の Ubuntu/Debian ベースの Kubernetes ノードが必要になります。
10. ポッドディスラプション予算PodDisruptionBudget (PDB: https://kubernetes.io/docs/concepts/workloads/Pods/disruptions/#Pod-disruption-budgets) メカニズムは、実稼働環境で実行されるアプリケーションに不可欠なツールです。同時に使用できないアプリケーション ポッドの数の最大制限を指定する方法を提供します。上記では、潜在的にリスクのある状況を回避するのに役立ついくつかの方法について説明しました。アプリケーションの複数のコピーを実行する、PodAntiAffinity を指定する (複数の Pod が同じノードに割り当てられないようにする) などです。 ただし、複数の K8s ノードが同時に使用できなくなる状況が発生する可能性があります。たとえば、インスタンス ノードをより高い構成のインスタンス ノードにアップグレードするとします。これら以外にも理由があるかもしれませんが、この記事では詳しく説明しません。最後の問題は、複数のノードが同時に削除されることです。 Kubernetes 内のすべてが一時的なものだと思われるかもしれません。ノードに障害が発生したり、ノードが削除されたりしても、そのノード上の Pod は他のノード上で自動的に再構築されるので、何が問題になるのでしょうか?さて、引き続き見ていきましょう。 アプリケーションに 3 つのレプリカがあると仮定します。負荷はそれらの間で均等に分散され、ポッドはノード全体に分散されます。この場合、レプリカの 1 つに障害が発生しても、アプリケーションは引き続き実行されます。ただし、2 つのレプリカに障害が発生すると、サービス全体のパフォーマンスが低下します。つまり、1 つの Pod だけでは負荷全体を処理できないのです。クライアントは 5XX エラーを受信し始めます。 (もちろん、nginx コンテナでレート制限を設定することもできます。この場合、エラーは 429 Too Many Requests になります。ただし、サービスは依然として低下します)。 ここで PodDisruptionBudget が役立ちます。構成リストを見てみましょう:
上記の構成リストは非常にシンプルです。おそらくそのほとんどはご存知だと思いますが、その中でも maxUnavailable が最も興味深いでしょう。このフィールドは、同時に使用できないポッドの最大数を示します。数値またはパーセンテージのいずれかになります。 アプリケーション用に PDB が構成されていると想定します。何らかの理由で、2 つ以上のノードがアプリケーション ポッドの削除を開始するとどうなりますか?上記の PDB では、一度に 1 つの Pod のみを削除できます。したがって、2 番目のノードは、レプリカの数が削除前のレベルに戻るまで待機してから、2 番目のレプリカを削除します。 代わりに、minAvailable パラメータを設定することもできます。例えば:
このパラメータにより、クラスター内のレプリカの少なくとも 80% が常に利用可能になります。したがって、必要に応じてレプリカの 20% のみを削除できます。 minAvailable は絶対数またはパーセンテージで表すことができます。 ただし、注意点があります。PodAntiAffinity 条件を満たすには、クラスター内に十分なノードがなければなりません。そうしないと、レプリカが削除されたが、適切なノードが不足しているためにスケジューラがレプリカを再デプロイできないという状況が発生する可能性があります。したがって、ノードのドレインは完了するまでに長い時間がかかり、アプリケーションのコピーは 3 つではなく 2 つになります。もちろん、 kubectl describe コマンドを使用して待機中の Pod を表示し、何が起こったかを確認し、問題をトラブルシューティングすることもできます。ただし、このような事態が発生しないようにすることが最善です。 要約すると、システムの重要なコンポーネントに対しては常に PDB を構成します。 11. 水平ポッドオートスケーラー別のシナリオを考えてみましょう。アプリケーションの予期しない負荷が通常よりも大幅に高くなった場合はどうなるでしょうか?はい、クラスターを手動でスケーリングすることは可能ですが、これは推奨される方法ではありません。 ここで、HorizontalPodAutoscaler (HPA、https://kubernetes.io/docs/tasks/run-application/horizontal-Pod-autoscale/) が登場します。HPA を使用すると、メトリックを選択し、それをトリガーとして使用して、メトリックの値に基づいてクラスターを自動的にスケールアップ/スケールダウンできます。静かな夜に、クラスターが突然爆発的に増加し、トラフィックが急増したと想像してください。 Reddit ユーザーがサービスを発見し、CPU 負荷 (またはその他の Pod メトリック) が増加してしきい値に達すると、HPA が起動します。HPA はクラスターをスケーリングして、多数の Pod に負荷を均等に分散します。 これにより、すべての受信リクエストが正常に処理されます。同様に重要なのは、負荷が平均に戻ると、HPA はクラスターをスケールダウンしてインフラストラクチャ コストを削減することです。それは素晴らしいですね。 HPA が追加するレプリカの数を計算する方法を見てみましょう。これは公式ドキュメントに記載されている式です:
ここで、次の仮定を立てます。
この場合、結果は 3 * ( 100 / 60 ) となり、これは「およそ」 5 つのレプリカになります (HPA は結果を切り上げます)。したがって、申請書には追加のコピーが 2 つ発行されます。もちろん、HPA の動作は継続されます。負荷が減少すると、HPA はクラスターを縮小するために必要なレプリカの数を (上記の式を使用して) 計算し続けます。 さらに、私たちが最も懸念している部分がもう一つあります。どのような指標を使用すべきでしょうか?最初に思い浮かぶのは、CPU やメモリの使用率などの主要なメトリックです。これは、CPU とメモリの消費量が負荷に比例する場合に機能します。しかし、Pod が異なるリクエストを処理する場合はどうなるでしょうか?リクエストによっては、大きな CPU サイクルを必要とするものもあれば、大量のメモリを消費するものもあり、また最小限のリソースしか必要としないものもあります。 たとえば、RabbitMQ キューとそれを処理するインスタンスを見てみましょう。キューに 10 個のメッセージがあると仮定します。監視により、メッセージが着実かつ定期的にキューから削除されていることが示されます (RabbitMQ の用語で)。つまり、キュー内のメッセージの平均数は 10 個であれば問題ないと考えられます。しかし、負荷が突然増加し、キューが 100 メッセージにまで増加します。ただし、ワーカーの CPU とメモリの消費量は同じままです。ワーカーはキューを着実に処理し、キューには約 80 ~ 90 件のメッセージを残し続けます。 しかし、カスタム メトリックを使用してキュー内のメッセージの数を表す場合はどうなるでしょうか?カスタム メトリックを次のように構成します。
したがって、3 * ( 80 / 15 ) = 16 です。この場合、HPA はワーカーの数を 16 に増やすことができ、ワーカーはキュー内のすべてのメッセージを迅速に処理します (この時点で、HPA はワーカーの数を再び減らします)。ただし、この数のポッドに対応するには、必要なインフラストラクチャがすべて整っている必要があります。つまり、既存のノードに適合する必要があり、Cluster Autoscaler (https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler) の場合は、インフラストラクチャ ベンダー (クラウド プロバイダー) によって新しいノードがプロビジョニングされる必要があります。つまり、クラスター リソースの計画に戻ります。 それでは、いくつかのリストを見てみましょう。
これは非常に簡単です。 CPU 負荷が 50% に達すると、HPA はレプリカの数を最大 10 までスケーリングし始めます。 興味深い事例があります。
この例では、HPA はカスタム メトリック (https://kubernetes.io/docs/tasks/run-application/horizontal-Pod-autoscale/#support-for-custom-metrics) を使用することに注意してください。キューのサイズ (queue_messages メトリック) に基づいてスケーリングの決定が行われます。キュー内のメッセージの平均数が 10 であることを考えると、しきい値を 15 に設定します。これにより、レプリカの数をより正確に管理できます。ご覧のとおり、カスタム メトリックを使用すると、CPU ベースのメトリックと比較して、より正確なクラスターの自動スケーリングが可能になります。 追加機能: HPA 構成オプションは多様です。たとえば、さまざまなインジケーターを組み合わせることができます。次のリストでは、CPU 使用率とキュー サイズの両方を使用してスケーリングの決定をトリガーします。
この場合、HPA はどのような計算アルゴリズムを使用するのでしょうか?そうですね、利用されるメトリックに関係なく、計算されたレプリカの最大数を使用します。たとえば、CPU メトリックに基づく値では 5 つのレプリカを追加する必要があることが示されていても、キュー サイズ メトリックに基づく値では 3 つの Pod しか提供されない場合、HPA は大きい方の値を使用して 5 つの Pod を追加します。 Kubernetes 1.18 のリリースにより、scaleUp および scaleDown シナリオを定義できるようになりました (https://kubernetes.io/docs/tasks/run-application/horizontal-Pod-autoscale/#support-for-configurable-scaling-behavior)。例えば:
上記のリストにあるように、2 つの部分があります。最初のもの ( scaleDown ) はスケールダウン パラメータを定義し、2 番目のもの ( scaleUp ) はスケールアップに使用されます。各パーツには stabilizationWindowSeconds があります。これにより、レプリカの数が変動し続ける場合に、いわゆる「スラッシング」(または不必要なスケーリング)を防ぐことができます。このパラメータは基本的に、レプリカの数が変更された後のタイムアウトとして機能します。 それでは、両方の戦略についてお話ししましょう。 scaleDown ポリシー タイプ: Percent を使用すると、特定の期間にスケールダウンする Pod の割合を指定できます。負荷が周期的な動作をする場合は、パーセンテージを減らして期間を長くする必要があります。この場合、負荷が減少すると、HPA は (その公式に従って) 一度に多数の Pod を強制終了するのではなく、対応する Pod を徐々に強制終了します。さらに、指定された期間内に HPA が強制終了できるタイプの Pod の最大数を設定できます。 selectpolicy:minパラメーターに注意してください。これは、HPAが最小数のポッドに影響を与える戦略を使用することを意味します。したがって、パーセンテージ値(上記の例では5%)が数値の代替値(上記の例では5ポッド)よりも少ない場合、HPAはパーセンテージ値を選択します。対照的に、SelectPolicy:Maxは逆の効果があります。 同様のパラメーターは、スケールアップセクションで使用されています。ほとんどの場合、クラスターは(ほぼ)即座にスケーリングする必要があることに注意してください。わずかな遅延でさえユーザーとその経験に影響を与える可能性があるためです。したがって、このセクションでは、stabilizationWindowsSecondsが0に設定されています。負荷に循環パターンがある場合、HPAは、必要に応じて(HPAマニフェストで定義されているように)MaxReplicasまでレプリカカウントを増加させることができます。当社のポリシーにより、HPAは10秒ごとに現在実行されているレプリカの最大100%を追加することができます(期間秒:10)。 最後に、SelectPolicyパラメーターを無効に設定して、特定の方向にズームをオフにすることができます。
ほとんどの場合、HPAが予想どおりに機能していない場合、ポリシーは使用されます。ポリシーは柔軟性を提供しますが、構成リストをより困難にすることもできます。 最近、HPAはポッドのグループで個々のコンテナのリソース使用量を追跡することができました(kubernetes 1.20でアルファ機能として導入)(https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#container-resource-metrics。 HPA:要約完全なHPAチェックリストの例で、この段落を終了しましょう。
この例は参照用のみであることに注意してください。自分の操作の詳細に適応する必要があります。 HORIZONTAL POD Autoscalerの紹介:HPAは、生産環境に適しています。ただし、HPAのインジケーターを選択する場合は、注意して、できるだけ多くの状況を考慮する必要があります。誤ったメトリックまたは誤ったしきい値は、無駄なリソース(不必要なレプリカから)または劣化したサービス(十分なレプリカがない場合)になります。アプリケーションの動作を綿密に監視し、適切なバランスに達するまでテストしてください。 12。verticalPodautoscalerVPA(https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler)コンテナとセットのリソース要件(対応するモードが有効になっている場合)を分析します。 たとえば、インポートされたライブラリが巨大なリソース消費者であるか、コードが十分に最適化されていないことを発見するために、いくつかの新しい機能を使用してアプリケーションの新しいバージョンを展開するとしましょう。言い換えれば、アプリケーションのリソース要件が増加します。テスト中にこれに気付かない(生産時にそうするようにアプリケーションをロードするのは難しいためです)。 もちろん、更新が開始される前に、関連するリクエストと制限はすでにアプリケーションに設定されています。現在、アプリケーションはメモリ制限に達し、そのポッドはOOMのために殺されます。 VPAはこれを防ぎます!一見、VPAは広く使用する必要がある素晴らしいツールのように見えます。しかし、実際の生活では、以下で簡単に説明するように、これは当てはまりません。 主な問題(まだ解決されていない)は、リソースの変更を有効にするためにPODを再起動する必要があることです。将来的には、VPAはポッドを再起動せずに変更することができますが、現在はこれを行うことはできません。でも心配しないでください。 「よく書かれた」アプリケーションがあり、再展開の準備ができています(たとえば、多数のコピー、そのpodantiaffity、poddistributionbudget、horizontalpodautoscalerはすべて慎重に構成されています)、これは大したことではありません。この場合、(おそらく)VPAアクティビティにさえ気付かないでしょう。 残念ながら、アプリケーションの再配置はあまり良くないなど、他の快適でない状況が発生する可能性があります。レプリカの数はノードの不足のために制限されます。最悪の場合、アプリケーションは最悪の場合、負荷の増加によりPODのリソース消費が増加し、HPAはクラスターを緩和し、VPAのパラメーターを緩和します。したがって、高負荷は残りのポッドに分布しています。これらのいくつかは、崩壊し、事態を悪化させ、波及効果の失敗につながる可能性があります。 これが、さまざまなVPA動作モードをより深く理解することが重要である理由です。最も簡単な「オフモード」から始めましょう。 オフモード:このパターンは、ポッドのリソース消費を計算して提案することです。ほとんどの場合、このモードを使用します(このモードをお勧めします)。しかし、最初に、いくつかの例を見てみましょう。 いくつかの基本リストは次のとおりです。
このリストのパラメーターについては詳しく説明しません。記事(https://povilasv.me/vertical-pod-autoscaling-the-finitive-guide/)は、VPAの機能と詳細について詳しく説明しています。要するに、VPAターゲット(TargetRef)を指定し、更新ポリシーを選択します。 さらに、VPAが使用できるリソースの上限と下限を指定します。主にupdateModeパーツに焦点を合わせます。 「Recreate」または「Auto」モードでは、VPAがPODを再作成するため、結果の短期サービスサスペンションリスクを考慮する必要があります(PODのリソースパラメーターアップデートの上記のパッチが利用可能になるまで)。私たちはそれを望んでいないので、私たちは「オフ」モードを使用します:
VPAはメトリックの収集を開始します。 kubectl describe vpaコマンドを使用して、提案を表示できます(VPAを数分間実行させてください):
数日間(1週間、1か月など)走った後、VPAの推奨事項がより正確になります。次に、アプリマニフェストの制限を調整するのに最適な時期があります。これにより、リソースの不足によりOOM終了を回避し、インフラストラクチャを保存できます(初期リクエスト/制限が高すぎる場合)。 それでは、VPAの使用に関するいくつかの詳細について話しましょう。 他のVPAモード:「初期」モードでは、VPAはポッドが起動したときにリソースを割り当て、後で変更しなくなったことに注意してください。したがって、過去1週間の負荷が比較的低い場合、VPAは新しく作成されたポッドのリクエスト/制限を低く設定します。負荷が突然増加すると、リクエスト/制限がそのような負荷に必要な量よりもはるかに低くなるため、問題を引き起こす可能性があります。このパターンは、負荷が均等に分布し、線形で成長する場合に役立つ場合があります。 「Auto」モードでは、VPAはポッドを再現します。したがって、アプリケーションは正しく再起動する必要があります。適切に閉じない場合(つまり、既存の接続などを正しく閉じるなど)、回避可能な5XXエラーをキャッチする可能性が高いでしょう。 StateFulsetで自動モードを使用することをお勧めすることはまれです。MPAがPostgreSQLリソースを生産に追加しようとしていることを想像してください... 開発環境に関しては、生産で使用するために(後)受け入れることができるリソースレベルを見つけるために自由に実験できます。 「初期」モードでVPAを使用すると、RedisクラスターのMaxmemoryパラメーターを使用するとします。必要なときに調整するために変更する必要がある可能性が高いです。問題は、RedisがCGROUPSレベルの制限を気にしないことです。 言い換えれば、ポッドに1GBのメモリキャップがある場合、Maxmemoryは2GBに設定され、大きなリスクがあります。しかし、どのようにしてmaxmemoryを制限と同じに設定できますか?まあ、方法があります! VPAの推奨値を使用できます。
環境変数を使用してメモリ制限を取得し(およびアプリケーション要件から10%を減らします)、結果値をMaxMemoryに設定できます。デフォルトのRedisコンテナイメージは、環境変数を使用して通過するためにMaxmemoryをサポートしていないため、Redis構成を処理するためにSEDが使用するinitコンテナで何かをする必要があるかもしれません。それにもかかわらず、このソリューションは実用的です。 最後に、VPAが一度にすべてのデイモンセットポッドを追放するという事実に注意を向けたいと思います。現在、この問題を修正するパッチを開発しています(https://github.com/kubernetes/kubernetes/pull/98307)。 最終的なVPAの推奨事項:「オフ」モードは、ほとんどの場合に適しています。開発環境で「自動」モードと「初期」モードを試すことができます。 多くの経験を蓄積し、徹底的にテストした場合にのみ、生産でVPAを使用できます。また、あなたは自分が何をしているのか、なぜそれをしているのかを明確に理解する必要があります。 同時に、ポッドリソースのホットな(再起動フリーの)アップデート機能を熱心に楽しみにしています。 HPAとVPAの両方を使用することにはいくつかの制限があることに注意してください。たとえば、CPUベースまたはメモリベースのメトリックがトリガーとして使用される場合、VPAはHPAで使用しないでください。その理由は、しきい値に到達すると、VPAがリソース要求/制限を増やし、HPAが新しいコピーを追加するためです。 したがって、負荷は劇的に低下し、プロセスは逆に進み、「ジッター」になります。公式文書(https://github.com/kubernetes/autoscaler/tree/master/vertical-pod-autoscaler#known-limitations)は、既存の制限をより明確に示しています。 。 結論は:Kubernetesの高可用性展開アプリケーションのいくつかの提案と関連するケースを共有しました。これは、高可用性アプリケーションの展開に役立ちます。スケジューラ操作、更新ポリシー、優先順位、プローブなどについて説明しました。最後の部分では、残りの3つの重要なトピックについて詳しく説明します:PoddisuptionBudget、HorizontalPodautoscaler、およびVerticalPodautoscaler。 質問に記載されている多くのケースは、生成する実際のシナリオに基づいています。使用する場合は、自己生成環境に従って調整してください。 この記事を通して、読者が自分の環境に基づいて検証し、それぞれの世代の経験を一緒に共有し、Kubernetes関連のテクノロジーの開発と進歩を共同で促進できることを願っています。繰り返しになりますが、この記事を注意深く読んで多くの時間を費やしてくれた読者に感謝したいと思います。 参考記事:
|
<<: ByteDanceのインフラストラクチャチームは、クラウドネイティブストレージソリューションcsi-driver-nvmfをK8S CSIコミュニティに寄贈しました。
>>: パブリッククラウド?プライベートクラウド?ハイブリッドクラウド?所により曇り?業界クラウド?違いが分からない 2
タイトルを見て、「Ahrefs? バックリンクやキーワードランキングをチェックするだけのツールじゃな...
最近、A5 ウェブマスターのウェブサイトに「本物のオリジナル SEO 記事の書き方を教える」という記...
今年8月の人気記事「6年、公会計が運命を変えた」は、春秋文体で公会計の発展に壮大な雰囲気を与えた。実...
IT Homeは11月29日、米国ラスベガスで本日開催されたAmazonの「AWS re:Inven...
9月25日、百度とインテルが共同で立ち上げた「5G+AIエッジコンピューティング共同実験室」が正式に...
【51CTO.comオリジナル記事】年末から年明けにかけて、誰もが何らかの総括や予測を立て、2021...
業界の専門家は、唯一の「本物の」クラウドはパブリッククラウドであると指摘しています。企業には適してい...
企業は、文化的な変化に適応し、主要な指標を整理し、自動化を実装し、そして最も重要なことに、ソフトウェ...
現在、国内のオンラインオーディオコンテンツ消費市場は急速な発展段階にあります。 Analysys I...
SEO ビジネスについて顧客と話し合うとき、顧客を見分ける能力を持つことは非常に重要です。ある程度の...
サーバーで遊ぶ人なら、ほとんどが wholesaleinternet.net を知っていると思います...
ローカルWeiboもWeiboであり、Sina WeiboやTencent Weiboからの圧力にも...
最近、「Gartner の OpenStack 企業トップ 8」と題されたメディアの一連の記事が、一...
検索エンジンの魅力は皆さんもよくご存知だと思います。インターネットの急速な発展に伴い、あらゆる分野の...
iovz は、韓国の SK データセンターにクラウド サーバーを提供しています。このサーバーは中国本...