Condividi tramite


Orchestrare le implementazioni a fasi tra cluster membri

Le esecuzioni di aggiornamento a fasi di Azure Kubernetes Fleet Manager offrono un approccio controllato alla distribuzione di carichi di lavoro in più cluster membri usando un processo di staging per fase. Per ridurre al minimo i rischi, questo approccio viene distribuito in sequenza nei cluster di destinazione, con tempi di attesa facoltativi e controlli di approvazione tra fasi.

Questo articolo illustra come creare ed eseguire esecuzioni di aggiornamenti a fasi per distribuire i carichi di lavoro progressivamente ed eseguire il rollback alle versioni precedenti quando necessario.

Note

Azure Kubernetes Fleet Manager offre due approcci per gli aggiornamenti a fasi:

  • A livello di cluster: usare ClusterStagedUpdateRun con ClusterResourcePlacement per gli amministratori di fleet che gestiscono le modifiche a livello di infrastruttura
  • Con Ambito spazio dei nomi: usare StagedUpdateRun con ResourcePlacement per i team delle applicazioni che gestiscono le distribuzioni all'interno dei rispettivi spazi dei nomi specifici

Gli esempi in questo articolo illustrano entrambi gli approcci usando le schede. Scegliere la scheda corrispondente all'ambito di distribuzione.

Prerequisites

  • È necessario un account Azure con una sottoscrizione attiva. Creare un account gratuito.

  • Per comprendere i concetti e la terminologia usati in questo articolo, leggere la panoramica concettuale delle strategie di implementazione a fasi.

  • Per completare questo articolo, è necessaria l'interfaccia della riga di comando di Azure versione 2.58.0 o successiva. Per eseguire l'installazione o l'aggiornamento, vedere Installare l'interfaccia della riga di comando di Azure.

  • Se l'interfaccia della riga di comando di Kubernetes (kubectl) non è ancora disponibile, è possibile installarla usando questo comando:

    az aks install-cli
    
  • È necessaria l'estensione dell'interfaccia della riga di comando di Azure fleet. È possibile installarlo eseguendo il comando seguente:

    az extension add --name fleet
    

    Eseguire il comando az extension update per effettuare l'aggiornamento alla versione più recente dell'estensione:

    az extension update --name fleet
    

Configurare l'ambiente demo

Questa demo viene eseguita in un Fleet Manager con un cluster hub e tre cluster membri. Se non è disponibile, seguire la guida introduttiva per creare un Fleet Manager con un cluster hub. Aggiungere quindi i cluster del servizio Azure Kubernetes come membri.

Questa esercitazione illustra le esecuzioni degli aggiornamenti a fasi usando un ambiente demo fleet con tre cluster membri con le etichette seguenti:

nome del cluster labels
member1 environment=canary, order=2
member2 environment=staging
member3 environment=canary, order=1

Per raggruppare i cluster in base all'ambiente e controllare l'ordine di distribuzione all'interno di ogni fase, queste etichette consentono di creare fasi.

Preparare i carichi di lavoro per il posizionamento

Pubblicare carichi di lavoro nel cluster hub in modo che possano essere inseriti nei cluster membri.

Creare uno spazio dei nomi e un file configmap per il carico di lavoro nel cluster hub:

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

Per distribuire le risorse, creare un clusterResourcePlacement:

Note

spec.strategy.type è impostato su External per consentire l'implementazione attivata con 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

Tutti e tre i cluster devono essere pianificati perché vengono usati i criteri PickAll, ma non è necessario distribuire risorse nei cluster membri perché non è stato ancora creato un oggetto ClusterStagedUpdateRun.

Verificare che il posizionamento sia pianificato:

kubectl get crp example-placement

L'output dovrebbe essere simile all'esempio seguente:

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

Gestire gli snapshot delle risorse

Fleet Manager crea snapshot delle risorse quando le risorse cambiano. Ogni snapshot ha un indice univoco che è possibile usare per fare riferimento a versioni specifiche delle risorse.

Tip

Per altre informazioni sugli snapshot delle risorse e sul relativo funzionamento, vedere Informazioni sugli snapshot delle risorse.

Controllare gli snapshot delle risorse correnti

Per controllare gli snapshot delle risorse correnti:

kubectl get clusterresourcesnapshots --show-labels

L'output dovrebbe essere simile all'esempio seguente:

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

È disponibile una sola versione dello snapshot. È l'ultima versione (kubernetes-fleet.io/is-latest-snapshot=true) e contiene l'indice delle risorse 0 (kubernetes-fleet.io/resource-index=0).

Creare un nuovo snapshot della risorsa

Modificare ora la mappa di configurazione con un nuovo valore:

kubectl edit cm test-cm -n test-namespace

Aggiornare il valore da value1 a value2:

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

L'output dovrebbe essere simile all'esempio seguente:

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

Verranno ora visualizzate due versioni degli snapshot delle risorse con indice 0 e 1 rispettivamente:

kubectl get clusterresourcesnapshots --show-labels

L'output dovrebbe essere simile all'esempio seguente:

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

L'etichetta più recente è impostata su example-placement-1-snapshot, che contiene i dati configmap più recenti:

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

L'output dovrebbe essere simile all'esempio seguente:

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

Distribuire una strategia di aggiornamento a fasi

