次の方法で共有


ClusterStagedUpdateRun を使用して、メンバー クラスター間で段階的なロールアウトを調整する

Azure Kubernetes Fleet Manager の段階的な更新実行では、ステージバイステージ プロセスを使用して複数のメンバー クラスターにワークロードをデプロイするための制御されたアプローチが提供されます。 この方法では、ターゲット クラスターに順番にデプロイし、オプションの待機時間とステージ間の承認ゲートを使用して、リスクを最小限に抑えることができます。

この記事では、段階的な更新実行を作成して実行し、ワークロードを段階的にデプロイし、必要に応じて以前のバージョンにロールバックする方法について説明します。

Prerequisites

  • アクティブなサブスクリプションを含む Azure アカウントが必要です。 無料でアカウントを作成できます

  • この記事で使用される概念と用語を理解するには、 段階的なロールアウト戦略の概念の概要を参照してください。

  • この記事の内容を完了するには、Azure CLI バージョン 2.58.0 以降がインストールされている必要があります。 インストールとアップグレードについては、「Azure CLI のインストール」を参照してください。

  • Kubernetes CLI (kubectl) がまだインストールされていない場合は、次のコマンドを使用してインストールしてください。

    az aks install-cli
    
  • Azure CLI 拡張機能の fleet が必要です。 これは、次のコマンドを実行してインストールできます。

    az extension add --name fleet
    

    最新バージョンの拡張機能に更新するには、az extension update コマンドを実行します。

    az extension update --name fleet
    

デモ環境を構成する

このデモは、ハブ クラスターと 3 つのメンバー クラスターを持つ Fleet Manager で実行されます。 お持ちでない場合は、 クイックスタート に従って、ハブ クラスターを使用して Fleet Manager を作成します。 次に、Azure Kubernetes Service (AKS) クラスターをメンバーとして参加させます。

このチュートリアルでは、次のラベルを持つ 3 つのメンバー クラスターを含むデモフリート環境を使用して、段階的な更新実行を示します。

クラスター名 labels
member1 environment=canary, order=2
member2 environment=staging
member3 environment=canary,order=1

これらのラベルを使用すると、環境ごとにクラスターをグループ化し、各ステージ内のデプロイ順序を制御するステージを作成できます。

配置用のワークロードを準備する

次に、ワークロードをメンバー クラスターに配置できるように、ハブ クラスターに発行します。

ハブ クラスターでワークロードの名前空間と構成マップを作成します。

kubectl create ns test-namespace
kubectl create cm test-cm --from-literal=key=value1 -n test-namespace

リソースをデプロイするには、ClusterResourcePlacement を作成します。

Note

spec.strategy.typeExternalに設定され、ClusterStagedUpdateRunでロールアウトがトリガーされます。

apiVersion: placement.kubernetes-fleet.io/v1beta1
kind: ClusterResourcePlacement
metadata:
  name: example-placement
spec:
  resourceSelectors:
    - group: ""
      kind: Namespace
      name: test-namespace
      version: v1
  policy:
    placementType: PickAll
  strategy:
    type: External

PickAll ポリシーを使用するため、3 つのクラスターはすべてスケジュールする必要がありますが、ClusterStagedUpdateRunを作成していないため、まだメンバー クラスターにリソースをデプロイする必要はありません。

配置がスケジュールされていることを確認します。

kubectl get crp example-placement

出力は次の例のようになります。

NAME                GEN   SCHEDULED   SCHEDULED-GEN   AVAILABLE   AVAILABLE-GEN   AGE
example-placement   1     True        1                                           51s

リソース スナップショットの操作

Fleet Manager は、リソースが変更されたときにリソース スナップショットを作成します。 各スナップショットには、リソースの特定のバージョンを参照するために使用できる一意のインデックスがあります。

Tip

リソース スナップショットとそのしくみについて詳しくは、「 リソース スナップショットについて」をご覧ください。

現在のリソース スナップショットを確認する

現在のリソース スナップショットを確認するには:

kubectl get clusterresourcesnapshots --show-labels

