OpenKruise (https://openkruise.io) は、デプロイメント、リリース、運用と保守、可用性の保護など、クラウドネイティブ アプリケーションの自動化に重点を置いた Kubernetes ベースの拡張スイートです。 OpenKruise が提供する機能のほとんどは、CRD 拡張に基づいて定義されています。外部依存関係はなく、純粋な Kubernetes クラスターで実行できます。 Kubernetes 自体が提供するアプリケーションの展開および管理機能の中には、大規模なアプリケーションやクラスターのシナリオには到底不十分なものもあります。 OpenKruise は、アプリケーションの展開、アップグレード、保護、運用、保守などにおける Kubernetes の欠点を補います。 OpenKruise は次のコア機能を提供します。 - 拡張ワークロード: OpenKruise には、CloneSet、Advanced StatefulSet、Advanced DaemonSet、BroadcastJob などの一連の拡張ワークロードが含まれています。Kubernetes ネイティブ ワークロードと同様の基本機能をサポートするだけでなく、インプレース アップグレード、構成可能なスケーリング/リリース戦略、同時操作なども提供します。その中でも、インプレース アップグレードは、アプリケーション コンテナ イメージや環境変数までアップグレードする新しい方法です。新しいイメージを使用して Pod 内の特定のコンテナのみが再構築され、Pod 全体やその中の他のコンテナは影響を受けません。したがって、リリース速度が速くなり、スケジューラ、CNI、CSI などの他のコンポーネントへの悪影響が回避されます。
- アプリケーション バイパス管理: OpenKruise は、バイパスを通じてアプリケーション サイドカー コンテナーとマルチリージョン デプロイメントを管理する複数の方法を提供します。バイパスとは、アプリケーションのワークロードを変更せずに実装できることを意味します。たとえば、SidecarSet を使用すると、一致するすべての Pod が作成されるときに、特定のサイドカー コンテナーをそれらの Pod に挿入できます。ポッド内の他のコンテナに影響を与えることなく、挿入されたサイドカー コンテナ イメージをその場でアップグレードすることもできます。 WorkloadSpread は、ステートレス ワークロードによって拡張された Pod の地域分布を制限できるため、単一のワークロードを複数の地域に柔軟にデプロイできるようになります。
- 高可用性保護: OpenKruise は、CRD、名前空間、およびほぼすべてのワークロード タイプのリソースを含む Kubernetes リソースがカスケード削除メカニズムによって干渉されるのを防ぎます。 Pod Eviction に対する保護のみを提供するネイティブ Kubernetes PDB と比較して、PodUnavailableBudget は、Pod の削除、Eviction、更新など、多くの自発的な中断シナリオから保護できます。
- 高度なアプリケーション運用および保守機能: OpenKruise は、アプリケーションの管理を向上させるための高度な運用および保守機能も多数提供します。たとえば、ImagePullJob を使用して、任意の範囲のノード上の特定のイメージを事前にプルしたり、Pod 内の 1 つ以上のコンテナーをその場で再起動するように指定したりできます。
建築次の図は、OpenKruise の全体的なアーキテクチャを示しています。 建築 OpenKruise のすべての機能は Kubernetes CRD を通じて提供されます。 Kruise-manager は、コントローラーと Webhook を実行する中心的なコンポーネントです。これは、Deployment を通じて kruise-system 名前空間にデプロイされます。論理的には、cloneset-controller や sidecarset-controller などのコントローラーは独立して実行されます。ただし、複雑さを軽減するために、これらは別のバイナリ ファイルにパッケージ化され、kruise-controller-manager-xxx Pod で実行されます。コントローラーに加えて、kruise-controller-manager-xxx には、Kruise CRD および Pod リソースのアドミッション Webhook も含まれています。 Kruise-manager は、感知して処理する必要があるリソースを構成するためのいくつかの webhook 構成を作成し、kube-apiserver が呼び出すサービスを提供します。 バージョン v0.8.0 以降では、新しい Kruise-daemon コンポーネントが提供されます。 DaemonSet を通じて各ノードにデプロイされ、イメージのプリヒートやコンテナの再起動などの機能を提供します。 インストールここでもインストールには Helm を使用します。注意: v1.0.0 以降では、OpenKruise は Kubernetes >= 1.16 以上のクラスターにインストールして使用する必要があります。 まずチャートのリポジトリを追加します。 ➜ helmリポジトリにopenkruiseを追加しますhttps://openkruise.github.io/charts/ ➜ helmリポジトリの更新 次に、次のコマンドを実行して、アプリケーションの最新バージョンをインストールします。 ➜ Helmアップグレード-- kruiseをインストールopenkruise / kruise --バージョン1.3 .0 チャートはテンプレート内でデフォルトで名前空間 kruise-system を定義するため、インストール時に指定する必要はありません。ご使用の環境で DockerHub 公式イメージへのアクセスが遅い場合は、次のコマンドを使用してイメージを Alibaba Cloud イメージに置き換えることができます。 ➜ Helm upgrade --install kruise openkruise/kruise --set manager.image.repository=openkruise-registry.cn-shanghai.cr.aliyuncs.com/openkruise/kruise-manager --version 1.3.0 アプリケーションがデプロイされると、2 つの kruise-manager Pod が kruise-system 名前空間で実行されます。また、マスターを選出するためにリーダー選挙も使用します。高可用性を実現するために、一度に 1 つだけがサービスを提供します。さらに、kruise-daemon コンポーネントは DaemonSet として起動されます。 ➜ kubectl getポッド- n kruise -システム 名前準備完了ステータス再起動年齢 kruise -コントローラー-マネージャー- 7 d78fc5c97 - d6mbb 1 / 1実行中0 52秒 kruise -コントローラー-マネージャー- 7 d78fc5c97 - wccbn 1 / 1実行中0 52秒 クルーズ-デーモン- 9f 94 k 1 / 1ランニング0 52 s kruise - daemon - bqj69 1 / 1実行中0 52秒 kruise - daemon - h95pf 1 / 1実行中0 52秒 インストールにデフォルトのパラメータを使用しない場合は、構成をカスタマイズすることもできます。設定可能な値は、チャートのドキュメント https://github.com/openkruise/charts を参照してカスタマイズできます。 クローンセットCloneSet コントローラーは、OpenKruise が提供するネイティブ デプロイメント用の拡張コントローラーです。使い方はデプロイメントとほぼ同じです。以下は、宣言した CloneSet リソース オブジェクトです。 #クローンセット- demo.yaml apiバージョン:アプリ。クルーズ。 io / v1alpha1 種類: CloneSet メタデータ: 名前: cs -デモ 仕様: レプリカ: 3 セレクター: マッチラベル: アプリ: cs テンプレート: メタデータ: ラベル: アプリ: cs 仕様: コンテナ: -名前: nginx 画像: nginx :アルパイン imagePullPolicy : IfNotPresent ポート: -コンテナポート: 80 上記の CloneSet オブジェクトを直接作成します。 ➜ kubectl apply -fクローンセット-デモ.yaml ➜ kubectl get cloneset cs -デモ 名前希望更新済みUPDATED_READY READY合計年齢 cs -デモ3 3 0 0 3 8秒 ➜ kubectlクローンセットcsの説明-デモ 名前: cs - demo 名前空間:デフォルト ラベル: <なし> 注釈: <なし> APIバージョン: apps 。クルーズ。 io / v1alpha1 種類: CloneSet # ...... イベント: タイプ理由年齢送信元 メッセージ ---- ------ ---- ---- ------- 正常成功21秒クローンセットの作成-コントローラーはポッドの作成に成功しましたcs -デモ- jfx5s 正常成功21 sクローンセットの作成-コントローラーはポッドcs -デモ- kg9p2の作成に成功しました 正常成功21 sクローンセットの作成-コントローラーはポッドcs -デモ- n72frの作成に成功しました オブジェクトが作成された後、kubectl describe コマンドを使用して対応するイベント情報を表示できます。 cloneset-controller が Pod を直接作成していることがわかります。これはネイティブのデプロイメントとは多少異なります。デプロイメントは ReplicaSet を通じて Pod を作成するため、ここでは CloneSet が Pod を直接管理していることがわかります。この時点で、ポッドの 3 つのレプリカも正常に作成されます。 ➜ kubectlポッドを取得- l app = cs 名前準備完了ステータス再起動年齢 cs -デモ- jfx5s 1 / 1実行中0 58秒 cs -デモ- kg9p2 1 / 1実行中0 58秒 cs -デモ- n72fr 1 / 1実行中0 58秒 CloneSet は使用方法が Deployment に似ていますが、Deployment よりも多くの高度な機能を備えています。詳しく紹介していきましょう。 スケーリングストリーミングの拡張CloneSet が拡張されている場合、ScaleStrategy.MaxUnavailable を使用して拡張ステップのサイズを制限し、サービス アプリケーションへの影響を最小限に抑えることができます。絶対値またはパーセンテージを設定できます。この値を設定しない場合は、制限がないことを意味します。 たとえば、上記のリソース リストに次のデータを追加します。 apiバージョン:アプリ。クルーズ。 io / v1alpha1 種類: CloneSet メタデータ: 名前: cs -デモ 仕様: 最小準備秒数: 60 スケール戦略: 最大利用不可: 1 レプリカ: 5 ...... 上記では、scaleStrategy.maxUnavailable を 1 に設定しています。minReadySeconds パラメータと組み合わせると、スケールアップ時に、CloneSet は、前のスケールアウトされた Pod が 1 分以上 Ready 状態だった場合にのみ、次の Pod を作成することになります。たとえば、ここではレプリカを 5 つまでスケールアップします。上記のオブジェクトを更新した後、CloneSet イベントを表示します。 ➜ kubectlクローンセットcsの説明-デモ ...... イベント: タイプ理由年齢送信元 メッセージ ---- ------ ---- ---- ------- 正常に作成されました4 つのm25sクローン セット-コントローラーがポッドcs -デモ- jfx5sの作成に成功しました 正常に完了しました4 つのm25sクローン セットを作成-コントローラーがポッドcsの作成に成功-デモ- kg9p2 正常に完了しました4 つのm25sクローン セットの作成-コントローラーがポッドcsの作成に成功しました-デモ- n72fr 警告ScaleUpLimited 66秒cloneset -コントローラーのscaleUp は、 scaleStrategyにより制限されています。最大利用不可、制限: 1 正常な成功作成66秒クローンセット-コントローラーはポッドcs -デモ- x8ndfの作成に成功しました 警告ScaleUpLimited 64秒( 66秒を超えるとx6 ) cloneset - controller scaleUp はscaleStrategyにより制限されます。最大利用不可、制限: 0 正常成功作成5秒クローンセット-コントローラーがポッドcs -デモ- 2 sfzzの作成に成功 Pod がすぐに拡張されることがわかります。 minReadySeconds: 60 を設定したので、新しく拡張された Pod が正常に作成されてから 1 分後に別の Pod が拡張されます。これは上記のイベント情報でも確認できます。 Pod の AGE を見ると、拡張された 2 つの Pod の間に約 1 分のギャップがあることもわかります。 ➜ kubectlポッドを取得- l app = cs 名前準備完了ステータス再起動年齢 cs -デモ- 2 sfzz 1 / 1実行中0 22秒 cs -デモ- jfx5s 1 / 1実行中0 4分42秒 cs -デモ- kg9p2 1 / 1実行中0 4分42秒 cs -デモ- n72fr 1 / 1実行中0 4 m42s cs -デモ- x8ndf 1 / 1実行中0 83秒 CloneSet がスケールダウンされる場合、削除する Pod を指定することもできますが、これは StatefulSet または Deployment では不可能です。 StatefulSet はシーケンス番号に基づいて Pod を削除しますが、Deployment/ReplicaSet はコントローラーで定義された順序に基づいてのみ削除できます。 CloneSet を使用すると、次に示すように、レプリカの数を減らしながら削除する Pod の名前を指定できます。 apiバージョン:アプリ。クルーズ。 io / v1alpha1 種類: CloneSet メタデータ: 名前: cs -デモ 仕様: 最小準備秒数: 60 スケール戦略: 最大利用不可: 1 削除するポッド: - cs -デモ- n72fr レプリカ: 4 ...... 上記のリソース オブジェクトを更新すると、アプリケーションは 4 つのポッドにスケールダウンされます。 podsToDelete リストに Pod 名が指定されている場合、コントローラーはまずこれらの Pod を削除します。削除された Pod については、コントローラーによって podsToDelete リストから自動的にクリアされます。たとえば、上記のリソース オブジェクトを更新すると、 cs-demo-n72fr Pod は削除され、残りは保持されます。 ➜ kubectlポッドを取得- l app = cs 名前準備完了ステータス再起動年齢 cs -デモ- 2 sfzz 1 / 1実行中0 61秒 cs -デモ- jfx5s 1 / 1実行中0 5分21秒 cs -デモ- kg9p2 1 / 1実行中0 5分21秒 cs -デモ- x8ndf 1 / 1実行中0 2 m2s podsToDelete に Pod 名のみを追加し、レプリカの数を変更しない場合、コントローラーは指定された Pod を最初に削除し、新しい Pod を拡張します。 Pod を直接削除する別の方法は、削除する Pod に apps.kruise.io/specified-delete: true ラベルを追加することです。 手動で Pod を削除する場合と比較して、podsToDelete または apps.kruise.io/specified-delete: true を使用すると、CloneSet の maxUnavailable/maxSurge によって削除が保護され、PreparingDelete ライフサイクル フックがトリガーされます。 PVCテンプレートかなりユニークな機能として、CloneSet では、ユーザーが PVC テンプレート volumeClaimTemplates を構成して、各 Pod に固有の PVC を生成できることが挙げられます。ステートフル アプリケーションでは通常、個別の PVC 設定が必要になるため、これはデプロイメントではサポートされていません。 CloneSet の PVC テンプレートを使用する場合は、次の点に注意する必要があります。 - 自動的に作成された各 PVC には CloneSet を指す ownerReference があるため、CloneSet が削除されると、作成されたすべての Pod と PVC が削除されます。
- CloneSet によって作成された各 Pod と PVC には、apps.kruise.io/cloneset-instance-id: xxx というラベルが付けられます。関連付けられている Pod と PVC は同じインスタンス ID を持ち、その名前にはこのインスタンス ID が接尾辞として付加されます。
- ポッドがスケールダウンされたときに CloneSet コントローラーによって削除されると、そのポッドに関連付けられているすべての PVC も削除されます。
- 外部からの直接呼び出しによってポッドが削除または排除された場合でも、そのポッドに関連付けられている PVC は引き続き存在します。 CloneSet コントローラーが数が不十分であると判断して容量を再拡張すると、新しく拡張された Pod は元の Pod のインスタンス ID を再利用し、元の PVC に関連付けます。
- Pod が再構築およびアップグレードされると、関連付けられている PVC が削除され、Pod とともに新しく作成されます。
- Pod がインプレースでアップグレードされると、関連付けられている PVC は引き続き使用されます。
PVC テンプレートの例を次に示します。 #クローンセット- pvc.yaml apiバージョン:アプリ。クルーズ。 io / v1alpha1 種類: CloneSet メタデータ: ラベル: アプリ:サンプル 名前:サンプル-データ 仕様: レプリカ: 3 セレクター: マッチラベル: アプリ:サンプル テンプレート: メタデータ: ラベル: アプリ:サンプル 仕様: コンテナ: -名前: nginx 画像: nginx :アルパイン ボリュームマウント: -名前:データ-ボリューム マウントパス: / usr / share / nginx / html ボリュームクレームテンプレート: -メタデータ: 名前:データ- vol 仕様: アクセスモード: [ "ReadWriteOnce" ] リソース: リクエスト: ストレージ: 20 Gi たとえば、上記のリソース オブジェクトを適用すると、3 つの Pod と 3 つの PVC が自動的に作成され、各 Pod が PVC をマウントします。 ➜ kubectl get pods - l app =サンプル 名前準備完了ステータス再起動年齢 サンプル-データ- t4vq6 0 / 1保留中0 2分13秒 サンプル-データ- vcjnl 0 / 1保留中0 2分13秒 サンプル-データ- znwjd 0 / 1保留中0 2分13秒 ➜ kubectl get pvc - l app =サンプル 名前ステータスボリューム容量アクセスモードストレージクラス 年齢 データ-ボリューム-サンプル-データ- t4vq6保留中2分 46 秒 データ- vol -サンプル-データ- vcjnl保留中2分 46 秒 データ-ボリューム-サンプル-データ- znwjd保留中2分 46 秒 アップグレードCloneSet には 3 つのアップグレード方法があります。 - 再作成: 古い Pod とその PVC を削除し、新しいバージョンで再作成します。これがデフォルトの方法です。
- InPlaceIfPossible: 最初に Pod がインプレースでアップグレードされ、それが失敗した場合は再構築されてアップグレードされます。
- InPlaceOnly: インプレース アップグレードのみが許可されます。したがって、ユーザーは前の項目の制限されたフィールドのみを変更できます。他のフィールドを変更しようとすると拒否されます。
ここで重要な概念は、インプレース アップグレードです。これは、OpenKruise が提供するコア機能の 1 つでもあります。 Pod 内のイメージをアップグレードする場合、再構築アップグレードとインプレース アップグレードの違いは次の図に示されています。 インプレースアップグレード 再構築およびアップグレードするときは、古い Pod を削除して新しい Pod を作成する必要があります。 - Pod名とuidは、2つの完全に異なるPodオブジェクト(デプロイメントのアップグレードなど)であるため変更されます。
- Pod名は変更されない可能性がありますが、UIDは変更される可能性があります。これは、同じ名前を再利用する異なるPodオブジェクトであるためです(StatefulSetのアップグレードなど)。
- 新しいポッドは以前のポッドが配置されていたノードにスケジュールされない可能性が高いため、ポッドが配置されているノードの名前は変更される可能性があります。
- ポッドのIPが変更されました。新しいポッドには以前のIPアドレスが割り当てられない可能性が高いためです。
ただし、インプレース アップグレードの場合は、同じ Pod オブジェクトを再利用し、そのフィールドを変更するだけです。 - スケジュール設定、IP アドレスの割り当て、ボリュームのマウントなどの余分な操作やコストを回避できます。
- 古いイメージのレイヤーのほとんどが再利用され、新しいイメージの変更の一部のレイヤーのみをプルする必要があるため、イメージのプルが高速化されます。
- コンテナがインプレースでアップグレードされると、ポッド内の他のコンテナは影響を受けず、引き続き実行されます。
したがって、インプレース アップグレード方式を使用してワークロードをアップグレードできれば、オンライン アプリケーションへの影響は最小限に抑えられることは明らかです。前述のように、CloneSet アップグレード タイプは InPlaceIfPossible をサポートしており、これは Kruise が Pod 上でインプレース アップグレードを実行しようとすることを意味します。これが不可能な場合は、再構築アップグレードにフォールバックします。インプレース アップグレードを実行するには、次の変更が許可されます。 - ラベルや注釈などのワークロードで spec.template.metadata.* を更新すると、Kruise は既存の Pod のメタデータの変更のみを更新します。
- ワークロード内の spec.template.spec.containers[x].image を更新します。 Kruise は、Pod 全体を再構築せずに、Pod 内のこれらのコンテナのイメージをその場でアップグレードします。
- Kruise v1.0 以降では、spec.template.metadata.labels/annotations を更新し、コンテナー内の変更されたラベル/注釈から env を構成すると、Kruise はこれらのコンテナーをアップグレードして、新しい env 値を有効にします。
それ以外の場合、spec.template.spec.containers[x].env や spec.template.spec.containers[x].resources などの他のフィールドへの変更は、再構築アップグレードに戻されます。 たとえば、上記のアプリケーションのアップグレード方法を InPlaceIfPossible に設定する場合、リソース リストに spec.updateStrategy.type: InPlaceIfPossible を追加するだけで済みます。 apiバージョン:アプリ。クルーズ。 io / v1alpha1 種類: CloneSet メタデータ: 名前: cs -デモ 仕様: 更新戦略: タイプ: InPlaceIfPossible ...... #イメージ: nginx : 1.7.9 アップデート後、Pod のステータスはあまり変化していないことがわかります。名前とIPは同じです。唯一の変更点は画像タグです: ➜ kubectlポッドを取得- l app = cs 名前準備完了ステータス再起動年齢 cs -デモ- 2 sfzz 1 / 1実行中1 ( 18秒前) 36分 cs -デモ- jfx5s 1 / 1実行中0 40 m cs -デモ- kg9p2 1 / 1実行中0 40 m cs -デモ- x8ndf 1 / 1実行中0 37分 ➜ kubectlクローンセットcsの説明-デモ 名前: cs - demo 名前空間:デフォルト ラベル: <なし> 注釈: <なし> APIバージョン: apps 。クルーズ。 io / v1alpha1 種類: CloneSet ...... イベント: タイプ理由年齢送信元 メッセージ ---- ------ ---- ---- ------- # ...... 正常SuccessfulUpdatePodInPlace 6 m58s cloneset - controller がポッドcs - demo - 2 sfzzを正常にインプレース更新しました(リビジョンcs - demo - 7 cb9c88699 ) 正常SuccessfulUpdatePodInPlace 5 m46s cloneset - controller がポッドcs - demo - x8ndfを正常にインプレース更新しました(リビジョンcs - demo - 7 cb9c88699 ) 正常SuccessfulUpdatePodInPlace 4 m43s cloneset - controller がポッドcs - demo - kg9p2を正常にインプレース更新しました(リビジョンcs - demo - 7 cb9c88699 ) 正常SuccessfulUpdatePodInPlace 3 m40s cloneset - controller がポッドcs - demo - jfx5sを正常にインプレース更新しました(リビジョンcs - demo - 7 cb9c88699 ) ➜ kubectl describe pod cs -デモ- 2 sfzz ...... イベント: タイプ理由年齢送信元 メッセージ ---- ------ ---- ---- ------- 通常スケジュール44 m default - scheduler default / cs - demo - 2 sfzzをnode2に正常に割り当てました 通常44 m のkubeletコンテナイメージ「 nginx:alpine」が既にマシン上に存在します 通常、 8 つのm8s kubeletコンテナを強制終了すると、 nginx の定義が変更され、再起動されます。 通常のプル8 m8s kubeletイメージ"nginx:1.7.9"のプル 通常7分 58 秒( 44分でx2 ) kubeletコンテナnginxを作成 正常開始7分 58 秒( x2 44分) kubeletコンテナnginxを開始 通常プル7分 58 秒kubeletイメージ「nginx:1.7.9」を9.720841233秒で正常にプルしました(待機時間を含めると9.720847295秒) これはインプレースアップグレードの効果です。インプレース アップグレードの全体的なワークフローを次の図に示します。 インプレースアップグレードプロセス Kruise をインストールまたはアップグレードするときに PreDownloadImageForInPlaceUpdate 機能ゲートを有効にすると、CloneSet コントローラーは、古いバージョンのポッドが配置されているすべてのノードで、グレースケールでリリースする新しいバージョンのイメージを自動的に事前加熱します。これは、アプリケーションのリリースを高速化するのに非常に役立ちます。 デフォルトでは、CloneSet に事前加熱された各新しいイメージの同時実行性は 1 です。つまり、各ノードはイメージを 1 つずつプルします。調整する必要がある場合は、apps.kruise.io/image-predownload-parallelism アノテーションを使用して CloneSet で同時実行性を設定できます。 さらに、Kruise v1.1.0 以降では、少数の新しいバージョンの Pod が正常にアップグレードされた後に、apps.kruise.io/image-predownload-min-updated-ready-pods を使用してイメージの事前加熱を制御することもできます。その値は絶対数またはパーセンテージにすることができます。 apiバージョン:アプリ。クルーズ。 io / v1alpha1 種類: CloneSet メタデータ: 注釈: アプリ。クルーズ。 io /画像-事前ダウンロード-並列処理: "5" アプリ。クルーズ。 io /イメージ-事前ダウンロード-最小-更新済み-準備完了-ポッド: "2" 不要なイメージのプルを回避するために、自動プレウォーミングは現在、レプリカが 3 を超える CloneSet に対してのみ実行されることに注意してください。
さらに、CloneSet はバッチ グレースケールもサポートします。 updateStrategy プロパティでは、古いバージョンの Pod の数または割合を保持するために使用できるパーティション パラメータを設定できます。デフォルト値は 0 です。 - 数値の場合、コントローラーは(レプリカ - パーティション)数のポッドを最新バージョンに更新します。
- パーセンテージの場合、コントローラーは (レプリカ * (100% - パーティション)) 個のポッドを最新バージョンに更新します。
たとえば、上記の例のイメージを nginx:latest に更新し、partitinotallow=2 を設定します。更新後、アップグレードされたポッドは 2 つだけであることがわかります。 ➜ kubectl get pods -l app = cs -Lコントローラー-リビジョン-ハッシュ 名前準備完了ステータス再起動年齢コントローラ-改訂-ハッシュ cs -デモ- 2 sfzz 1 / 1実行中1 ( 11分前) 47分cs -デモ- 7 cb9c88699 cs -デモ- jfx5s 1 / 1実行中2 ( 99秒前) 52分cs -デモ- 7 c4d79f5bc cs -デモ- kg9p2 1 / 1実行中2 ( 27秒前) 52分cs -デモ- 7 c4d79f5bc cs -デモ- x8ndf 1 / 1実行中1 ( 10分前) 48分cs -デモ- 7 cb9c88699 ➜ kubectl get pods - o custom - columns = 'DATA:metadata.name,CONTAINERS:spec.containers[*].name,IMAGES:spec.containers[*].image' - l app = cs データコンテナ画像 cs -デモ- 2 sfzz nginx nginx : 1.7 .9 cs -デモ- jfx5s nginx nginx :最新 cs -デモ- kg9p2 nginx nginx :最新 cs -デモ- x8ndf nginx nginx : 1.7 .9 さらに、CloneSet は、Pod リリースの優先ルールを制御するための優先ポリシーの定義、Pod のタイプをリリース プロセス全体に分割するためのポリシーの定義、Pod リリースやその他の操作の一時停止など、より高度な使用法もサポートしています。 ライフサイクルフックCloneSet によって管理される各 Pod にはクリアな状態があり、これは Pod ラベルの lifecycle.apps.kruise.io/state にマークされます。 - 正常: 通常の状態。
- PreparingUpdate: インプレース アップグレードの準備をしています。
- 更新中: インプレースアップグレード中。
- 更新: インプレース アップグレードが完了しました。
- PreparingDelete: 削除の準備をしています。
ライフサイクル フックは、上記の状態フローのポイントをブロックすることによって、インプレース アップグレードの前後および削除の前にカスタム操作 (トラフィックの切り替え、アラームなど) を実装します。 CloneSet ライフサイクルは、主に preDelete と inPlaceUpdate の 2 つのプロパティをサポートします。 apiバージョン:アプリ。クルーズ。 io / v1alpha1 種類: CloneSet 仕様:
#ファイナライザを介してフックを定義する ライフサイクル: preDelete : # PreDeleteはPodが削除される前のフックです ファイナライザーハンドラー: -例.io /未準備-ブロッカー inPlaceUpdate : # InPlaceUpdate はPod更新の前後のフックです ファイナライザーハンドラー: -例.io /未準備-ブロッカー
#またはラベルで定義することもできます ライフサイクル: インプレースアップデート: ラベルハンドラ: 例.io / block -未準備: "true" アップグレードまたは削除する前にポッドを NotReady に設定するライフサイクル: 事前削除: markPodNotReady : true ファイナライザーハンドラー: -例.io /未準備-ブロッカー インプレースアップデート: markPodNotReady : true ファイナライザーハンドラー: -例.io /未準備-ブロッカー - preDelete.markPodNotReady=true を設定した場合:
- Pod が PreparingDelete 状態に入ると、Kruise は KruisePodReady Pod Condition を False に設定し、Pod は NotReady になります。
この機能を使用すると、コンテナが実際に停止する前にポッド上のトラフィックを除外して、トラフィックの損失を防ぐことができます。 フロー図 ライフサイクル図 - CloneSet が Pod を削除する場合 (通常のスケールダウン、再構築、アップグレードを含む) :
- ライフサイクル フックが定義されていない場合、または Pod が preDelete 条件を満たしていない場合は、直接削除されます。
- それ以外の場合は、まず Pod のステータスを PreparingDelete に変更します。 Kruise は、ユーザー コントローラーがタスクを完了し、ラベル/ファイナライザーを削除し、Pod が preDelete 条件を満たさない場合にのみ、Pod を削除します。
- PreparingDelete 状態の Pod は削除フェーズにあり、アップグレードされないことに注意してください。
- CloneSet が Pod をインプレースでアップグレードする場合:
アップグレードする前に、ライフサイクルフックが定義されていて、PodがinPlaceUpdate条件を満たしている場合は、PodのステータスをPreparingUpdateに変更します。 ユーザー コントローラーがタスクを完了してラベル/ファイナライザーを削除し、Pod が inPlaceUpdate 条件を満たさない場合、kruise は Pod のステータスを Updating に変更し、アップグレードを開始します。 アップグレードが完了した後、ライフサイクルフックが定義されていて、PodがinPlaceUpdate条件を満たしていない場合は、PodのステータスをUpdatedに変更します。 ユーザー コントローラーがタスクを完了してラベル/ファイナライザーを追加し、Pod が inPlaceUpdate 条件を満たすと、kruise は Pod のステータスを Normal に変更し、アップグレードが成功したと判断します。
PreparingDelete から Normal 状態に戻ることについては、設計上サポートされています (指定された削除を元に戻すことによって) が、通常、この使用方法はお勧めしません。 PreparingDelete 状態の Pod はアップグレードされないため、Normal 状態に戻った後すぐに再びリリース フェーズに入る可能性があり、ユーザーにとってフックの処理が難しい問題となります。 ユーザーコントローラロジックの例上記の例に従って、次のように定義できます。 - example.io/unready-blocker ファイナライザーをフックとして使用します。
- 初期化アノテーションとして example.io/initialing アノテーションを使用します。
CloneSet テンプレートに次のフィールドを追加します。 apiバージョン:アプリ。クルーズ。 io / v1alpha1 種類: CloneSet 仕様: テンプレート: メタデータ: 注釈: 例.io /初期化中: "true" ファイナライザー: -例.io /未準備-ブロッカー # ... ライフサイクル: 事前削除: ファイナライザーハンドラー: -例.io /未準備-ブロッカー インプレースアップデート: ファイナライザーハンドラー: -例.io /未準備-ブロッカー ユーザー コントローラーのロジックは次のようになります。 - Normal 状態の Pod の場合、アノテーションに example.io/initialing: true が含まれており、Pod ステータスの準備完了条件が True の場合、トラフィックが接続され、アノテーションは削除されます。
- PreparingDelete および PreparingUpdate 状態の Pod の場合、トラフィックは切断され、example.io/unready-blocker ファイナライザーは削除されます。
- 更新状態の Pod の場合は、トラフィックを許可し、example.io/unready-blocker ファイナライザーを追加します。
使用シナリオさまざまな歴史的理由や客観的な要因により、一部のユーザーは自社のシステム アーキテクチャ全体を Kubernetes 化できない場合があります。たとえば、一部のユーザーは、Kubernetes 自体が提供するサービス検出メカニズムを一時的に使用できず、代わりに Kubernetes とは独立した別のサービス登録および検出システムを使用します。このアーキテクチャでは、ユーザーがサービスを Kubernetes に変換すると、多くの問題が発生する可能性があります。たとえば、Kubernetes が Pod を正常に作成するたびに、内部および外部にサービスを提供できるように、その Pod をサービス検出センターに登録する必要があります。同様に、Pod をオフラインにする場合は、通常、Pod を正常にオフラインにする前に、まずサービス検出センターから削除する必要があります。そうしないと、トラフィック損失が発生する可能性があります。ただし、ネイティブ Kubernetes システムでは、Pod のライフサイクルはワークロード (デプロイメントなど) によって管理されます。これらのワークロードのレプリカ フィールドが変更されると、対応するコントローラーはすぐにポッドを追加または削除するため、ユーザーがポッドのライフサイクルの管理をカスタマイズすることが難しくなります。 この問題には、一般的に 2 つの解決策があります。1 つは、Kubernetes の弾力性を制限することです。たとえば、ワークロードを特定のリンクでのみスケールアップまたはスケールダウンできるように規定して、Pod が削除される前に Pod IP がサービス レジストリから削除されるようにします。しかし、これにより Kubernetes 自体の弾力性が制約され、リンク管理の難しさやリスクが増大します。 2 つ目は、既存のサービス検出システムを根本的に変革することですが、これは明らかにより時間がかかり、リスクの高い作業です。 CloneSet ライフサイクル変換 では、既存のサービス検出システムの変換を回避しながら Kubernetes の弾力性を最大限に活用し、2 つのシステム間のギャップを迅速に埋める方法はあるのでしょうか? OpenKruise CloneSet は、このようなシナリオに特化して対処するための高度にカスタマイズ可能な拡張機能のセットを提供し、ユーザーが Pod ライフサイクルのより洗練されたカスタマイズされた管理を実行できるようにします。 CloneSet は、Pod ライフサイクルのいくつかの重要な時点でフックを予約し、ユーザーがこれらの時点でカスタマイズされた拡張アクションを挿入できるようにします。たとえば、Pod をアップグレードする前に、サービス検出センターで Pod IP を削除し、アップグレードが完了した後に Pod IP をサービス検出センターに登録するか、特別なスニッフィングおよび監視アクションを実行します。 次のようなシナリオがあると仮定しましょう。 - ユーザーは Kubernetes Service をサービス検出メカニズムとして使用しません。サービス検出システムは Kubernetes から完全に独立しています。
- CloneSet を Kubernetes ワークロードとして使用します。
そして、具体的なニーズについて、次のような合理的な仮定を立てます。 - Kubernetes Pod が作成されると、次のようになります。
- 作成が成功し、ポッドの準備が整うと、ポッド IP がサービス検出センターに登録されます。
- Kubernetes Pod がインプレースでアップグレードされると、次のようになります。
アップグレードする前に、サービス検出センターから Pod IP を削除する (またはアクティブにフェイルオーバーする) 必要があります。 アップグレードが完了し、ポッドの準備ができたら、ポッド IP をサービス検出センターに再度登録します。 Kubernetes Pod が削除されると: 削除する前に、サービス検出センターから Pod IP を削除する必要があります。
上記の前提に基づいて、実際に CloneSet LifeCycle を使用して、ユーザー定義の Pod ライフサイクル管理メカニズムを実装する単純な Operator を作成できます。 先ほど、CloneSet LifeCycle は Pod のライフサイクルを 5 つの状態に定義し、5 つの状態間の遷移ロジックはステート マシンによって制御されることを説明しました。関心のあるノードを 1 つ以上選択し、独立した Operator を記述してこれらの状態の遷移を実装し、Pod のライフサイクルを制御し、関心のあるノードに独自のカスタマイズされたロジックを挿入することができます。 apiバージョン:アプリ。クルーズ。 io / v1alpha1 種類: CloneSet メタデータ: 名前空間:デモ 名前:クローンセット-ライフサイクル-デモ 仕様: レプリカ: 2 # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ##ライフサイクル構成 ライフサイクル: インプレースアップデート: ラベルハンドラ: ##タグを定義する: # # 1.クローンセットコントローラのインプレースPod更新を防止する # # 2.オペレータにinPlace更新フックを実行するように通知する 例.com / unready - blocker - inplace : "true" 事前削除: ラベルハンドラ: ##タグを定義する: # # 1.クローンセットコントローラのポッド削除を防止する # # 2.オペレータにpreDeleteフックを実行するよう通知する 例.com / unready - blocker - delete : "true" # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # セレクター: マッチラベル: アプリ: nginx テンプレート: メタデータ: ラベル: アプリ: nginx # #このラベルは、このポッドが新しく作成されたかどうかを判断するために使用できます 例.com / new - create : "true" # #仕様に対応します。ライフサイクル。 inPlaceUpdate 。ラベル ハンドラ。例。 com /未準備-ブロッカー-インプレース 例.com / unready - blocker - inplace : "true" # #仕様に準拠しています。ライフサイクル。事前削除。ラベル ハンドラ。例。 com /未準備-ブロッカー-インプレース 例.com / unready - blocker - delete : "true" コンテナ: -名前:メイン 画像: nginx :最新 imagePullPolicy :常に 更新戦略: 最大利用不可: 20 % タイプ: InPlaceIfPossible 前の CRD の章では、Operator の開発方法について説明しました。ここでは詳細には触れません。コントローラーのコアコードは次のとおりです。 定数( deleteHookLabel = "example.com/unready-blocker-delete" inPlaceHookLabel = "example.com/unready-blocker-inplace" newCreatElabel = "Example.com/newly-create" )
func ( r * samplereconciner ) reconcile ( reqctrl。request ) ( ctrl。result 、 error ) { ... ...
switchlabel : = func ( pod * v1。pod 、 key 、 value string ) error { ボディ: = fmt 。 sprintf ( ` { " metadata " :{ " labels " :{ "%s " : "%s " }}} ` 、 key 、 value ) err : = r 。 Patch ( Context。Todo ()、 Pod 、 Client。RawPatch ( Types。StrategicMergePatchType 、[ ] byte ( body ) ) ) ;エラー!=ゼロ{ エラーを返す } ゼロを返す }
/* ポッドライフサイクルフックロジック */ スイッチ{ //新しく作成されたポッドを処理します ケースISNewlyCreateHooked ( POD ): //このポッドをサービスディスカバリーセンターに登録します err : = posttregistry ( pod ) ;エラー!=ゼロ{ retuncileを返します。結果{}、 err } err : = switchlabel ( pod 、 newlycreatelabel 、 "false" ) ;エラー!=ゼロ{ retuncileを返します。結果{}、 err }
//インプレースアップグレードの準備ができているポッドを処理する ケースISPREUPDATEHOOKED ( POD ): //サービスディスカバリーセンターにこのポッドを失敗させます err : = postfailover ( pod ) ;エラー!=ゼロ{ retuncileを返します。結果{}、 err } err : = switchlabel ( pod 、 inplacehooklabel 、 "false" ) ;エラー!=ゼロ{ retuncileを返します。結果{}、 err }
//アップデートが完了した後、PODを処理します case isUpdatedhooked ( pod ): //サービスディスカバリーセンターにポッドを再登録させます err : = posttregistry ( pod ) ;エラー!=ゼロ{ retuncileを返します。結果{}、 err } err : = switchlabel ( pod 、 inplacehooklabel 、 "true" ) ;エラー!=ゼロ{ retuncileを返します。結果{}、 err }
//削除するポッドを処理します ケースISPREDELETEHOOKED ( POD ): //サービスディスカバリーセンターのポッドを解除します err : = postunregister ( pod ) ;エラー!=ゼロ{ retuncileを返します。結果{}、 err } err : = switchlabel ( pod 、 deletehooklabel 、 "false" ) ;エラー!=ゼロ{ retuncileを返します。結果{}、 err } }
ctrlを返します。結果{}、 nil }
func isnewlycreatehooked ( pod * v1。pod ) bool { Kruiseappspubを返します。 lifecyclestateType ( pod。labels [ kruiseappspub。lifecyclestatekey ]) == kruiseappspub 。ライフサイクルスタテンモルマル&&ポッド。ラベル[ NewlyCreatelabel ] == "True" && isPodReady ( POD ) }
func ispreupdatehooked ( pod * v1。pod ) bool { Kruiseappspubを返します。 lifecyclestateType ( pod。labels [ kruiseappspub。lifecyclestatekey ]) == kruiseappspub 。 lifecyclestatepreparingupdate && pod 。ラベル[ inplacehooklabel ] == "true" }
func isupdatedhooked ( pod * v1。pod ) bool { Kruiseappspubを返します。 lifecyclestateType ( pod。labels [ kruiseappspub。lifecyclestatekey ]) == kruiseappspub 。 lifecyclestateUpdated && pod 。ラベル[ inplacehooklabel ] == "false" && ispodready ( pod ) }
func ispredeletehooked ( pod * v1。pod ) bool { Kruiseappspubを返します。 lifecyclestateType ( pod。labels [ kruiseappspub。lifecyclestatekey ]) == kruiseappspub 。 lifecyclestatepreparingdelete && pod 。ラベル[ deletehooklabel ] == "true" } 上記のコードでは、4つの分岐は、対応するポッドの4つの重要な宣言サイクルサイクルノード、つまり作成後、アップグレード前、削除前に対応します。実際のニーズに応じて、対応するフックを改善できます。上記のフックの動作は具体的には次のとおりです。 - Postregistry(POD *V1.POD):PODサービスを登録するために、リクエスト通知サービスディスカバリーセンターを送信します。
- PostFailover(POD *V1.POD):リクエスト通知サービスディスカバリーセンターを送信このPODサービスに失敗します。
- Postunregiste(pod *v1.pod):リクエスト通知サービスディスカバリーセンターを送信して、ポッドサービスからログアウトします。
これがクローンセットライフサイクルの力です。ニーズに応じて、カスタマイズされたロジックをPODライフサイクル管理に完全に挿入できます。 |