Un ClusterStagedUpdateStrategy oggetto definisce il modello di orchestrazione che raggruppa i cluster in fasi e specifica la sequenza di implementazione. Seleziona i cluster membri in base alle etichette. Per la dimostrazione, ne viene creata una con due fasi, staging e canary:

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

Distribuire un'esecuzione di aggiornamento a fasi per implementare la modifica più recente

Un ClusterStagedUpdateRun esegue il rollout di un ClusterResourcePlacement in seguito a un ClusterStagedUpdateStrategy. Per attivare l'esecuzione dell'aggiornamento a fasi per ClusterResourcePlacement (CRP), viene creato un oggetto ClusterStagedUpdateRun che specifica il nome CRP, il nome della strategia updateRun e l'indice dello snapshot delle risorse più recente ("1"):

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

L'esecuzione dell'aggiornamento a fasi viene inizializzata ed eseguita:

kubectl get csur example-run

L'output dovrebbe essere simile all'esempio seguente:

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

Un'analisi più dettagliata dello stato dopo la scadenza di un minuto TimedWait :

kubectl get csur example-run -o yaml

L'output dovrebbe essere simile all'esempio seguente:

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"

È possibile notare che il periodo TimedWait per la fase di staging scade e si nota anche che è stato creato l'oggetto per l'attività ClusterApprovalRequest di approvazione nella fase canary. Possiamo controllare il ClusterApprovalRequest generato e verificare che nessuno lo abbia ancora approvato.

kubectl get clusterapprovalrequest

L'output dovrebbe essere simile all'esempio seguente:

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

Approvare l'esecuzione dell'aggiornamento a fasi

È possibile approvare ClusterApprovalRequest creando un file di patch JSON e applicandolo:

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

Inviare una richiesta di patch per approvare usando il file JSON creato.

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

Verificare quindi di aver approvato la richiesta:

kubectl get clusterapprovalrequest

L'output dovrebbe essere simile all'esempio seguente:

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

Ora è possibile procedere e completare ClusterStagedUpdateRun:

kubectl get csur example-run

L'output dovrebbe essere simile all'esempio seguente:

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

Verificare il completamento dell'implementazione

ClusterResourcePlacement mostra anche l'implementazione completata e le risorse sono disponibili in tutti i cluster membri:

kubectl get crp example-placement

L'output dovrebbe essere simile all'esempio seguente:

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

Il test-cm configmap deve essere distribuito in tutti e tre i cluster membri, con i dati più recenti:

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

Distribuire un secondo clusterStagedUpdateRun per eseguire il rollback a una versione precedente

Implementare una seconda esecuzione di aggiornamento in fasi per effettuare il rollback

Si supponga che l'amministratore del carico di lavoro voglia eseguire il rollback della modifica della mappa di configurazione, ripristinando il valore value2 in value1. Anziché aggiornare manualmente la configmap dall'hub, è possibile creare un nuovo ClusterStagedUpdateRun utilizzando un indice di snapshot della risorsa precedente, nel nostro contesto "0", e riutilizzare la stessa strategia:

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

Esaminiamo il nuovo ClusterStagedUpdateRun:

kubectl get csur

L'output dovrebbe essere simile all'esempio seguente:

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

Al termine di un minutoTimedWait, verrà visualizzato l'oggetto ClusterApprovalRequest creato per il nuovo ClusterStagedUpdateRun.

kubectl get clusterapprovalrequest

L'output dovrebbe essere simile all'esempio seguente:

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

Per approvare il nuovo ClusterApprovalRequest oggetto, riutilizzare lo stesso approval.json file per applicare patch:

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

Verificare se il nuovo oggetto è approvato:

kubectl get clusterapprovalrequest                                                                            

L'output dovrebbe essere simile all'esempio seguente:

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

Il file configmap test-cm deve ora essere distribuito in tutti e tre i cluster membri, con i dati ripristinati in value1:

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

Differenze principali tra approcci

Aspetto Con ambito cluster Con ambito spazio dei nomi
Risorsa strategia ClusterStagedUpdateStrategy StagedUpdateStrategy
Aggiornare la risorsa di esecuzione ClusterStagedUpdateRun StagedUpdateRun
Posizionamento di destinazione ClusterResourcePlacement ResourcePlacement
Risorsa di approvazione ClusterApprovalRequest (nome breve: careq) ApprovalRequest (nome breve: areq)
Risorsa Snapshot ClusterResourceSnapshot ResourceSnapshot
Scope A livello di cluster Vincolato allo spazio dei nomi
Caso d'uso Implementazioni dell'infrastruttura Distribuzioni di applicazioni
Autorizzazioni Livello di amministratore del cluster Livello del namespace

Pulire le risorse

Al termine di questa esercitazione, è possibile pulire le risorse create:

kubectl delete csur example-run example-run-2
kubectl delete csus example-strategy
kubectl delete crp example-placement
kubectl delete namespace test-namespace

Passaggi successivi

In questo articolo si è appreso come usare le esecuzioni di aggiornamento a fasi per orchestrare le implementazioni tra cluster membri. Sono state create strategie di aggiornamento a fasi sia per le distribuzioni con ambito cluster che per le distribuzioni con ambito spazio dei nomi, sono state eseguite implementazioni progressive ed è stato eseguito il rollback alle versioni precedenti.

Per altre informazioni sulle esecuzioni degli aggiornamenti a fasi e sui concetti correlati, vedere le risorse seguenti: