Partager via


Modèles de mise à niveau de charge de travail avec état

Mettez à niveau des clusters qui exécutent des bases de données et des applications avec état sans perte de données à l’aide de ces modèles éprouvés.

Présentation de cet article

Cet article fournit des modèles de mise à niveau spécifiques à la base de données pour les clusters Azure Kubernetes Service (AKS) avec des charges de travail avec état, telles que :

  • Modèle de roue ferris PostgreSQL pour un temps d’arrêt d’environ 30 secondes.
  • Remplacement propagé de Redis pour les mises à niveau de cache sans temps d’arrêt.
  • Cascades de pas à pas mongoDB pour la sécurité des jeux de réplicas.
  • Listes de contrôle de mise à niveau d’urgence pour les réponses de sécurité.
  • Procédures de validation et de restauration pour la protection des données.

Ces modèles sont les mieux utilisés par les administrateurs de base de données pour les applications avec des données persistantes et des services avec état critique.

Pour plus d’informations, consultez les articles suivants :


Pour un démarrage rapide, sélectionnez un lien pour obtenir des instructions :

Choisir votre modèle

Type de base de données Modèle de mise à niveau Temps d'arrêt Complexité Idéal pour
PostgreSQL Grande roue Temps d’arrêt d’environ 30 secondes Moyenne Bases de données de production
Redis Remplacement propagé Aucun Bas Couches de cache
MongoDB Cascade pas à pas Temps d’arrêt d’environ 10 secondes Moyenne Bases de données de documents
Elasticsearch Rééquilibrage des partitions (bientôt disponible) Aucun Élevé Rechercher des clusters
N’importe quelle base de données Sauvegarde-restauration (bientôt disponible) Temps d’arrêt de 2 minutes à 5 minutes Bas Configurations simples

Liste de contrôle de mise à niveau d’urgence

Avez-vous besoin de mettre à niveau maintenant en raison de problèmes de sécurité ?

  1. Exécutez les commandes suivantes pour une vérification de sécurité immédiate (deux minutes) :

    # Verify all replicas are healthy
    kubectl get pods -l tier=database -o wide
    # Check replication lag
    ./scripts/check-replica-health.sh
    # Ensure recent backup exists
    kubectl get job backup-job -o jsonpath='{.status.completionTime}'
    
  2. Choisissez un modèle d’urgence (une minute) :

  3. Exécuter avec un filet de sécurité (fenêtre de 15 minutes à 30 minutes) :

    • Testez toujours les procédures de restauration à l’avance.
    • Surveillez les métriques d’application pendant la mise à niveau.
    • Conservez l’équipe de base de données en veille.

Modèle de roue ferris : PostgreSQL

Ce modèle est idéal pour les clusters PostgreSQL à 3 nœuds avec configuration du réplica principal/réplica dans les zones de disponibilité.

Modèle visuel :

Initial: [PRIMARY] [REPLICA-1] [REPLICA-2]
Step 1:  [PRIMARY] [REPLICA-1] [NEW-NODE]  ← Add new node
Step 2:  [REPLICA-1] [NEW-NODE] [REPLICA-2] ← Promote & remove old primary  
Step 3:  [NEW-PRIMARY] [NEW-NODE] [REPLICA-2] ← Complete rotation

Implémentation rapide (20 minutes)

# 1. Add new node to cluster
kubectl scale statefulset postgres-cluster --replicas=4
# 2. Wait for new replica to sync
kubectl wait --for=condition=ready pod postgres-cluster-3 --timeout=300s
# 3. Promote new primary and failover (30-second downtime window)
kubectl exec postgres-cluster-3 -- pg_ctl promote -D /var/lib/postgresql/data
# 4. Update service endpoint
kubectl patch service postgres-primary --patch '{"spec":{"selector":{"app":"postgres-cluster","role":"primary","pod":"postgres-cluster-3"}}}'
# 5. Remove old primary node
kubectl delete pod postgres-cluster-0
Guide détaillé pas à pas

Validation des prérequis

#!/bin/bash
# pre-upgrade-validation.sh