出力は次の例のようになります。

NAME                           GEN   AGE   LABELS
example-placement-0-snapshot   1     60s   kubernetes-fleet.io/is-latest-snapshot=true,kubernetes-fleet.io/parent-CRP=example-placement,kubernetes-fleet.io/resource-index=0

スナップショットのバージョンは 1 つだけです。 最新の (kubernetes-fleet.io/is-latest-snapshot=true) であり、リソース インデックス 0 (kubernetes-fleet.io/resource-index=0) を持ちます。

新しいリソース スナップショットを作成する

次に、新しい値で configmap を変更します。

kubectl edit cm test-cm -n test-namespace

値を value1 から value2 に更新します。

kubectl get configmap test-cm -n test-namespace -o yaml

出力は次の例のようになります。

apiVersion: v1
data:
  key: value2 # value updated here, old value: value1
kind: ConfigMap
metadata:
  creationTimestamp: ...
  name: test-cm
  namespace: test-namespace
  resourceVersion: ...
  uid: ...

インデックスが 0 と 1 の 2 つのバージョンのリソース スナップショットが表示されます。

kubectl get clusterresourcesnapshots --show-labels

出力は次の例のようになります。

NAME                           GEN   AGE    LABELS
example-placement-0-snapshot   1     2m6s   kubernetes-fleet.io/is-latest-snapshot=false,kubernetes-fleet.io/parent-CRP=example-placement,kubernetes-fleet.io/resource-index=0
example-placement-1-snapshot   1     10s    kubernetes-fleet.io/is-latest-snapshot=true,kubernetes-fleet.io/parent-CRP=example-placement,kubernetes-fleet.io/resource-index=1

最新のラベルは、最新の configmap データを含む example-placement-1-snapshot に設定されます。

kubectl get clusterresourcesnapshots example-placement-1-snapshot -o yaml

出力は次の例のようになります。

apiVersion: placement.kubernetes-fleet.io/v1
kind: ClusterResourceSnapshot
metadata:
  annotations:
    kubernetes-fleet.io/number-of-enveloped-object: "0"
    kubernetes-fleet.io/number-of-resource-snapshots: "1"
    kubernetes-fleet.io/resource-hash: 10dd7a3d1e5f9849afe956cfbac080a60671ad771e9bda7dd34415f867c75648
  creationTimestamp: "2025-07-22T21:26:54Z"
  generation: 1
  labels:
    kubernetes-fleet.io/is-latest-snapshot: "true"
    kubernetes-fleet.io/parent-CRP: example-placement
    kubernetes-fleet.io/resource-index: "1"
  name: example-placement-1-snapshot
  ownerReferences:
  - apiVersion: placement.kubernetes-fleet.io/v1beta1
    blockOwnerDeletion: true
    controller: true
    kind: ClusterResourcePlacement
    name: example-placement
    uid: e7d59513-b3b6-4904-864a-c70678fd6f65
  resourceVersion: "19994"
  uid: 79ca0bdc-0b0a-4c40-b136-7f701e85cdb6
spec:
  selectedResources:
  - apiVersion: v1
    kind: Namespace
    metadata:
      labels:
        kubernetes.io/metadata.name: test-namespace
      name: test-namespace
    spec:
      finalizers:
      - kubernetes
  - apiVersion: v1
    data:
      key: value2 # latest value: value2, old value: value1
    kind: ConfigMap
    metadata:
      name: test-cm
      namespace: test-namespace

ClusterStagedUpdateStrategy をデプロイする

ClusterStagedUpdateStrategyは、クラスターをステージにグループ化するオーケストレーション パターンを定義し、ロールアウト シーケンスを指定します。 ラベルによってメンバー クラスターが選択されます。 デモでは、ステージングとカナリアの 2 段階 から成るものを作成します:

apiVersion: placement.kubernetes-fleet.io/v1beta1
kind: ClusterStagedUpdateStrategy
metadata:
  name: example-strategy
spec:
  stages:
    - name: staging
      labelSelector:
        matchLabels:
          environment: staging
      afterStageTasks:
        - type: TimedWait
          waitTime: 1m
    - name: canary
      labelSelector:
        matchLabels:
          environment: canary
      sortingLabelKey: order
      afterStageTasks:
        - type: Approval

ClusterStagedUpdateRun をデプロイして最新の変更をロールアウトする

ClusterStagedUpdateRunは、ClusterResourcePlacementに従ってClusterStagedUpdateStrategyのロールアウトを実行します。 ClusterResourcePlacement (CRP) のステージング更新実行をトリガーするには、CRP 名、updateRun 戦略名、および最新のリソース スナップショット インデックス ("1") を指定する ClusterStagedUpdateRun を作成します。

apiVersion: placement.kubernetes-fleet.io/v1beta1
kind: ClusterStagedUpdateRun
metadata:
  name: example-run
spec:
  placementName: example-placement
  resourceSnapshotIndex: "1"
  stagedRolloutStrategyName: example-strategy

ステージングされた更新プログラムの実行が初期化され、実行されます。

kubectl get csur example-run

出力は次の例のようになります。

NAME          PLACEMENT           RESOURCE-SNAPSHOT-INDEX   POLICY-SNAPSHOT-INDEX   INITIALIZED   SUCCEEDED   AGE
example-run   example-placement   1                         0                       True                      7s

1 分間の TimedWait が経過した後の状態の詳細を次に示します。

kubectl get csur example-run -o yaml

出力は次の例のようになります。

apiVersion: placement.kubernetes-fleet.io/v1beta1
kind: ClusterStagedUpdateRun
metadata:
  ...
  name: example-run
  ...
spec:
  placementName: example-placement
  resourceSnapshotIndex: "1"
  stagedRolloutStrategyName: example-strategy
