ゼロから始めるK8 |ステートフルアプリケーションオーケストレーション– StatefulSet
https:// www.kubernetes.org.cn/6724.html
著者| Jiuzhu Alibabaテクニカルエキスパート
この記事は、「CNCF x Alibaba Cloudネイティブテクノロジーオープンコース」の講義22から編集したものです。
「Alibaba Cloud Native」パブリックアカウントに従い、キーワード「Getting Started」に返信して、K8sシリーズの記事のPPTを最初からダウンロードします。
はじめに:ステートフルアプリケーションの展開と配信は、アプリケーションの運用と保守の分野で常に困難の1つでした。ディスクの永続的な状態、各マシンには独立した安定したネットワーク識別、リリース順序の確実性など、一般的なステートフル要件があります。このような問題に対応するため、Kubersnetesはステートフルセットコントローラーをワークロードとして提供し、ステートフルアプリケーションのデプロイとK8s環境へのランディングを支援します。
1.「ステートフル」要件
以前、アプリケーションオーケストレーション管理ツールとしての展開について説明しましたが、どのような機能を提供するのですか?
以下に示すように:
- まず、予想されるポッドの数の定義をサポートします。コントローラーは、希望するバージョンのポッドの数と予想される数を維持します。
- 次に、ポッドのリリース方法の構成をサポートします。構成が完了すると、コントローラーは指定された戦略に従ってポッドを更新します。同時に、更新プロセス中に、使用できないポッドの数が定義した範囲内であることも確認します。
- 3番目に、リリースプロセス中に問題が発生した場合、Deploymentはワンクリックロールバックもサポートします。
簡単に言うと、Deploymentは、管理するポッドの同じバージョンはすべて同一のコピーであると考えています。つまり、Deployment Controllerの観点から見ると、内部にデプロイされているアプリケーションや動作に関係なく、同じバージョンのすべてのポッドはまったく同じです。
このような機能は、ステートレスアプリケーションでサポートされています。
分析が必要
たとえば、以下の図に示されているいくつかの要件:
上記の要件はすべてDeploymentでは満たすことができないため、Kubernetesコミュニティは、ステートフルアプリケーションを管理するためのStatefluSetと呼ばれるリソースを提供しています。
StatefulSet:ステートフルアプリケーション管理用コントローラー
実際、コミュニティの多くのステートレスアプリケーションもStatefulSetを通じて管理されていますが、この記事を読むことで、なぜステートフルアプリケーションもStatefulSetを通じて管理するのか、誰もが理解できるでしょう。
上の図の右側に示すように、StatefulSetのポッドにはすべて、0から始まり、定義されたレプリカの数が1つ減少するまで番号が付けられています。各ポッドには、独立したネットワークID(ホスト名、独立したpvcおよびpvストレージ)があります。この場合、同じStatefulSetの下の異なるポッドには、異なるネットワークIDと独自の専用ストレージディスクがあり、ほとんどのステートフルアプリケーションのニーズを十分に満たすことができます。
上の画像の右側に示すように:
- まず、各ポッドには注文番号があり、番号に従って作成、削除、更新されます。
- 次に、ヘッドレスサービスを構成することにより、各ポッドに一意のネットワーク識別子(ホスト名)があります。
- 3番目に、pvcテンプレートであるpvcテンプレートを構成することで、各ポッドに1つ以上のpvストレージディスクがあります。
- 最後に、特定の数のグレースケールリリースがサポートされています。たとえば、StatefulSetのコピーが3つある場合、そのうちの1つまたは2つ、または3つを新しいバージョンにアップグレードするように指定できます。このようにして、グレースケールアップグレードの目的を達成します。
第二に、ユースケースの解釈
StatefulSetの例の作成
上図の左側はサービス構成です。ヘッドレスサービスを構成することで、実際に目標を達成したいと思います:StatefulSetのポッドに独立したネットワークIDがあることを期待します。ここでのサービス名はnginxと呼ばれます。
上図の右側はStatefulSet構成で、仕様にはnginxとも呼ばれるserviceNameがあります。このserviceNameを使用して、このStatefulSetが対応するサービスを指定します。
この仕様には、セレクターやテンプレートなど、よく知られているフィールドがいくつかあります。セレクターはラベルセレクターです。セレクターによって定義されたラベル選択ロジックは、app:nginxを含むテンプレートのメタデータのラベルと一致する必要があります。テンプレートでnginxコンテナを定義します。このコンテナで使用されるイメージバージョンは高山バージョンであり、公開されたポート80はWebサービスとして使用されます。
最後に、volumeMountsはtemplate.specで定義されています。このvolumeMountsは、仕様のVolumesからではなく、pvcテンプレートであるvolumeClaimTemplatesからです。pvcテンプレートでwww-storageと呼ばれるpvc名を定義しました。このpvc名は、/ usr / share / nginx / htmlディレクトリにマウントされたボリューム名としてvolumeMountsも書き込みます。このようにして、各ポッドには独立したpvcがあり、コンテナ内の対応するディレクトリにマウントされます。
サービス、StatefulSet状態
上記の2つのオブジェクトを作成すると、getコマンドを使用してService nginxリソースが正常に作成されたことがわかります。
同時に、エンドポイントを見ると、このバックエンドが3つのIPとポートを登録していることがわかります。これらの3つのIPはポッドのIPに対応し、ポートは前の仕様で構成された80個のポートに対応しています。
最後に、sts(StatefulSetの略)nginx-webを取得します。結果からわかるように、値が3/3のREADYという列があります。分母3はStatefulSetで必要な数であり、分子3はポッドがREADYで必要な状態数に達したことを示します。
ポッド、PVCステータス
下の図のgetポッドは、3つのポッドが実行状態にあり、READYであることを示しています。そのIPは、前に見たエンドポイントアドレスです。
NAMEの名前はget pvcで確認できます。プレフィックスはwww-storage、真ん中はnginx-web、サフィックスはシリアル番号です。分析により、www-storageがvolumeClaimTemplatesで定義された名前であり、中央で定義された名前がStatefulSetであり、最後のシリアル番号がポッドのシリアル番号に対応していること、つまり3つのPVCが3つのポッドによってバインドされていることがわかります。このように、異なるポッドは異なるPVCを利用します。PVCは対応するPVもバインドして、異なるPVを異なるポッドにバインドする目的を達成します。
ポッドバージョン
以前、DeploymentはReplicaSetを使用してポッドバージョンと予想されるポッド数を管理することを学びましたが、StatefulSetでは、StatefulSetコントローラーが下位ポッドを管理するため、StatefulSetはポッドラベルを使用して、このポッドのバージョンを識別します。コントローラリビジョンハッシュ。このラベルは、ポッドのDeploymentおよびStatefulSetによって挿入されたポッドテンプレートハッシュに似ています。
上の図に示すように、controller-revision-hashはgetポッドを介して表示されます。ここでのハッシュは、最初のポッドの作成に対応するテンプレートバージョンです。サフィックスが677759c9b8であることがわかります。最初にここで記録してから、ポッドのアップグレードを実行してから、controller-revision-hashが変更されるかどうかを確認します。
ミラーを更新
上記のコマンドを実行すると、上の画像の下のStatefulSet構成で、StatefulSetの画像がメインラインの新しいバージョンに更新されていることがわかります。
新しいバージョンのステータスを表示
get podコマンドを使用してリビジョンハッシュをクエリすると、3つのポッドの背後にあるcontroller-revision-hashが新しいリビジョンハッシュにアップグレードされ、後で7c55499668になります。これら3つのポッドの作成時に、シリアル番号が2のポッドが最も早く、シリアル番号が1と0であることがわかります。つまり、アップグレードプロセス中の実際のアップグレードシーケンスは2-1-0であり、ポッドはこのような逆の順序で新しいバージョンに徐々にアップグレードされ、アップグレードしたポッドは以前のポッドで使用されていたPVCも再利用します。したがって、PVストレージディスクのデータは新しいポッドにマウントされたままになります。
上の図の右上は、StatefulSetのステータスに表示されるデータです。いくつかの重要なフィールドがあります。
- currentReplica:現在のバージョンの番号を示します
- currentRevision:現在のバージョン番号を示します
- updateReplicas:新しいバージョンの数を示します
- updateRevision:更新するバージョン番号を示します
もちろん、currentReplicaとupdateReplica、およびcurrentRevisionとupdateRevisionが同じであることも確認できます。つまり、すべてのポッドが必要なバージョンにアップグレードされています。
3.動作デモ
StatefulSetオーケストレーションファイル
まず、ここではAlibaba Cloudのクラスターに接続されています。クラスターには3つのノードがあります。
次に、StatefulSetと対応するサービスを作成するには、まず対応するレイアウトファイルを確認します。
上の図の例に示すように、Serviceに対応するnginxはポート80を外部に公開します。StatefulSet構成のメタデータは名前をnginx-webとして定義し、テンプレートのコンテナーはイメージ情報を定義し、最後にvolumeClaimTemplatesをPVCテンプレートとして定義します。
作成を開始
上記のコマンドを実行すると、ServiceおよびStatefulSetが正常に作成されました。get podを通じて、最初に作成されたポッドのシリアル番号が0であることがわかります; get pvcを通じて、シリアル番号0のPVCがPVにバインドされていることがわかります。
シーケンス番号0のポッドはすでに作成されており、ステータスはContainerCreatingです。
シリアル番号0のポッドが作成されると、シリアル番号1のポッドが作成され始め、新しいPVCも正常に作成され、続いてシリアル番号2のポッドが作成されていることを確認します。
各ポッドが作成される前に、PVCが作成されていることがわかります。PVCが作成された後、ポッドはPending状態からPVにバインドし、ContainerCreatingになり、最終的にRunningに到達します。
ステータスを表示
次に、kubectl get sts nginx-web -o yamlを使用してStatefulSetの状態を確認します。
上の図に示すように、予想されるレプリカの数は3で、現在使用可能な数は3であり、最新バージョンに達しています。
次に、サービスとエンドポイントを見ると、サービスのポートが80であり、エンドポイントに3つの対応するIPアドレスがあることがわかります。
再びポッドを取得すると、3つのポッドが上記のエンドポイントのIPアドレスに対応していることがわかります。
上記の操作の結果は次のとおりです。3つのPVCと3つのポッドが目的の状態に達し、StatefulSetによって報告されるステータスには、3つのレプリカとcurrentReplicasがあります。
アップグレード操作
ここでも、kubectl set imageはイメージを宣言するための固定された表現です; StatefulSetは任意のタイプを示します; nginx-webはリソース名です; nginx = nginx:mainline、等号の前のnginxはテンプレートで定義したコンテナー名であり、後者nginx:mainlineは、更新するイメージのバージョンです。
上記のコマンドにより、StatefulSet内のイメージが新しいバージョンに正常に更新されました。
get podでステータスを確認すると、nginx-web-1とnginx-web-2が実行状態になっています。対応するコントローラーリビジョンハッシュは既に新しいバージョンです。次に、nginx-web-0のポッド、古いポッドが削除され、新しいポッドはまだ作成中の状態です。
ステータスを再度確認します。すべてのポッドはすでに実行中ステータスになっています。
StatefulSet情報を見ると、StatefulSetのステータスで定義されているcurrentRevisionが新しいバージョンに更新されており、StatefulSetが取得した3つのポッドが新しいバージョンに入ったことを示しています。
これら3つのポッドが以前のネットワークロゴとストレージディスクをまだ再利用しているかどうかを確認するにはどうすればよいですか?
実際、ヘッドレスサービスによって構成されたホスト名はポッド名にのみリンクされているため、アップグレードされたポッド名が古いポッド名と同じである限り、以前のポッドで使用されていたネットワークIDを使用できます。
ストレージディスクについては、上の画像からPVCのステータスを確認できます。PVCの作成時刻は変更されていません。これは、ポッドが最初に作成された時刻であるため、アップグレードされたポッドは古いポッドで使用されていたPVCを使用します。
たとえば、ポッドの1つを表示できます。このポッドにも宣言されたボリュームがあります。persistentVolumeClaimの名前www-storage-nginx-web-0は、PVCリストにあるシリアル番号0のPVCに対応しています。古いポッドで使用されます。アップグレードプロセス中に、コントローラは古いポッドを削除し、同じ名前で新しいポッドを作成しますが、新しいポッドは古いポッドが使用していたPVCを再利用します。
このようにして、ネットワークストレージの目的をアップグレードの前後に再利用できます。
4、建築設計
管理モード
StatefulSetは3つのタイプのリソースを作成できます。
- 最初のリソース:ControllerRevision
このリソースを通じて、StatefulSetは異なるバージョンのテンプレートテンプレートを簡単に管理できます。
例:上記のnginxの場合、作成開始時の最初のテンプレートバージョンは、対応するControllerRevisionを作成します。イメージバージョンが変更されると、StatefulSetコントローラーによって新しいControllerRevisionが作成されます。各ControllerRevisionは、テンプレートの各バージョンに対応し、ControllerRevisionハッシュの各バージョンにも対応していることがわかります。実際、ポッドラベルで定義されたControllerRevisionハッシュは、ControllerRevisionの名前です。このリソースStatefulSet Controllerを通じて、さまざまなバージョンのテンプレートリソースを管理します。
- 2番目のリソース:PVC
volumeClaimTemplatesがStatefulSetで定義されている場合、StatefulSetはポッドを作成する前にこのテンプレートに基づいてPVCを作成し、そのPVCをポッドボリュームに追加します。
ユーザーが仕様のpvcテンプレートでvolumeClaimTemplatesを定義すると、StatefulSetはポッドを作成する前にテンプレートに従ってPVCを作成し、それをポッドに対応するボリュームに追加します。もちろん、仕様でpvcテンプレートを定義することはできません。その場合、作成されたポッドは単一のpvをマウントしません。
- 3番目のリソース:ポッド
StatefulSetはポッドを順番に作成、削除、更新し、各ポッドには一意のシリアル番号があります。
上の図に示すように、StatefulSetコントローラーは3つのリソース(ControllerRevision、Pod、PVC)を所有しています。
ここでの違いは、StatefulSetの現在のバージョンはControllerRevisionとPodにOwnerReferenceを追加するだけで、PVCにOwnerReferenceを追加しないことです。前のシリーズの記事で述べたように、OwnerReferenceを持つリソースは、管理対象のリソースが削除されると、デフォルトで従属リソースをカスケードして削除します。したがって、StatefulSetがデフォルトで削除された後、StatefulSetによって作成されたControllerRevisionおよびPodは削除されますが、OwnerReferenceがPVCに書き込まれないため、PVCはカスケードによって削除されません。
StatefulSetコントローラー
上の図は、StatefulSetコントローラーのワークフローを示しています。ワークフロー全体を簡単に紹介しましょう。
最初に、Informerのイベントハンドラーを登録して、StatefulSetおよびPodの変更を処理します。コントローラのロジックでは、StatefulSetまたはPodが変更されるたびに、対応するStatefulSetを見つけてキューに入れます。処理のためにキューから取り出された直後の最初の操作は、リビジョンの更新です。つまり、最初に現在のStatefulSetのテンプレートをチェックし、対応するControllerRevisionがあるかどうかを確認します。そうでない場合、それはテンプレートが更新されたことを意味し、コントローラーはリビジョンの新しいバージョンを作成し、新しいControllerRevisionハッシュバージョン番号が存在します。
次に、コントローラはすべてのバージョン番号を取り出し、シリアル番号に従ってソートします。この並べ替え処理中に、ポッドが欠落している場合は、シリアル番号に従って作成されます。余分なポッドがあることが判明した場合は、シリアル番号に従って削除されます。ポッドの数とポッドシリアル番号がレプリカの数と一致することが保証されている場合、コントローラーはポッドを更新する必要があるかどうかを確認します。つまり、これら2つのステップの違いは、すべてのポッドがシリアル番号を満たしているかどうかを確認するためにMangerポッドがあり、ポッドの目的のバージョンが要件を満たしているかどうかを確認するために後者のアップデートがあり、シリアル番号で更新することです。
更新の順序更新プロセスは上の図に示されていますが、実際にはこのプロセスは比較的簡単で、ポッドを削除します。ポッドを削除した後、それは実際には次のトリガーイベントです。コントローラーがこの成功を得ると、ポッドが欠落していることがわかり、前のステップのマネージャーポッドから新しいポッドを順番に作成します。この後、コントローラーは更新ステータスを実行します。これは、以前にコマンドラインで表示されたステータス情報です。
このプロセス全体を通じて、StatefulSetはステートフルアプリケーションを管理する機能を実現します。
容量拡張シミュレーション
StatefulSetレプリカの初期構成が1であるとすると、Pod0があります。次に、レプリカを1から3に変更した後、実際に最初にPod1を作成します。デフォルトでは、Pod1のステータスがREADYになるのを待ってから、Pod2を作成します。
上の図からわかるように、各StatefulSetの下のポッドはシーケンス番号0から作成されます。したがって、レプリカがNのStatefulSetは、ポッドシーケンス番号[0、N)で作成され、0は開曲線、Nは閉曲線です。つまり、N> 0の場合、シーケンス番号は0〜N-1です。
拡張管理戦略
一部の生徒は質問をする可能性があります。シリアル番号に従って作成および削除したくない場合、StatefulSetは他の作成および削除ロジックもサポートしているため、コミュニティの一部の人々はStatefulSetを通じてステートレスアプリケーションも管理しています。その利点は、独自のネットワークIDとネットワークストレージを使用できることと、同時に拡張および縮小できることです。
StatefulSet.specにはpodMangementPolicyフィールドと呼ばれるフィールドがあり、このフィールドのオプションの戦略はOrderedReadyとParallelであり、デフォルトでは前者です。
先ほど作成した例のように、podMangementPolicyは仕様で定義されていません。次に、コントローラはデフォルトでOrderedReadyを戦略として使用し、OrderedReadyの場合、拡張と縮小は厳密にOrderの順序で実行されます。次のポッドを拡張する前に、前のポッドの状態がReadyになるのを待つ必要があります。縮小する場合は、逆の順序で削除し、シーケンス番号を大きいものから小さいものへと削除します。
たとえば、上の図の右側でPod0からPod0、Pod1、およびPod2に拡張する場合、最初にPod1を作成し、Pod1 ReadyがPod2を作成するのを待つ必要があります。実際、可能性があります。たとえば、Pod1を作成すると、何らかの理由でPod0がNotReady状態になり、ホストマシンまたはアプリケーション自体の原因である可能性があります。この時点では、コントローラーはPod2を作成しないため、以前に作成したポッドを準備するだけでなく、以前のすべてのポッドを準備してから、次のポッドを作成する必要があります。上記の例で、Pod2を作成する場合、Pod0とPod1が準備されている必要があります。
別の戦略はParallelと呼ばれます。名前が示すように、並行して拡張と縮小を行います。前のポッドが準備完了になるのを待つ必要はなく、次のポッドを処理する前に削除する必要もありません。
シミュレーション後
ここでStatefulSetテンプレート1が論理Revision1に対応すると想定すると、StatefulSetの下の3つのポッドはRevision1バージョンに属します。画像などのテンプレートを変更した後、コントローラーはポッドを1つずつ逆の順序でアップグレードしました。上の図では、Controllerが最初にRevision2を作成したことがわかります。これは、ControllerRevision2などのリソースの作成に対応し、Resource ControllerRevision2の名前を新しいRevisionハッシュとして作成しています。Pod2を新しいバージョンにアップグレードした後、Pod0とPod1を1つずつ削除してから、Pod0とPod1を作成します。
そのロジックは実際には非常に単純です。コントローラーは、アップグレードプロセス中に、シリアル番号が最も大きいポッドを削除して条件を満たします。次に、削除後、コントローラーが調整を実行しているときに、このシリアル番号のないポッドを見つけて、新しいバージョンを追跡します。ポッドを作成します。
スペックフィールド分析
まず、仕様の最初のいくつかのフィールドを見てください。レプリカとセレクターは、私たちがよく知っているフィールドです。
- レプリカは主に予想数量です。
- セレクターはイベントセレクターであり、spec.template.metadata.labelsで定義された条件に一致する必要があります。
- テンプレート:作成するポッドの基本情報テンプレートを定義するポッドテンプレート。
- VolumeClaimTemplates:PVCテンプレートのリストこれが仕様で定義されている場合、PVCはポッドテンプレートの前に作成されます。PVCが作成された後、作成されたPVC名は、テンプレートに従ってボリュームとして作成されたポッドに挿入されます。
- ServiceName:ヘッドレスサービスに対応する名前。もちろん、誰かがこの関数を必要としない場合、Serviceには存在しない値が割り当てられ、コントローラーは検証を行わないため、偽のServiceNameを書き込むことができます。ただし、StatefulSetの下のポッドにネットワークIDが必要かどうかに関係なく、各サービスにヘッドレスサービスを構成することをお勧めします。
- PodMangementPolicy:ポッド管理戦略。前述したように、このフィールドのオプションの戦略はOrderedReadyとParallelです。これはデフォルトで前者です。
- UpdataStrategy:ポッドのアップグレード戦略。これは、以下で詳細に説明する構造です。
- RevisionHistoryLimit:履歴を保持するためにControllerRevisionsの数を制限します(デフォルトは10)。ここで明確なバージョンであることに注意してください。これらのバージョンに対応する関連するポッドがあってはなりません。このバージョンにまだポッドがある場合、このControllerRevisionは削除できません。
アップグレード戦略フィールド分析
上の画像の右側に、StatefulSetUpdateStrategyにtypeフィールドがあり、2つのタイプを定義していることがわかります。1つはRollingUpdate、もう1つはOnDeleteです。
- RollingUpdateは実際にはDeploymentのアップグレードと少し似ています。つまり、ローリングアップグレード方式に従ってアップグレードします。
- OnDeleteは削除時にアップグレードされます。アクティブアップグレードを禁止するために呼び出されます。コントローラーは、残存するポッドをアクティブにアップグレードせず、OnDeleteを介してアップグレードします。たとえば、現在3つの古いポッドがありますが、アップグレード戦略はOnDeleteであるため、スペックのミラーを更新するときに、コントローラーは3つのポッドを1つずつ新しいバージョンにアップグレードしませんが、レプリカを縮小すると、コントローラーが最初にポッドを削除します。次回キャパシティーを拡張すると、コントローラーは新しいバージョンのポッドを拡張します。
RollingUpdateStatefulSetSetStrategyでは、Partitionというフィールドがあることがわかります。このパーティションは、ローリングアップグレード中に古いバージョンのポッドの数が保持されることを意味します。StatefulSetを終了したばかりの多くの学生は、これがグレースケールの新しいバージョンの数だと思うかもしれませんが、これは誤りです。
例:現在、レプリカが10のStatefulSetがあるとします。バージョンを更新するときにパーティションが8の場合、8つのポッドを新しいバージョンに更新する必要があるわけではありませんが、8つのポッドを古いバージョンとして保持する必要があります。 、グレースケールとして2つの新しいバージョンのみを更新します。レプリカが10の場合、次のポッドシリアル番号は[0,9)なので、パーティションを8に構成すると、実際には[0,7)を保持します。これらの8つのポッドは古いバージョンであり、[8,9)のみです。新しいバージョンを入力します。
要約すると、レプリカ= N、パーティション= M(M
V.このセクションの要約
これで、この記事のメインコンテンツの終わりです。ここに、全員の簡単な要約を示します。
- StatefulSetはKubernetesの一般的なワークロードです。その最初の目標はステートフルアプリケーションのデプロイですが、ステートレスアプリケーションのデプロイもサポートしています。
- デプロイとは異なり、StatefulSetはポッドを直接操作して拡張/縮小/公開し、ReplicaSetなどの他のワークロードによって制御されません。
- StatefulSetの特徴は次のとおりです。各ポッド専用PVCのサポート、一意のネットワークIDがあり、アップグレードリリース後にPVCとネットワークIDを再利用できます。