echo "=== PostgreSQL Cluster Health Check ==="
# Check replication status
kubectl exec postgres-primary-0 -- psql -c "SELECT * FROM pg_stat_replication;"
# Verify sync replication (must show 'sync' state)
SYNC_COUNT=$(kubectl exec postgres-primary-0 -- psql -t -c "SELECT count(*) FROM pg_stat_replication WHERE sync_state='sync';")
if [ "$SYNC_COUNT" -lt 2 ]; then
    echo "ERROR: Need at least 2 synchronous replicas"
    exit 1
fi
# Confirm recent backup exists
LAST_BACKUP=$(kubectl get job postgres-backup -o jsonpath='{.status.completionTime}')
echo "Last backup: $LAST_BACKUP"
# Test failover capability in staging first
echo "✅ Prerequisites validated"

Étape 1 : Monter en puissance avec un nouveau nœud

# Add new node with upgraded Kubernetes version
kubectl patch statefulset postgres-cluster --patch '{
  "spec": {
    "replicas": 4,
    "template": {
      "spec": {
        "nodeSelector": {
          "kubernetes.io/arch": "amd64",
          "aks-nodepool": "upgraded-pool"
        }
      }
    }
  }
}'
# Monitor new pod startup
kubectl get pods -l app=postgres-cluster -w
# Verify new replica joins cluster
kubectl exec postgres-cluster-3 -- psql -c "SELECT * FROM pg_stat_replication;"

Étape 2 : Exécuter un basculement contrôlé

#!/bin/bash
# controlled-failover.sh

echo "=== Starting Controlled Failover ==="
# Ensure minimal replication lag (< 0.1-second)
LAG=$(kubectl exec postgres-primary-0 -- psql -t -c "SELECT EXTRACT(EPOCH FROM now() - pg_last_xact_replay_timestamp());")
if (( $(echo "$LAG > 0.1" | bc -l) )); then
    echo "ERROR: Replication lag too high ($LAG seconds)"
    exit 1
fi
# Pause application writes (use connection pool drain)
kubectl patch configmap pgbouncer-config --patch '{"data":{"pgbouncer.ini":"[databases]\napp_db = host=postgres-primary port=5432 dbname=appdb pool_mode=statement max_db_connections=0"}}'
# Wait for active transactions to complete
sleep 10
# Promote new primary (this is the 30-second downtime window)
kubectl exec postgres-cluster-3 -- pg_ctl promote -D /var/lib/postgresql/data
# Update service selector to new primary
kubectl patch service postgres-primary --patch '{
  "spec": {
    "selector": {
      "statefulset.kubernetes.io/pod-name": "postgres-cluster-3"
    }
  }
}'
# Resume application writes
kubectl patch configmap pgbouncer-config --patch '{"data":{"pgbouncer.ini":"[databases]\napp_db = host=postgres-primary port=5432 dbname=appdb pool_mode=statement"}}'
echo "✅ Failover completed"

Étape 3 : Nettoyer et valider

# Remove old primary node
kubectl delete pod postgres-cluster-0 --force
# Scale back to 3 replicas
kubectl patch statefulset postgres-cluster --patch '{"spec":{"replicas":3}}'
# Validate cluster health
kubectl exec postgres-cluster-3 -- psql -c "SELECT * FROM pg_stat_replication;"
# Test application connectivity
kubectl run test-db-connection --image=postgres:15 --rm -it -- psql -h postgres-primary -U app_user -d app_db -c "SELECT version();"

Configuration avancée

Pour les bases de données stratégiques qui nécessitent un <temps d’arrêt de 10 secondes :

# Use synchronous replication with multiple standbys
# postgresql.conf
synchronous_standby_names = 'ANY 2 (standby1, standby2, standby3)'
synchronous_commit = 'remote_apply'

Validation réussie

Pour valider votre progression, utilisez la liste de contrôle suivante :

  • Le nouveau principal accepte les lectures et les écritures.
  • Tous les réplicas affichent une réplication saine.
  • L’application se reconnecte automatiquement.
  • Aucune perte de données détectée.
  • Sauvegarde/restauration testée sur le nouveau serveur principal.

Restauration d’urgence

Pour les problèmes immédiats (<2 minutes)

Redirigez le trafic vers le trafic principal précédent :

kubectl patch service postgres-primary --patch '{
  "spec": {
    "selector": {
      "statefulset.kubernetes.io/pod-name": "postgres-cluster-1"
    }
  }
}'
Pour une récupération complète du basculement (5 à 10 minutes)
  1. Arrêtez les écritures dans le principal actuel :

    kubectl exec postgres-primary-0 -- psql -c "SELECT pg_reload_conf();"
    
  2. Rediriger le service vers un réplica sain :

    kubectl patch service postgres-primary --patch '{"spec":{"selector":{"statefulset.kubernetes.io/pod-name":"postgres-replica-1-0"}}}'
    
  3. Promouvoir un réplica vers le nouveau réplica principal :

    kubectl exec postgres-replica-1-0 -- pg_ctl promote -D /var/lib/postgresql/data
    kubectl wait --for=condition=ready pod postgres-replica-1-0 --timeout=60s
    
  4. Mettre à jour les chaînes de connexion :

    kubectl patch configmap postgres-config --patch '{"data":{"primary-host":"postgres-replica-1-0.postgres"}}'
    
  5. Vérifiez que le nouveau principal accepte les écritures :

    kubectl exec postgres-replica-1-0 -- psql -c "CREATE TABLE upgrade_test (id serial, timestamp timestamp default now());"
    kubectl exec postgres-replica-1-0 -- psql -c "INSERT INTO upgrade_test DEFAULT VALUES;"
    

Résultat attendu : Environ 30 secondes d’arrêt, aucune perte de données et un nœud mis à niveau qui exécute la version actuelle de Kubernetes.

Étape 3 : Mettre à niveau Node1 (ancien principal)

#!/bin/bash
# upgrade-node1.sh

echo "=== Step 3: Upgrade Node1 (Former Primary) ==="

# Drain Node1 gracefully
kubectl drain aks-nodepool1-12345678-vmss000000 --grace-period=300 --delete-emptydir-data --ignore-daemonsets

# Trigger node upgrade
az aks nodepool upgrade \
    --resource-group production-rg \
    --cluster-name aks-prod \
    --name nodepool1 \
    --kubernetes-version 1.29.0 \
    --max-surge 0 \
    --max-unavailable 1

# Monitor upgrade progress
while kubectl get node aks-nodepool1-12345678-vmss000000 -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' | grep -q "False"; do
    echo "Waiting for node upgrade to complete..."
    sleep 30
done

echo "Node1 upgrade completed"

Étape 4 : Rejoindre Node1 en tant que réplica

#!/bin/bash
# rejoin-node1.sh

echo "=== Step 4: Rejoin Node1 as Replica ==="

# Wait for postgres pod to be scheduled on upgraded node
kubectl wait --for=condition=ready pod postgres-primary-0 --timeout=300s

# Reconfigure as replica pointing to new primary (Node2)
kubectl exec postgres-primary-0 -- bash -c "
echo 'standby_mode = on' >> /var/lib/postgresql/data/recovery.conf
echo 'primary_conninfo = \"host=postgres-replica-1-0.postgres port=5432\"' >> /var/lib/postgresql/data/recovery.conf
"

# Restart postgres to apply replica configuration
kubectl delete pod postgres-primary-0
kubectl wait --for=condition=ready pod postgres-primary-0 --timeout=120s

# Verify replication is working
kubectl exec postgres-replica-1-0 -- psql -c "SELECT * FROM pg_stat_replication WHERE application_name='postgres-primary-0';"

echo "Node1 successfully rejoined as replica"

Étape 5 : Mettre à niveau le nœud3 (réplica-2)

#!/bin/bash
# upgrade-node3.sh

echo "=== Step 5: Upgrade Node3 (Replica-2) ==="

# Similar process for Node3
kubectl drain aks-nodepool1-12345678-vmss000002 --grace-period=300 --delete-emptydir-data --ignore-daemonsets

az aks nodepool upgrade \
    --resource-group production-rg \
    --cluster-name aks-prod \
    --name nodepool1 \
    --kubernetes-version 1.29.0 \
    --max-surge 0 \
    --max-unavailable 1