status:
  conditions:
  - lastTransitionTime: "2025-07-22T21:28:08Z"
    message: ClusterStagedUpdateRun initialized successfully
    observedGeneration: 1
    reason: UpdateRunInitializedSuccessfully
    status: "True" # the updateRun is initialized successfully
    type: Initialized
  - lastTransitionTime: "2025-07-22T21:29:53Z"
    message: The updateRun is waiting for after-stage tasks in stage canary to complete
    observedGeneration: 1
    reason: UpdateRunWaiting
    status: "False" # the updateRun is still progressing and waiting for approval
    type: Progressing
  deletionStageStatus:
    clusters: [] # no clusters need to be cleaned up
    stageName: kubernetes-fleet.io/deleteStage
  policyObservedClusterCount: 3 # number of clusters to be updated
  policySnapshotIndexUsed: "0"
  stagedUpdateStrategySnapshot: # snapshot of the strategy used for this update run
    stages:
    - afterStageTasks:
      - type: TimedWait
        waitTime: 1m0s
      labelSelector:
        matchLabels:
          environment: staging
      name: staging
    - afterStageTasks:
      - type: Approval
      labelSelector:
        matchLabels:
          environment: canary
      name: canary
      sortingLabelKey: order
  stagesStatus: # detailed status for each stage
  - afterStageTaskStatus:
    - conditions:
      - lastTransitionTime: "2025-07-22T21:29:23Z"
        message: Wait time elapsed
        observedGeneration: 1
        reason: AfterStageTaskWaitTimeElapsed
        status: "True" # the wait after-stage task has completed
        type: WaitTimeElapsed
      type: TimedWait
    clusters:
    - clusterName: member2 # stage staging contains member2 cluster only
      conditions:
      - lastTransitionTime: "2025-07-22T21:28:08Z"
        message: Cluster update started
        observedGeneration: 1
        reason: ClusterUpdatingStarted
        status: "True"
        type: Started
      - lastTransitionTime: "2025-07-22T21:28:23Z"
        message: Cluster update completed successfully
        observedGeneration: 1
        reason: ClusterUpdatingSucceeded
        status: "True" # member2 is updated successfully
        type: Succeeded
    conditions:
    - lastTransitionTime: "2025-07-22T21:28:23Z"
      message: All clusters in the stage are updated and after-stage tasks are completed
      observedGeneration: 1
      reason: StageUpdatingSucceeded
      status: "False"
      type: Progressing
    - lastTransitionTime: "2025-07-22T21:29:23Z"
      message: Stage update completed successfully
      observedGeneration: 1
      reason: StageUpdatingSucceeded
      status: "True" # stage staging has completed successfully
      type: Succeeded
    endTime: "2025-07-22T21:29:23Z"
    stageName: staging
    startTime: "2025-07-22T21:28:08Z"
  - afterStageTaskStatus:
    - approvalRequestName: example-run-canary # ClusterApprovalRequest name for this stage
      conditions:
      - lastTransitionTime: "2025-07-22T21:29:53Z"
        message: ClusterApprovalRequest is created
        observedGeneration: 1
        reason: AfterStageTaskApprovalRequestCreated
        status: "True"
        type: ApprovalRequestCreated
      type: Approval
    clusters:
    - clusterName: member3 # according to the labelSelector and sortingLabelKey, member3 is selected first in this stage
      conditions:
      - lastTransitionTime: "2025-07-22T21:29:23Z"
        message: Cluster update started
        observedGeneration: 1
        reason: ClusterUpdatingStarted
        status: "True"
        type: Started
      - lastTransitionTime: "2025-07-22T21:29:38Z"
        message: Cluster update completed successfully
        observedGeneration: 1
        reason: ClusterUpdatingSucceeded
        status: "True" # member3 update is completed
        type: Succeeded
    - clusterName: member1 # member1 is selected after member3 because of order=2 label
      conditions:
      - lastTransitionTime: "2025-07-22T21:29:38Z"
        message: Cluster update started
        observedGeneration: 1
        reason: ClusterUpdatingStarted
        status: "True"
        type: Started
      - lastTransitionTime: "2025-07-22T21:29:53Z"
        message: Cluster update completed successfully
        observedGeneration: 1
        reason: ClusterUpdatingSucceeded
        status: "True" # member1 update is completed
        type: Succeeded
    conditions:
    - lastTransitionTime: "2025-07-22T21:29:53Z"
      message: All clusters in the stage are updated, waiting for after-stage tasks
        to complete
      observedGeneration: 1
      reason: StageUpdatingWaiting
      status: "False" # stage canary is waiting for approval task completion
      type: Progressing
    stageName: canary
    startTime: "2025-07-22T21:29:23Z"

ステージング ステージの TimedWait 期間が経過していることがわかります。また、カナリア ステージの承認タスクの ClusterApprovalRequest オブジェクトが作成されていることがわかります。 生成された ClusterApprovalRequest を確認し、まだ承認されていないことを確認できます

kubectl get clusterapprovalrequest

出力は次の例のようになります。

NAME                 UPDATE-RUN    STAGE    APPROVED   APPROVALACCEPTED   AGE
example-run-canary   example-run   canary                                 2m39s

json パッチ ファイルを作成して適用することで、 ClusterApprovalRequest を承認できます。

cat << EOF > approval.json
"status": {
    "conditions": [
        {
            "lastTransitionTime": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
            "message": "lgtm",
            "observedGeneration": 1,
            "reason": "testPassed",
            "status": "True",
            "type": "Approved"
        }
    ]
}
EOF

作成された JSON ファイルを使用して、承認するパッチ要求を送信します。

kubectl patch clusterapprovalrequests example-run-canary --type='merge' --subresource=status --patch-file approval.json

次に、それが承認されていることを確認します。

kubectl get clusterapprovalrequest

出力は次の例のようになります。

NAME                 UPDATE-RUN    STAGE    APPROVED   APPROVALACCEPTED   AGE
example-run-canary   example-run   canary   True       True               3m35s

現在、ClusterStagedUpdateRun は処理を進めて完了できます。

kubectl get csur example-run

出力は次の例のようになります。

