Azure Kubernetes Fleet Manager の段階的な更新実行では、ステージバイステージ プロセスを使用して複数のメンバー クラスターにワークロードをデプロイするための制御されたアプローチが提供されます。 この方法では、ターゲット クラスターに順番にデプロイし、オプションの待機時間とステージ間の承認ゲートを使用して、リスクを最小限に抑えることができます。
この記事では、段階的な更新実行を作成して実行し、ワークロードを段階的にデプロイし、必要に応じて以前のバージョンにロールバックする方法について説明します。
Prerequisites
アクティブなサブスクリプションを含む Azure アカウントが必要です。 無料でアカウントを作成できます。
この記事で使用される概念と用語を理解するには、 段階的なロールアウト戦略の概念の概要を参照してください。
この記事の内容を完了するには、Azure CLI バージョン 2.58.0 以降がインストールされている必要があります。 インストールとアップグレードについては、「Azure CLI のインストール」を参照してください。
Kubernetes CLI (kubectl) がまだインストールされていない場合は、次のコマンドを使用してインストールしてください。
az aks install-cliAzure 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.typeはExternalに設定され、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 を使用して、メンバー クラスター間で段階的なロールアウトを調整する方法について説明しました。 段階的な更新戦略を作成し、プログレッシブ ロールアウトを実行し、以前のバージョンへのロールバックを実行しました。
段階的な更新プログラムの実行と関連する概念の詳細については、次のリソースを参照してください。
Azure Kubernetes Service