# Wait for upgrade and pod readiness
kubectl wait --for=condition=ready pod postgres-replica-2-0 --timeout=300s

# Verify all replicas are in sync
kubectl exec postgres-replica-1-0 -- psql -c "SELECT application_name, state, sync_state FROM pg_stat_replication;"

Étape 6 : Basculement final (Node2 → Node3)

#!/bin/bash
# final-failover.sh

echo "=== Step 6: Final Failover and Node2 Upgrade ==="

# Failover primary from Node2 to Node3
kubectl patch service postgres-primary --patch '{"spec":{"selector":{"statefulset.kubernetes.io/pod-name":"postgres-replica-2-0"}}}'
kubectl exec postgres-replica-2-0 -- pg_ctl promote -D /var/lib/postgresql/data

# Upgrade Node2
kubectl drain aks-nodepool1-12345678-vmss000001 --grace-period=300 --delete-emptydir-data --ignore-daemonsets

az aks nodepool upgrade \
    --resource-group production-rg \
    --cluster-name aks-prod \
    --name nodepool1 \
    --kubernetes-version 1.29.0 \
    --max-surge 0 \
    --max-unavailable 1

# Rejoin Node2 as replica
kubectl wait --for=condition=ready pod postgres-replica-1-0 --timeout=300s

echo "All nodes upgraded successfully. PostgreSQL cluster operational."

Validation et surveillance

#!/bin/bash
# post-upgrade-validation.sh

echo "=== Post-Upgrade Validation ==="

# Verify cluster topology
kubectl get pods -l app=postgres -o wide

# Check all replicas are connected
kubectl exec postgres-replica-2-0 -- psql -c "SELECT application_name, client_addr, state FROM pg_stat_replication;"

# Validate data integrity
kubectl exec postgres-replica-2-0 -- psql -c "SELECT COUNT(*) FROM upgrade_test;"

# Performance validation
kubectl exec postgres-replica-2-0 -- psql -c "EXPLAIN ANALYZE SELECT * FROM pg_stat_activity;"

echo "Upgrade validation completed successfully"

Remplacement propagé du cluster Redis

Dans ce scénario, un cluster Redis à six nœuds (trois principaux et trois réplicas) ne nécessite aucun temps d’arrêt.

Implémentation

#!/bin/bash
# redis-cluster-upgrade.sh

echo "=== Redis Cluster Rolling Upgrade ==="

# Get cluster topology
kubectl exec redis-0 -- redis-cli cluster nodes

# Upgrade replica nodes first (no impact to writes)
for replica in redis-1 redis-3 redis-5; do
    echo "Upgrading replica: $replica"
    
    # Remove replica from cluster temporarily
    REPLICA_ID=$(kubectl exec redis-0 -- redis-cli cluster nodes | grep $replica | cut -d' ' -f1)
    kubectl exec redis-0 -- redis-cli cluster forget $REPLICA_ID
    
    # Drain and upgrade node
    kubectl delete pod $replica
    kubectl wait --for=condition=ready pod $replica --timeout=120s
    
    # Rejoin cluster
    kubectl exec redis-0 -- redis-cli cluster meet $(kubectl get pod $replica -o jsonpath='{.status.podIP}') 6379
    
    echo "Replica $replica upgraded and rejoined"
done

# Upgrade master nodes with failover
for master in redis-0 redis-2 redis-4; do
    echo "Upgrading master: $master"
    
    # Trigger failover to replica
    kubectl exec $master -- redis-cli cluster failover
    
    # Wait for failover completion
    sleep 10
    
    # Upgrade the demoted master (now replica)
    kubectl delete pod $master
    kubectl wait --for=condition=ready pod $master --timeout=120s
    
    echo "Master $master upgraded"
done

echo "Redis cluster upgrade completed"

Pas à pas du jeu de réplicas MongoDB

Dans ce scénario, un jeu de réplicas MongoDB à trois membres nécessite une étape principale coordonnée.

Implémentation

#!/bin/bash
# MongoDB upgrade script

Echo "=== MongoDB Replica Set Upgrade ==="

# Check replica set status
kubectl exec mongo-0 --mongo --eval "rs.status()"