NAME          PLACEMENT           RESOURCE-SNAPSHOT-INDEX   POLICY-SNAPSHOT-INDEX   INITIALIZED   SUCCEEDED   AGE
example-run   example-placement   1                         0                       True          True        5m28s

ClusterResourcePlacementには、ロールアウトが完了し、リソースがすべてのメンバー クラスターで使用できることも示されています。

kubectl get crp example-placement

出力は次の例のようになります。

NAME                GEN   SCHEDULED   SCHEDULED-GEN   AVAILABLE   AVAILABLE-GEN   AGE
example-placement   1     True        1               True        1               8m55s

configmap test-cm は、最新のデータを使用して、3 つのメンバー クラスターすべてにデプロイする必要があります。

apiVersion: v1
data:
  key: value2
kind: ConfigMap
metadata:
  ...
  name: test-cm
  namespace: test-namespace
  ...

2 つ目の ClusterStagedUpdateRun をデプロイして以前のバージョンにロールバックする

次に、ワークロード管理者が configmap の変更をロールバックし、 value2 値を value1に戻したいとします。 ハブから configmap を手動で更新する代わりに、コンテキスト内で以前のリソース スナップショット インデックス "0" を使用して新しい ClusterStagedUpdateRun を作成し、同じ戦略を再利用できます。

apiVersion: placement.kubernetes-fleet.io/v1beta1
kind: ClusterStagedUpdateRun
metadata:
  name: example-run-2
spec:
  placementName: example-placement
  resourceSnapshotIndex: "0"
  stagedRolloutStrategyName: example-strategy

新しい ClusterStagedUpdateRunを確認してみましょう。

kubectl get csur

出力は次の例のようになります。

NAME            PLACEMENT           RESOURCE-SNAPSHOT-INDEX   POLICY-SNAPSHOT-INDEX   INITIALIZED   SUCCEEDED   AGE
example-run     example-placement   1                         0                       True          True        13m
example-run-2   example-placement   0                         0                       True                      9s

1 分間のTimedWaitが経過すると、新しいClusterApprovalRequest用に作成されたClusterStagedUpdateRun オブジェクトが表示されます。

kubectl get clusterapprovalrequest

出力は次の例のようになります。

NAME                   UPDATE-RUN      STAGE    APPROVED   APPROVALACCEPTED   AGE
example-run-2-canary   example-run-2   canary                                 75s
example-run-canary     example-run     canary   True       True               14m

新しい ClusterApprovalRequest オブジェクトを承認するには、同じ approval.json ファイルを再利用して修正プログラムを適用しましょう。

kubectl patch clusterapprovalrequests example-run-2-canary --type='merge' --subresource=status --patch-file approval.json

新しいオブジェクトが承認されているかどうかを確認します。

kubectl get clusterapprovalrequest                                                                            

出力は次の例のようになります。

NAME                   UPDATE-RUN      STAGE    APPROVED   APPROVALACCEPTED   AGE
example-run-2-canary   example-run-2   canary   True       True               2m7s
example-run-canary     example-run     canary   True       True               15m

これで、configmap test-cm は 3 つのメンバー クラスターすべてにデプロイされ、データは value1に戻されます。

apiVersion: v1
data:
  key: value1
kind: ConfigMap
metadata:
  ...
  name: test-cm
  namespace: test-namespace
  ...

リソースをクリーンアップする

このチュートリアルが完了したら、作成したリソースをクリーンアップできます。

# Delete the staged update runs
kubectl delete csur example-run example-run-2

# Delete the staged update strategy
kubectl delete csus example-strategy

# Delete the cluster resource placement
kubectl delete crp example-placement

# Delete the test namespace (this will also delete the configmap)
kubectl delete namespace test-namespace

次のステップ

この記事では、ClusterStagedUpdateRun を使用して、メンバー クラスター間で段階的なロールアウトを調整する方法について説明しました。 段階的な更新戦略を作成し、プログレッシブ ロールアウトを実行し、以前のバージョンへのロールバックを実行しました。

段階的な更新プログラムの実行と関連する概念の詳細については、次のリソースを参照してください。