Upgrade eines 3-Knoten WSFC mit Always On Availability Group: Windows Server 2019 + SQL Server 2017 → Windows Server 2025 + SQL Server 2025 (VMware vSphere)
Dieser Artikel beschreibt einen vollständigen, schrittweisen Migrations- und Upgrade-Pfad für einen 3-Knoten Windows Server Failover Cluster (WSFC) mit SQL Server Always On Availability Group von Windows Server 2019 / SQL Server 2017 auf Windows Server 2025 / SQL Server 2025. Die Migration erfolgt auf VMware vSphere mittels eines parallelen Clusters und einer Distributed Availability Group (Distributed AG), bei der alle Produktiv-Namen (Listener, Cluster, Instanz) am Ende erhalten bleiben.
1. Executive Summary & Strategie
Die bestehende Umgebung (3 Knoten, Windows Server 2019, SQL Server 2017 Always On AG) wird in zwei großen Schritten modernisiert: Betriebssystem auf Windows Server 2025 und Datenbank auf SQL Server 2025.
Gewählte Strategie – In-Place Rolling Re-Image (Variante B): Die vorhandenen drei VMware-VM-Hüllen (SQLN01, SQLN02, SQLN03) werden weiterverwendet. Pro Knoten wird die alte System- und Daten-VMDK detached (als Rollback-Anker behalten), eine frische OS-Disk angelegt und Windows Server 2025 + SQL Server 2025 installiert. Die Re-Imaged-Knoten bilden einen neuen WSFC und übernehmen die Daten von der Altumgebung per Distributed Availability Group. Nach Cutover wird auch der letzte Knoten re-imaged; abschließend werden Cluster- und Listener-Name auf die Originalwerte zurückgesetzt.
Warum dieses Vorgehen?
- VMware-VM-Hüllen bleiben erhalten – vCenter-UUID, MAC-Adressen, Folder-Pfade, Tags, Permissions, Backup-Job-Zuordnungen und Monitoring-IDs sind unverändert. Kein zusätzlicher Kapazitätsbedarf für 3 parallele Test-VMs.
- Hostnames sind durchgehend konstant –
sp_dropserver/sp_addserver, Domain-Rejoin oder SPN-Hostname-Bereinigung entfallen. Apps, die per Hostname referenzieren, sind nicht betroffen. - Der WSFC Cluster OS Rolling Upgrade unterstützt laut Microsoft nur den Sprung auf die nächste OS-Hauptversion (2022 → 2025). 2019 → 2025 ist nicht unterstützt – ein vollständiges Re-Image des Knotens ist daher zwingend.
- SQL Server 2017 → 2025 ist als direktes Upgrade dokumentiert; die Distributed AG zwischen den Versionen ist ein produktiver, von Microsoft beschriebener Migrationspfad.
Phasen-Übersicht
| Phase | Aktion | Risiko |
|---|---|---|
| 0 | Pre-Migration: Backups, DBCC, Witness vor Migration einrichten, VM-Inventar, VM-Clones als Rollback-Anker | niedrig |
| 1 | SQLN03 evict → Re-Image → in neuen WSFC (Single-Node) → AG_PROD_NEW + Listener (Temp-IP) + DAG DAG_MIGRATION aufbauen | mittel |
| 2 | SQLN02 evict → Re-Image → Join neuer Cluster + AG — Alter Cluster läuft auf 1 Knoten + Witness (SPOF!) | hoch |
| 3 | Cutover: DAG sync → SYNC-Commit → Failover auf neue AG — Point of no Return (DB-Upgrade auf 2025-Format) | hoch |
| 4 | SQLN01 (Ex-Primary) evict → Re-Image → Join neuer Cluster + AG. Altcluster und alte AG sind aufgelöst | niedrig |
| 5 | Rename neuer Cluster SQLCL01N → SQLCL01 und Listener SQLLST01N → SQLLST01 mit Original-IP 10.10.10.50. AG-Name bleibt AG_PROD_NEW | niedrig |
N und werden in Phase 5 auf die Originalnamen zurückgesetzt. Original-Listener-IP 10.10.10.50 wird wiederverwendet. AG-Name bleibt AG_PROD_NEW – ein Rename via DROP+CREATE ist mit Distributed AG / TDE-Datenbanken zu riskant; Apps verbinden sich über den Listener-Namen, nicht über den AG-Namen.
Safety.AllowProduction = $truefür Cutover und Rename.Safety.AcceptPhase2SPOFRisk = $truevor Phase 2 (Alt-Cluster läuft auf 1 Knoten + Witness während SQLN02 re-imaged wird).Safety.AcceptNoRollbackAfterCutover = $truevor Phase 3 (nach DB-Upgrade kein Failback auf SQL 2017 mehr möglich).
2. Voraussetzungen & Kompatibilitätsmatrix
Unterstützte Upgrade-Pfade
| Komponente | Quelle | Ziel | Unterstützt? |
|---|---|---|---|
| SQL Server | 2017 (14.x) | 2025 (17.x) | Ja – direkt (MS Learn: Supported version and edition upgrades 2025) |
| Windows Server | 2019 | 2025 | Nur Migration oder mehrstufig (2019→2022→2025). Direkter Rolling Upgrade nicht unterstützt. |
| SQL 2025 auf Win Server 2019 | – | – | Ja (Minimum-OS für SQL 2025 ist Server 2019). |
| AG mixed-version (Primary 2017 / Secondary 2025) | – | – | Nur temporär während Rolling Upgrade oder dauerhaft via Distributed AG. |
Anforderungen SQL Server 2025
- x64-CPU, mind. 1,4 GHz (empfohlen ≥ 2,0 GHz), mind. 4 GB RAM (empfohlen deutlich mehr).
- .NET Framework 4.7.2.
- Windows Server 2019, 2022 oder 2025 (Datacenter/Standard/Core).
- Aktuelle SSMS-Version (SSMS 20+ empfohlen für 2025-Features).
Lizenzierung & Edition
- Edition-Mapping prüfen: SQL 2017 Enterprise → SQL 2025 Enterprise. Web Edition entfällt in SQL 2025.
- Windows Server 2025 Datacenter empfohlen wegen Live-Migration / unbeschränkter Virtualisierungsrechte.
- Software Assurance / aktive Lizenzen verifizieren.
3. Namens-Erhaltung (Listener, Cluster, Hostnamen) PFLICHT
Damit Applikationen, Linked Servers, Connection-Strings, SPNs, Kerberos-Delegationen, Backup-Jobs und Monitoring nach der Migration ohne Anpassung weiterarbeiten, müssen die produktiv genutzten Namen am Ende identisch sein. Da bei Variante B die Hostnames durchgehend konstant bleiben, vereinfacht sich die Namens-Matrix erheblich.
3.1 Namens-Matrix
| Objekt | Vor Migration | Während Phasen 1–4 | Nach Phase 5 (final) |
|---|---|---|---|
| VMware-VM-Hüllen (UUID/MAC/Folder) | SQLN01 · SQLN02 · SQLN03 | unverändert (Disks getauscht) | unverändert |
| Computer-Hostnamen | SQLN01 · SQLN02 · SQLN03 | unverändert (gleiche Namen, frisches OS) | unverändert |
| WSFC-Clustername (CNO) | SQLCL01 (Win2019) | SQLCL01N (neuer Cluster Win2025) | SQLCL01 (Rename in Phase 5) |
| AG-Name | AG_PROD (2017) | AG_PROD (alt) + AG_PROD_NEW (neu) | AG_PROD_NEW (kein Rename – bewusst) |
| AG-Listener-Name (VCO) | SQLLST01 | SQLLST01N (Temp-IP) | SQLLST01 (Rename in Phase 5) |
| Listener-IP | 10.10.10.50 | 10.10.10.51 (temp) | 10.10.10.50 (wiederverwendet) |
| SQL-Instanzname | Default MSSQLSERVER | identisch | identisch |
| AD-Computer-Account (Knoten) | existiert | behalten + Passwort-Reset (nicht löschen!) | identisch |
| DB-Namen / Service-Account | unverändert | unverändert | unverändert |
AG_PROD_NEW dauerhaft belassen. Applikationen verbinden sich über den Listener-Namen SQLLST01 – der AG-Name ist nur für DBA-Tools/DMVs sichtbar.
3.2 Strategie pro Objekt
Computer-Hostnamen (SQLN01/02/03)
Bleiben durchgehend gleich. Vor dem Re-Image wird der Knoten evicted, sein AD-Computer-Account wird nicht gelöscht, sondern lediglich das Passwort zurückgesetzt (Set-ADAccountPassword -Reset). Nach erneutem Domain-Join (Re-Image bringt den selben Hostnamen) übernimmt der Server den vorhandenen AD-Account inkl. SPNs, ACLs und Gruppenmitgliedschaften.
Remove-ADComputer würde alle Gruppenmitgliedschaften, ACLs (insbesondere auf File-Shares/Storage) und automatisch registrierte SPNs zerstören. Bei Re-Use des Hostnamens nur das Computer-Account-Passwort zurücksetzen – der frisch installierte Knoten übernimmt es beim Domain-Join.
Listener-Name & Listener-IP
- Während Phasen 1–4 läuft auf dem neuen Cluster
SQLLST01Nmit der temporären IP10.10.10.51. Der alte ListenerSQLLST01(IP10.10.10.50) lebt parallel auf dem alten Cluster und bedient die Produktion bis zum Cutover. - Nach Cutover und Decommission des Altclusters wird in Phase 5 der Listener auf den Originalnamen und die Original-IP umgebogen:
Apps verbinden sich ohne Connection-String-Änderung wieder überALTER AVAILABILITY GROUP [AG_PROD_NEW] REMOVE LISTENER 'SQLLST01N'; ALTER AVAILABILITY GROUP [AG_PROD_NEW] ADD LISTENER N'SQLLST01' ( WITH IP ((N'10.10.10.50', N'255.255.255.0')), PORT = 1433);SQLLST01.
WSFC-Clustername
Der neue Cluster wird als SQLCL01N gestartet und in Phase 5 nach komplettem Abbau des alten Clusters umbenannt:
(Get-Cluster -Name SQLCL01N).Name = 'SQLCL01'
# Auf allen Knoten:
Restart-Service ClusSvc -Force
AG-Name (bewusst nicht umbenannt)
Die neue AG heißt AG_PROD_NEW und behält diesen Namen. Begründung siehe Alert oben. Apps referenzieren den Listener-Namen, nicht den AG-Namen.
SQL-Instanzname
Default-Instanz MSSQLSERVER bleibt unverändert (Standard-Setup auf jedem Knoten). Bei benannten Instanzen ist der Instanz-Anteil identisch zu setzen.
SPNs & Kerberos
- Hostname-bezogene SPNs (
MSSQLSvc/SQLN01.domain:1433) bleiben gültig, da der Computer-Account erhalten bleibt. - Listener-SPNs werden in Phase 5 vom Skript
11-Rename-Resources.ps1bereinigt und aufSQLLST01neu gesetzt; danachsetspn -Xauf Duplicates prüfen.
DNS / TTL
TTL der A-Records SQLLST01 bereits in Phase 0 auf 60 Sekunden senken – verkürzt Cache-Latenz nach Listener-Switch.
SQLCL01 entfernt, AD-VCO SQLLST01 entfernt, DNS-A-Record SQLLST01 entfernt, IP 10.10.10.50 nicht mehr in Verwendung. Das Skript 11-Rename-Resources.ps1 bricht ab, falls einer dieser Pre-Checks fehlschlägt.
4. Quorum & Witness – kritische Empfehlung MUSS-PRÜFUNG
Empfohlene Witness-Typen (im VMware-Umfeld)
| Typ | Eignung | Hinweise |
|---|---|---|
| Cloud Witness (Azure Storage Account) | Sehr gut – v. a. bei mehreren Standorten | Benötigt Internet (HTTPS/443) und Azure-Subscription mit Standard GPv2 Storage Account (LRS). |
| File Share Witness (SMB 2+) | Sehr gut, on-prem ohne Cloud | Share muss außerhalb der Cluster-Knoten liegen, idealerweise auf einem unabhängigen Server/anderem Failover-Cluster. |
| Disk Witness | Eher für FCI mit Shared Storage | Für AG ohne Shared Storage in der Regel nicht sinnvoll. |
Im neuen Cluster wird im Rahmen dieses Projekts verpflichtend ein Cloud- oder File-Share-Witness eingerichtet (siehe Phase 0, Schritt 0.7 für den alten Cluster, und automatisch durch 06-Build-NewCluster.ps1 für den neuen Cluster).
01-Preflight-Assessment.ps1 richtet den Witness auf dem alten Cluster ein (Sektion Witness.Old in Config.psd1). Auf dem neuen Cluster erfolgt das Witness-Setup im Skript 06-Build-NewCluster.ps1 (Sektion Witness.New).
5. VMware-Best-Practices vor dem Upgrade
Die folgenden Punkte stammen aus den VMware-Architektur-Whitepapern „Architecting Microsoft SQL Server on VMware vSphere“ und „Microsoft WSFC on VMware vSphere“ sowie den Microsoft-Empfehlungen für virtualisierte WSFC.
VM-Hardware
- VM-Hardware-Version auf das von der Ziel-ESXi-Version unterstützte Maximum heben (z. B. vHW 21+).
- PVSCSI-Controller für Daten- und Log-Disks. Mehrere Controller (OS / Data / Log / TempDB) zur IO-Parallelisierung.
- VMXNET3 als Netzwerkadapter; separate vNICs für Public, Cluster Heartbeat und ggf. Backup.
- Neueste VMware Tools installieren.
CPU & Memory
- vCPUs an physikalischer NUMA-Topologie ausrichten; keine breit-überdimensionierten vCPU-Zahlen.
- Memory Reservation = konfigurierter RAM für SQL-VMs (verhindert Ballooning / Swapping).
- „Reserve all guest memory (All locked)“ aktivieren.
Cluster & DRS
- DRS-Anti-Affinity-Regel („VM-VM Separate“) für alle AG-Replicas, damit nie zwei Knoten auf demselben ESXi-Host laufen.
- VM-Host-Affinity an Cluster-/Standort-Topologie ausrichten (z. B. Site-A vs. Site-B Hosts).
- HA-Restart-Priorität für SQL-VMs auf „High“, aber kein VMware-HA-Failover anstelle von WSFC-Failover erwarten.
Storage
- Eager Zeroed Thick oder modernes vVols/vSAN-Profil mit garantierter Performance.
- Separate Datastores / VMDKs für Data, Log, TempDB, Backup; Storage-Latenzziel < 10 ms (write log idealerweise < 5 ms).
- Bei AG ist kein Shared-VMDK / RDM erforderlich – jede Replica hat eigene Disks.
Netzwerk
- MTU 1500 (oder Jumbo Frames konsistent ende-zu-ende, falls AG-Traffic-Volumen es rechtfertigt).
- Latenz zwischen Replicas möglichst < 5 ms für synchronen Commit.
6. Phase 0 – Vorbereitung & Rollback-Anker T−14 Tage
- 0.1 Inventarisierung: Edition, Build/CU-Stand, AG-Konfiguration, Listener-Namen/IPs, Datenbanken (Größe, RTO/RPO), Logins, Linked Servers, SQL Agent Jobs, SSIS-Pakete, Cross-Database-Abhängigkeiten, TDE-Zertifikate, CDC/Replikation.
- 0.2 Data Migration Assistant (DMA) gegen alle DBs ausführen – Breaking Changes / Behavior Changes / Feature Parity prüfen.
- 0.3 Compatibility Level dokumentieren. SQL 2025 unterstützt ältere Compat-Level; ein Wechsel ist nicht automatisch.
- 0.4 Vollbackups (FULL + LOG, geprüft) aller AG-DBs +
master,msdb,model. Restore-Test in Stage. - 0.5 DBCC CHECKDB auf jeder AG-DB – keine Migration mit korrupten DBs.
- 0.6 Skripte sichern: Logins (SID/Hash), Jobs, Linked Servers, Server-Trigger, Audits, Credentials, Resource Governor, Mail-Profile, Endpoints, Zertifikate (TDE-Cert + Key per
BACKUP CERTIFICATE). - 0.7 Witness am alten Cluster nachrüsten PFLICHT – der bestehende 3-Knoten-Cluster läuft ohne Witness. Während Phase 2 verbleibt der alte Cluster auf 1 Knoten; ohne Witness wäre er sofort quorumlos:
Dies erledigt das SkriptSet-ClusterQuorum -Cluster SQLCL01 -CloudWitness -AccountName <StorAcct> -AccessKey <Key> # oder Set-ClusterQuorum -Cluster SQLCL01 -FileShareWitness '\\fsw01\WitnessSQLCL01$'01-Preflight-Assessment.ps1automatisch (Witness.Old-Sektion inConfig.psd1). - 0.8 AD-Vorbereitung: für den neuen Cluster (
SQLCL01N) ein CNO-Recht auf OU vorbereiten; für den späteren Rename muss der spätere NameSQLCL01ebenfalls freigegeben werden können. Computer-AccountsSQLN01/02/03NICHT löschen – sie werden weiterverwendet. - 0.9 DNS: A-Records für
SQLLST01N(Temp-IP10.10.10.51) undSQLCL01Nregistrieren. TTL fürSQLLST01auf 60 s reduzieren (vorbereitend für Listener-Rückkehr in Phase 5). - 0.10 Firewall: Ports 1433 (SQL), 5022 (AG-Endpoint), 3343/3389 (Cluster), 445/SMB (Witness), 135+dyn. RPC, 443 (Cloud-Witness).
- 0.11 VMware-Inventar exportieren: pro VM aktuelle vHW-Version, vCPU, RAM, Datastore-Pfad, Disk-VMDKs, NIC-Portgroups, DRS-Affinity, Tags. Datei dient als Rollback-Referenz für Skript
03-Reimage-VMShell.ps1. - 0.12 Cold-Clone aller drei VMs EMPFOHLEN – als zusätzlicher Rollback-Anker (zusätzlich zu den detached VMDKs). Die geklonten VMs bleiben heruntergefahren in einem separaten vCenter-Folder.
- 0.13 Kommunikation: Wartungsfenster, RACI, Go/No-Go-Kriterien definieren.
- 0.14 Stage-Probe: Migration in identischer Topologie durchspielen – insbesondere Phase 2 (SPOF) und Phase 3 (DB-Upgrade) zeitlich messen.
- Detached OS- und Daten-VMDKs (im Datastore, nicht gelöscht).
- Cold-Clone der kompletten VM (separater Folder).
- Backups der DBs (FULL+LOG, restore-getestet).
7. Phase 1 – Re-Image SQLN03 + neuer Cluster & AG T−7 Tage
SQLN03 ist die zweite Sekundär-Replica der alten AG (AG_PROD) – Eviction hat minimalen Einfluss (Primary bleibt SQLN01, Sec1 bleibt SQLN02 + Witness). Ablauf vollständig automatisierbar über die Skripte 02–07 aus C:\Cluster\Automation\.
- 1.1 Eviction: SQLN03 aus AG-Replica entfernen, aus altem Cluster evictieren, AD-Computer-Account-Passwort zurücksetzen.
Das Skript prüft, dass SQLN03 nicht Primary ist, entfernt die Replica idempotent, ruft.\02-Evict-Node.ps1 -NodeName SQLN03Remove-ClusterNode + Clear-ClusterNodeund resettet viaSet-ADAccountPassword -Reset. - 1.2 VM-Re-Image: VM herunterfahren, Disk-Inventar exportieren, alle vorhandenen VMDKs detachen (nicht löschen), neue OS- und Daten-Disks (PVSCSI je Controller) anlegen, ISO mounten, Boot von CD-ROM.
vCenter-VM-Objekt (UUID, MAC, Folder, Tags, Permissions) bleibt erhalten – kein Neuanlegen..\03-Reimage-VMShell.ps1 -NodeName SQLN03 - 1.3 Windows-Setup: Windows Server 2025 unattended installiert (
autounattend.xmlsetzt HostnameSQLN03, Domain-Join, IP). Beim Domain-Join übernimmt der frische Server den bestehenden AD-Computer-Account (Passwort wurde in 1.1 zurückgesetzt). - 1.4 OS-Konfiguration:
Features (.\04-Configure-Windows.ps1 -NodeName SQLN03Failover-Clustering,RSAT-Clustering-PowerShell), Firewall-Regeln, Power-Plan „High Performance“, Datendisks formatieren (NTFS 64K, Mountpoints), aktuelles CU. - 1.5 SQL 2025 installieren:
Unattended-Install (gleicher Service-Account, gleiches Daten-Layout, identische Collation), CU einspielen,.\05-Install-SQL.ps1 -NodeName SQLN03Enable-DbaAgHadr. - 1.6 Neuen WSFC erstellen (Single-Node):
Erstellt Cluster.\06-Build-NewCluster.ps1 -NodeName SQLN03 -CreateNewClusterSQLCL01Nauf10.10.10.49, setzt Witness (Cloud oder File-Share ausWitness.New). - 1.7 AG + Listener + DAG aufbauen:
Legt.\07-Create-AG-DAG.ps1 -NodeName SQLN03 -CreateNewAGAG_PROD_NEWals Single-Replica an, ListenerSQLLST01Nauf10.10.10.51, danachCREATE AVAILABILITY GROUP DAG_MIGRATION WITH (DISTRIBUTED)+ JOIN von der alten Seite – Automatic Seeding startet.
8. Phase 2 – Re-Image SQLN02 (SPOF-Phase) T−3 Tage
Safety.AcceptPhase2SPOFRisk = $true.
- 2.1 Frische Backup-Verifikation direkt vor Eviction:
Backup-DbaDatabase -SqlInstance SQLLST01 -Database * -Type Full -CompressBackup Test-DbaLastBackup -SqlInstance SQLLST01 -Database * - 2.2 SPOF-Gate setzen: in
Config.psd1Safety.AcceptPhase2SPOFRisk = $true. - 2.3 Re-Image-Sequenz für SQLN02:
.\02-Evict-Node.ps1 -NodeName SQLN02 .\03-Reimage-VMShell.ps1 -NodeName SQLN02 .\04-Configure-Windows.ps1 -NodeName SQLN02 .\05-Install-SQL.ps1 -NodeName SQLN02 .\06-Build-NewCluster.ps1 -NodeName SQLN02 .\07-Create-AG-DAG.ps1 -NodeName SQLN02 - 2.4 Server-Scope-Objekte migrieren (einmalig nach SQLN03 + SQLN02):
.\08-Migrate-Logins-Jobs.ps1Copy-DbaLogin,Copy-DbaAgentJob,Copy-DbaLinkedServer,Copy-DbaCredential,Copy-DbaDbMail,Copy-DbaServerAuditsowie TDE-Zertifikat-Backup/Restore (mit Vault-Passwort). - 2.5 DAG-Sync überwachen bis Queue-Drain:
.\09-Monitor-Sync.ps1 # poll log_send_queue_size + redo_queue_size
9. Phase 3 – Cutover & Failover Wartungsfenster
AG_PROD_NEW durchlaufen die Datenbanken ein internes Upgrade auf das SQL-2025-Format. Ein Failback auf SQL 2017 ist danach nicht mehr möglich – nur noch Restore aus Backup. Skript verlangt Safety.AcceptNoRollbackAfterCutover = $true zusätzlich zu AllowProduction = $true.
- 3.1 Apps stoppen oder in Read-Only (App-seitig oder via Firewall-Block).
- 3.2 Sync-Status prüfen – Queues = 0:
.\09-Monitor-Sync.ps1 # SELECT * FROM sys.dm_hadr_database_replica_states; - 3.3 Cutover ausführen:
Setzt DAG auf.\10-Cutover.ps1SYNCHRONOUS_COMMIT, wartet auf „Synchronized“, führt geplantes Failover aufAG_PROD_NEWaus, wartet auf Abschluss des DB-Upgrades. - 3.4 Smoke-Tests: Login, Schreib-/Leseoperation, Linked-Server-Aufrufe, kritische Reports.
- 3.5 Compatibility Level nach erfolgreichem Test schrittweise anheben (Query Store / Baseline vorher sichern):
ALTER DATABASE [DBName] SET COMPATIBILITY_LEVEL = 170; - 3.6 Statistiken erneuern + Index-Wartungspläne prüfen:
EXEC sp_updatestats; - 3.7 Apps wieder freischalten – Connection-String unverändert (Listener
SQLLST01Nantwortet, Apps erreichen die neuen Knoten). Der Rückkehr-Rename des Listeners aufSQLLST01erfolgt in Phase 5 ohne Connection-String-Änderung.
10. Phase 4 – Re-Image SQLN01 & Decommission Alt T+0 … T+3
SQLN01 ist nach Cutover noch der Ex-Primary des alten Clusters und hält die alte AG AG_PROD alleine. Mit der Eviction von SQLN01 zerfällt der alte Cluster vollständig.
- 4.1 Hypercare (1–3 Tage): Monitoring, Wait-Stats, Query-Store-Regressions-Analyse. Der alte Cluster läuft technisch noch und dient als zusätzlicher Sanity-Anker.
- 4.2 Distributed AG sauber abbauen (auf alter und neuer Seite):
ALTER AVAILABILITY GROUP [DAG_MIGRATION] REMOVE AVAILABILITY GROUP ON 'AG_PROD_NEW'; DROP AVAILABILITY GROUP [DAG_MIGRATION]; - 4.3 Alte AG droppen:
DROP AVAILABILITY GROUP [AG_PROD]; - 4.4 Re-Image-Sequenz SQLN01 (Ex-Primary):
Mit Eviction von SQLN01 ist der alte Cluster aufgelöst..\02-Evict-Node.ps1 -NodeName SQLN01 -ForcePrimary .\03-Reimage-VMShell.ps1 -NodeName SQLN01 .\04-Configure-Windows.ps1 -NodeName SQLN01 .\05-Install-SQL.ps1 -NodeName SQLN01 .\06-Build-NewCluster.ps1 -NodeName SQLN01 .\07-Create-AG-DAG.ps1 -NodeName SQLN01-ForcePrimaryerlaubt Eviction obwohl SQLN01 noch (alter) Primary ist. - 4.5 Altumgebung manuell bereinigen (Voraussetzung für Phase 5):
- DNS-A-Record
SQLLST01löschen. - AD-CNO
SQLCL01löschen (falls noch vorhanden). - AD-VCO
SQLLST01löschen. - Alte SPNs entfernen:
setspn -D MSSQLSvc/SQLLST01.domain.local:1433 <altSvcAcct>(+ FQDN-Variante). - IP
10.10.10.50in IPAM freigeben. nltest /dsgetdc:domain+ AD-Replikation abwarten.
- DNS-A-Record
- 4.6 Acceptance-Tests Zwischenstand:
Invoke-Pester -Path .\12-Acceptance.Tests.ps1 -Output Detailed
11. Phase 5 – Rename auf Originalnamen T+3 … T+7
Letzter Schritt: Cluster- und Listener-Name zurück auf die Originalwerte. Kein AG-Rename, kein Hostname-Rename. Komplett automatisiert in 11-Rename-Resources.ps1 mit harten Pre-Checks.
- 5.1 Voraussetzungen prüfen (das Skript bricht ab, falls nicht erfüllt):
- Kein DNS-A-Record für
SQLLST01vorhanden. - Kein AD-Computer-Account
SQLCL01und keinSQLLST01vorhanden. - IP
10.10.10.50antwortet nicht (Ping). - Alle 3 Knoten im neuen Cluster online.
- Kein DNS-A-Record für
- 5.2 Rename durchführen:
Reihenfolge: Listener.\11-Rename-Resources.ps1SQLLST01Nentfernen → ListenerSQLLST01mit IP10.10.10.50anlegen → Cluster-RenameSQLCL01N → SQLCL01→ Cluster-Service-Restart auf allen Knoten → SPN-Cleanup + Neu-Setzen → Duplicate-SPN-Check. - 5.3 DNS verifizieren:
Resolve-DnsName SQLLST01.domain.local Test-NetConnection -ComputerName SQLLST01 -Port 1433 - 5.4 App-Server DNS-Cache leeren (oder warten bis TTL ablaufen ist):
Invoke-Command -ComputerName $AppServers -ScriptBlock { ipconfig /flushdns } - 5.5 DNS-TTL wieder auf Normalwert (z. B. 3600 s).
- 5.6 Acceptance-Tests final:
Invoke-Pester -Path .\12-Acceptance.Tests.ps1 -Output Detailed - 5.7 Dokumentation: Architekturdiagramm, Runbook, Failover-Test-Protokoll, Quorum-Konfiguration, finale Namens-Matrix aktualisieren.
- 5.8 DR-Test innerhalb der ersten 30 Tage: Knotenausfall simulieren, Failover-Zeiten messen, Witness-Verlust simulieren.
12. Automatisierung PowerShell · dbatools · PowerCLI · Pester
Praktisch jeder manuelle Schritt der Phasen 0–5 lässt sich skripten. Ein vollständiges Skript-Set liegt unter C:\Cluster\Automation\ bei (siehe README.txt). Die Skripte sind idempotent, durch Pester-Tests validierbar und beziehen alle Parameter aus einer einzigen zentralen Datei – Config.psd1. Secrets bleiben in einem Vault und werden nur zur Laufzeit als SecureString in den Speicher geladen.
Safety.AllowProduction = $true— aktiviert Cutover- und Rename-Skripte.Safety.AcceptPhase2SPOFRisk = $true— entsperrt Phase 2 (Alt-Cluster verbleibt 1 Knoten + Witness).Safety.AcceptNoRollbackAfterCutover = $true— entsperrt Phase 3 (DB-Upgrade auf 2025-Format ist nicht reversibel).
$true gesetzt werden und sollten danach wieder zurückgesetzt werden.
11.1 Skript-Inventar (Variante B)
| Phase | Skript | Aufgabe | Aufruf |
|---|---|---|---|
| — | Config.psd1 · 00-LoadConfig.ps1 | Zentrale Konfiguration, Loader + Helper (Get-CfgSecret, Confirm-Step, Start-PhaseTranscript, Assert-ProductionAllowed, Assert-Phase2SPOFAccepted, Assert-CutoverPointOfNoReturn) | dot-source pro Skript |
| 0 | 01-Preflight-Assessment.ps1 | DBCC, Backups, Inventory, + Witness am alten Cluster nachrüsten, + VMware-Inventar exportieren, + Cold-Clone-Hinweis | .\01-Preflight-Assessment.ps1 |
| 1, 2, 4 | 02-Evict-Node.ps1 | AG-Replica entfernen, Cluster-Node evictieren, AD-Account-Passwort RESETTEN (nicht löschen) | -NodeName SQLN03 · in Phase 4 zusätzlich -ForcePrimary |
| 1, 2, 4 | 03-Reimage-VMShell.ps1 | VM herunterfahren, Disks-Inventar exportieren, VMDKs detachen (nicht löschen!), neue OS+Daten-Disks, ISO mounten, Boot-Order CD-ROM-first | -NodeName SQLN03 |
| 1, 2, 4 | 04-Configure-Windows.ps1 | Wartet auf WinRM, Features (Failover-Clustering), Firewall-Regeln, Datendisks formatieren (Mountpoints, 64K) | -NodeName SQLN03 |
| 1, 2, 4 | 05-Install-SQL.ps1 | SQL Server 2025 unattended (gleicher Service-Account, Layout, Collation) + neuestes CU, Enable-DbaAgHadr | -NodeName SQLN03 |
| 1, 2, 4 | 06-Build-NewCluster.ps1 | Erster Knoten: Test-Cluster + New-Cluster (Single-Node) + Witness. Folgende Knoten: Add-ClusterNode | -NodeName SQLN03 -CreateNewCluster |
| 1, 2, 4 | 07-Create-AG-DAG.ps1 | Erster Knoten: New-DbaAvailabilityGroup (Single-Replica) + Add-DbaAgListener (Temp-IP) + CREATE DISTRIBUTED + JOIN. Folgende Knoten: Add-DbaAgReplica | -NodeName SQLN03 -CreateNewAG |
| 2.5 | 08-Migrate-Logins-Jobs.ps1 | einmalig: Logins, Jobs, Linked Servers, Credentials, DbMail, Server-Audits, TDE-Cert | .\08-Migrate-Logins-Jobs.ps1 |
| 2.5, 3 | 09-Monitor-Sync.ps1 | Polling der Send-/Redo-Queue bis Drain | .\09-Monitor-Sync.ps1 |
| 3 | 10-Cutover.ps1 | SYNC-Commit, Sync abwarten, Failover, DB-Upgrade-Wait. Beide Risiko-Gates Pflicht. | .\10-Cutover.ps1 |
| 5 | 11-Rename-Resources.ps1 | Pre-Checks (DNS/AD/IP frei), Listener-Rename (Original-IP), Cluster-Rename, SPN-Cleanup, Duplicate-SPN-Check. Kein AG-Rename, kein Hostname-Rename. | .\11-Rename-Resources.ps1 |
| 0–5 | 12-Acceptance.Tests.ps1 | Pester-5 Tests: Cluster-Name, Knoten-State, Witness, AG-Replica-Anzahl, Queues, Listener, Hostname-Konstanz, Duplicate SPNs | Invoke-Pester -Path .\12-Acceptance.Tests.ps1 -Output Detailed |
02 → 03 → 04 → 05 → 06 → 07. Beim ersten Knoten (SQLN03) zusätzlich die Switches -CreateNewCluster und -CreateNewAG. Reihenfolge der Knoten: SQLN03 → SQLN02 → CUTOVER → SQLN01 → Rename.
11.2 Aufbau der zentralen Config
Config.psd1 ist ein PowerShell-Datafile (Hashtable) – wird per Import-PowerShellDataFile sicher geladen (kein Code-Execute). Der Loader 00-LoadConfig.ps1 prüft Pflichtfelder, weist CHANGE-ME ab, validiert dass Nodes.Order ein Set-Match zu Nodes.All ist und stellt $global:Cfg bereit.
@{
Project = 'WSFC-SQL-Upgrade-2025-InPlace'
Strategy = 'RollingReImage' # Variante B
Nodes = @{
All = @('SQLN01','SQLN02','SQLN03')
Order = @('SQLN03','SQLN02','SQLN01') # Re-Image-Reihenfolge
}
Old = @{ # bisheriger Cluster (wird aufgeloest)
ClusterName = 'SQLCL01'
ListenerName = 'SQLLST01'
ListenerIP = '10.10.10.50'
ListenerSubnetMask = '255.255.255.0'
AGName = 'AG_PROD'
SqlInstance = 'SQLLST01'
}
New = @{ # waehrend Migration und final
ClusterName = 'SQLCL01N' # in Phase 5 -> SQLCL01
ListenerName = 'SQLLST01N' # in Phase 5 -> SQLLST01
ListenerIPTemp = '10.10.10.51'
AGName = 'AG_PROD_NEW' # bleibt!
DAGName = 'DAG_MIGRATION'
SqlInstance = 'SQLLST01N'
}
ReImage = @{
IsoPath = '[ISO] Win2025/Windows2025.iso'
AutounattendIso = '[ISO] custom/autounattend-WSFC.iso'
OsDiskGB = 120
DataDiskGB = 500
LogDiskGB = 200
TempDbDiskGB = 100
DetachOldVmdks = $true # alte Disks BLEIBEN als Backup
CloneAsBackup = $true # zusaetzlich Cold-Clone
CloneFolder = 'Backup-PreMigration'
}
Witness = @{
Old = @{ Type = 'CloudWitness'; StorageAcct = 'sawsfcsqlcl01'; SecretRef = 'SQL2025_CLOUD_WITNESS_KEY' }
New = @{ Type = 'CloudWitness'; StorageAcct = 'sawsfcsqlcl01n'; SecretRef = 'SQL2025_CLOUD_WITNESS_KEY' }
}
Vmware = @{ VCenterServer = 'vcenter01.domain.local'; ... }
Sql = @{ SetupPath = '\\fs\sw\SQL2025\setup.exe'; ServiceAccount = 'DOMAIN\svc_sql'; ... }
Secrets = @{
Backend = 'SecretManagement'
VaultName = 'WSFC-Migration-Vault'
Refs = @{
SaPassword = 'SQL2025_SA_PWD'
CertEncryption = 'SQL2025_CERT_ENCRYPTION_PWD'
...
}
}
Safety = @{
RequireConfirmation = $true
AllowProduction = $false # Cutover + Rename
AcceptPhase2SPOFRisk = $false # Phase 2
AcceptNoRollbackAfterCutover= $false # Cutover
}
}
11.3 Beispiel: Pro-Knoten-Sequenz für SQLN03
# Erster Knoten (SQLN03) - baut auch Cluster + AG + DAG auf
.\02-Evict-Node.ps1 -NodeName SQLN03
.\03-Reimage-VMShell.ps1 -NodeName SQLN03
.\04-Configure-Windows.ps1 -NodeName SQLN03
.\05-Install-SQL.ps1 -NodeName SQLN03
.\06-Build-NewCluster.ps1 -NodeName SQLN03 -CreateNewCluster
.\07-Create-AG-DAG.ps1 -NodeName SQLN03 -CreateNewAG
# Zweiter Knoten (SQLN02) - SPOF-Phase
# Voraus: Safety.AcceptPhase2SPOFRisk = $true
.\02-Evict-Node.ps1 -NodeName SQLN02
.\03-Reimage-VMShell.ps1 -NodeName SQLN02
.\04-Configure-Windows.ps1 -NodeName SQLN02
.\05-Install-SQL.ps1 -NodeName SQLN02
.\06-Build-NewCluster.ps1 -NodeName SQLN02
.\07-Create-AG-DAG.ps1 -NodeName SQLN02
# Server-Scope migrieren + Sync abwarten
.\08-Migrate-Logins-Jobs.ps1
.\09-Monitor-Sync.ps1
# Cutover (Wartungsfenster)
# Voraus: AllowProduction = $true, AcceptNoRollbackAfterCutover = $true
.\10-Cutover.ps1
# Letzter Knoten (SQLN01, Ex-Primary)
.\02-Evict-Node.ps1 -NodeName SQLN01 -ForcePrimary
.\03-Reimage-VMShell.ps1 -NodeName SQLN01
.\04-Configure-Windows.ps1 -NodeName SQLN01
.\05-Install-SQL.ps1 -NodeName SQLN01
.\06-Build-NewCluster.ps1 -NodeName SQLN01
.\07-Create-AG-DAG.ps1 -NodeName SQLN01
# Phase 5: Rename + Tests
.\11-Rename-Resources.ps1
Invoke-Pester -Path .\12-Acceptance.Tests.ps1 -Output Detailed
11.4 Beispiel: VM-Re-Image mit PowerCLI (Auszug aus 03-Reimage-VMShell.ps1)
$vm = Get-VM -Name $NodeName
Stop-VMGuest -VM $vm -Confirm:$false
do { Start-Sleep 5; $vm = Get-VM $NodeName } until ($vm.PowerState -eq 'PoweredOff')
# Disk-Inventar als Rollback-Referenz exportieren
Get-HardDisk -VM $vm | Select Name,CapacityGB,Filename |
Export-Csv "$($Cfg.Paths.Reports)\Disks-$NodeName.csv" -NoTypeInformation
# VMDKs DETACHEN - bleiben im Datastore
Get-HardDisk -VM $vm | Remove-HardDisk -DeletePermanently:$false -Confirm:$false
# Neue OS-Disk + Daten-Disks
$os = New-HardDisk -VM $vm -CapacityGB $Cfg.ReImage.OsDiskGB -StorageFormat EagerZeroedThick
New-ScsiController -HardDisk $os -Type ParaVirtual -Confirm:$false
foreach ($d in 'Data','Log','TempDb') {
$hd = New-HardDisk -VM $vm -CapacityGB ($Cfg.ReImage."${d}DiskGB") -StorageFormat EagerZeroedThick
New-ScsiController -HardDisk $hd -Type ParaVirtual -Confirm:$false
}
# ISO mounten + Boot von CD-ROM
New-CDDrive -VM $vm -IsoPath $Cfg.ReImage.IsoPath -StartConnected:$true
$vm.ExtensionData.SetBootOptions((New-Object VMware.Vim.VirtualMachineBootOptions -Property @{
BootOrder = @((New-Object VMware.Vim.VirtualMachineBootOptionsBootableCdromDevice))
}))
Start-VM -VM $vm
11.5 Beispiel: AD-Account-Passwort-Reset (Auszug aus 02-Evict-Node.ps1)
# KEIN Remove-ADComputer - sonst gehen Gruppen/ACLs/SPNs verloren
$pwd = [System.Web.Security.Membership]::GeneratePassword(40, 8)
$sec = ConvertTo-SecureString $pwd -AsPlainText -Force
Set-ADAccountPassword -Identity $NodeName -Reset -NewPassword $sec
# Frisches OS uebernimmt beim Domain-Join den vorhandenen Account.
11.6 Beispiel: Cutover mit zwei Asserts (Auszug aus 10-Cutover.ps1)
. (Join-Path $PSScriptRoot '00-LoadConfig.ps1')
Assert-ProductionAllowed
Assert-CutoverPointOfNoReturn
# Sync abwarten
do {
$q = (Invoke-DbaQuery -SqlInstance $Cfg.New.SqlInstance -Query `
'SELECT SUM(log_send_queue_size) Q FROM sys.dm_hadr_database_replica_states').Q
Start-Sleep 5
} while ($q -gt 0)
# SYNC + Failover
Invoke-DbaQuery -SqlInstance $Cfg.Old.SqlInstance -Query @"
ALTER AVAILABILITY GROUP [$($Cfg.New.DAGName)]
MODIFY AVAILABILITY GROUP ON '$($Cfg.New.AGName)' WITH (AVAILABILITY_MODE = SYNCHRONOUS_COMMIT);
"@
Invoke-DbaQuery -SqlInstance $Cfg.New.SqlInstance -Query `
"ALTER AVAILABILITY GROUP [$($Cfg.New.DAGName)] FAILOVER;"
11.7 Beispiel: Acceptance-Tests (Pester 5)
BeforeAll { . (Join-Path $PSScriptRoot '00-LoadConfig.ps1') }
Describe 'Phase 5 - Final State' {
It 'Cluster traegt Originalnamen' { (Get-Cluster).Name | Should -Be $Cfg.Old.ClusterName }
It 'AG-Name ist AG_PROD_NEW (bewusst nicht umbenannt)' {
Get-DbaAvailabilityGroup -SqlInstance $Cfg.Old.ListenerName `
-AvailabilityGroup $Cfg.New.AGName | Should -Not -BeNullOrEmpty
}
It 'Listener antwortet auf 1433' {
(Test-NetConnection $Cfg.Old.ListenerName -Port 1433).TcpTestSucceeded | Should -BeTrue
}
It 'Keine Duplicate SPNs' { (setspn -X 2>&1 | Out-String) | Should -Not -Match 'found \d+ group' }
It 'Hostnames unveraendert (Re-Use VM-Huellen)' {
foreach ($n in $Cfg.Nodes.All) {
(Invoke-Command -ComputerName $n { $env:COMPUTERNAME }) | Should -Be $n
}
}
}
11.8 Orchestrierung end-to-end
- Azure DevOps Pipeline oder Ansible-Playbook mit einer Stage pro Phase – jede Stage ruft das passende Skript auf und schließt mit dem zugehörigen Pester-Test ab. Failed Test ⇒ Pipeline-Stop.
- Transcript-Logging (
Start-PhaseTranscript) – jeder Lauf hinterlässt einen Audit-Trail unterC:\Cluster\Automation\Reports\(in Config konfigurierbar). - Secrets über
SecretManagement-Modul (Azure Key Vault / CyberArk / lokaler SecretStore).
Config.psd1 vollständig befüllen (alle CHANGE-ME ersetzen), Secrets im Vault hinterlegen, in einer Stage-Umgebung end-to-end testen, dabei Safety.RequireConfirmation = $true und Pester konsequent nutzen. Cutover/Rename erfordern zusätzlich die Risiko-Gates.
13. Häufige Fehlerquellen & Gegenmaßnahmen
| Risiko / Fehler | Ursache | Gegenmaßnahme |
|---|---|---|
| Quorum-Verlust während Migration | Kein Witness, mehrere Knoten gleichzeitig in Wartung | Witness vor dem Upgrade einrichten; nie mehr als einen Knoten gleichzeitig drainen. |
| AG-Listener nicht erreichbar nach Cutover | DNS-Cache, falsche Cluster-IP, fehlender SPN | DNS-TTL niedrig setzen; setspn -L prüfen; ipconfig /flushdns auf App-Servern. |
| Distributed AG „Not Synchronizing“ | Endpoint-Port 5022 blockiert, Service-Account ohne CONNECT-Recht, Zertifikatsfehler | Firewall + GRANT CONNECT ON ENDPOINT::Hadr_endpoint TO [Login] prüfen; Endpoint-Authentifizierung (Windows vs. Zertifikat) konsistent. |
| TDE-Datenbank lässt sich auf neuem Replica nicht öffnen | TDE-Zertifikat aus master wurde nicht importiert |
Vor Seeding: Server-Cert & Private Key per BACKUP CERTIFICATE exportieren und auf jedem neuen Knoten installieren. |
| Performance-Regression nach Compat-Level-Hub | Neuer Cardinality Estimator | Query Store nutzen; bei Regression: USE HINT('FORCE_LEGACY_CARDINALITY_ESTIMATION') oder Compat-Level zurücksetzen, gezielte Plan-Force. |
| Cluster Validation Warnungen ignoriert | Treiber, Firmware, Netzwerk-Inkonsistenzen | Alle Warnungen adressieren – andernfalls verlustig Microsoft-Support. |
| SQL VMs auf demselben ESXi-Host (Single Point of Failure) | Fehlende DRS-Regel | VM-VM Anti-Affinity „Separate Virtual Machines“ für alle Replicas. |
| Memory Ballooning unter Last | Keine Memory-Reservation | Vollständige Memory-Reservation, ggf. „Lock pages in memory“ für SQL-Service-Account. |
| Mixed-Version-AG-Fenster zu lang | Projektverzögerung | Microsoft begrenzt das Fenster informell auf wenige Tage/Wochen – Cutover terminlich fest einplanen. |
| Setup-Blocker: „Pending reboot“ | Offene Windows-Updates | Vor Setup: Neustart, shutdown /r /t 0, PendingFileRenameOperations-Registry prüfen. |
| Duplicate SPN nach Listener-Rename | Alte SPNs am Vorgänger-Account nicht entfernt | setspn -X ausführen; alte SPNs explizit per setspn -D entfernen, dann erst neue setzen. |
| Cluster-Rename schlägt fehl („Computer object exists“) | Altes CNO noch in AD vorhanden | Altes CNO in AD löschen oder umbenennen, AD-Replikation abwarten, dann (Get-Cluster).Name = .... |
| Listener-Ressource bleibt offline nach Rename | VCO in AD existiert noch / Rechte fehlen | VCO entfernen oder Cluster-CNO „Create Computer Objects“-Recht auf OU geben. |
@@SERVERNAME ungleich Hostname nach Rename |
sp_dropserver/sp_addserver vergessen |
Sofort durchführen, SQL-Dienst neu starten; Replikation/Linked-Server prüfen. |
| App-Server verbinden nach Listener-Switch nicht | DNS-Cache, Connection-Pool, langer TTL | TTL vorab niedrig; nach Switch ipconfig /flushdns, App-Pool / Service-Restart. |
| SQL Agent Jobs liefern keine Mails | Database Mail Profile / Operatoren nicht migriert | In Phase 0.6 explizit sichern, in Phase 1.10 wiederherstellen, Testmail nach Cutover. |
| VMware Snapshots während Migration | I/O-Latenz, Konsistenzrisiken | Snapshots nicht als Backup nutzen; vor/nach Setup max. kurze Snapshots, danach konsolidieren. |
| Domain-Join scheitert nach Re-Image (Variante B) | AD-Computer-Account-Passwort nicht resettet, oder Re-Image mit altem Passwort versucht zu joinen | 02-Evict-Node.ps1 setzt vor Re-Image Set-ADAccountPassword -Reset. Bei manuellem Vorgehen: vor Domain-Join Passwort resetten und beim Join „Account already exists, use existing“ wählen. |
| Alt-Cluster verliert Quorum in Phase 2 | Witness fehlt — 1 Knoten + kein Witness = 1 Vote, Quorum-Verlust beim kleinsten Glitch | Phase-0-Schritt 0.7 verpflichtend (01-Preflight-Assessment.ps1 richtet Witness ein). Vor Phase 2 prüfen: Get-ClusterQuorum -Cluster SQLCL01. |
| Alte VMDKs nach Re-Image fälschlich gelöscht | Remove-HardDisk -DeletePermanently:$true verwendet |
03-Reimage-VMShell.ps1 setzt -DeletePermanently:$false. Bei manuellem Eingriff explizit verifizieren — sonst Rollback-Anker zerstört. |
| Phase 5 Rename bricht ab | Alte AD-Objekte, DNS-Eintrag oder IP noch in Verwendung | Schritt 4.5 vollständig abarbeiten. 11-Rename-Resources.ps1 bricht mit klarer Fehlermeldung ab und nennt das blockierende Objekt. |
14. Rollback-Strategie
Strategie B kennt mehrere Rollback-Ebenen, deren Wirksamkeit von der jeweiligen Phase abhängt:
Rollback-Anker (mit abnehmender Wirksamkeit)
- Detached VMDKs pro Knoten — vor jedem Re-Image (Phase 1, 2, 4) werden die alten OS- und Daten-VMDKs detached, nicht gelöscht. Sie bleiben im Datastore und können in vCenter wieder angehängt werden. Einschränkung: nach Re-Image ist die Vertrauensstellung zur Domäne gebrochen (Computer-Account-Passwort wurde resettet) – manuelle Re-Authentifizierung des AD-Accounts mit dem alten Passwort ist nicht möglich. Vollständiger Rollback nur durch Restore eines AD-Account-Backups oder durch Re-Join der alten Disks mit neuer Domain-Mitgliedschaft.
- Cold-Clone der kompletten VMs aus Phase 0 — im Datastore-Folder
Backup-PreMigration. Power-On möglich (anderer Name nötig, um Konflikt zu vermeiden). Schnellster Weg zu einer funktionsfähigen Alt-Replica vor Cutover. - DB-Backups (FULL + LOG) auf File-Share — einziger Rollback-Pfad nach Cutover.
Wirksamkeit je Phase
- Phasen 1–2 (vor Cutover): Re-Image rückgängig durch Re-Attach VMDKs + AD-Account-Wiederherstellung oder Cold-Clone-Power-On. Alter Cluster läuft auf den verbliebenen Knoten weiter und kann den Re-Imaged-Knoten als „echten“ Knoten wieder aufnehmen.
- Phase 3 (Cutover – Point of no Return): Bis zum Failover-Commit (
10-Cutover.ps1, vorALTER ... FAILOVER) kann die Distributed AG abgebrochen werden – Apps blieben aufSQLLST01(alt) verbunden, Datenverlust = 0. Nach erfolgreichem Failover beginnt das interne DB-Upgrade auf SQL-2025-Format. Failback auf 2017 ist nicht mehr per AG/DAG möglich. - Phase 4–5 (nach Cutover): Einziger Rollback – Restore der vor-Cutover-Backups auf eine separat aufgebaute SQL-2017-Instanz und Re-Routing der Apps. Realistische Wiederanlaufzeit: viele Stunden. Daher das Gate
AcceptNoRollbackAfterCutover.
15. Go-Live-Checkliste
| # | Prüfpunkt | Status |
|---|---|---|
| 1 | Aktuelle Full + Log Backups aller AG-DBs vorhanden & restore-getestet | ☐ |
| 2 | DBCC CHECKDB ohne Fehler auf allen AG-DBs | ☐ |
| 3 | Witness auf altem Cluster eingerichtet (Cloud oder File Share) — Pflicht für Phase 2 | ☐ |
| 4 | Witness auf neuem Cluster konfiguriert und „Online“ | ☐ |
| 5 | Cluster Validation Report für neuen Cluster ohne Errors | ☐ |
| 6 | SQL Server 2025 + neuestes CU auf allen re-imaged Knoten | ☐ |
| 7 | Logins / Jobs / Linked Servers / TDE-Zertifikate migriert | ☐ |
| 8 | Distributed AG „Synchronized“, Queues = 0 | ☐ |
| 9 | DRS Anti-Affinity-Regel für Replica-VMs aktiv | ☐ |
| 10 | Memory-Reservation = konfigurierter RAM auf allen SQL-VMs | ☐ |
| 11 | Firewall-Ports 1433 / 5022 / 3343 / 445 / 443 verifiziert | ☐ |
| 12 | Applikations-Connection-Strings unverändert lassen (Listener-Name bleibt) | ☐ |
| 13 | Backup-/Monitoring-Konfiguration für neuen Cluster bestätigt | ☐ |
| 14 | Rollback-Anker pro Knoten dokumentiert (Detached VMDKs + Cold-Clone) | ☐ |
| 15 | Wartungsfenster & Kommunikation an Stakeholder versendet | ☐ |
| 16 | Namens-Matrix dokumentiert & freigegeben (Hostnames konstant!) | ☐ |
| 17 | DNS-TTL für Listener auf 60 s gesenkt (vorbereitend für Phase 5) | ☐ |
| 18 | Risiko-Gates: AllowProduction, AcceptPhase2SPOFRisk, AcceptNoRollbackAfterCutover formell genehmigt | ☐ |
| 19 | Alte AD-Objekte SQLCL01 & SQLLST01 (VCO/CNO) und DNS-Eintrag SQLLST01 vor Phase 5 bereinigt | ☐ |
| 20 | IP 10.10.10.50 in IPAM frei vor Phase 5 | ☐ |
| 21 | Cluster- (SQLCL01N → SQLCL01) und Listener-Rename (SQLLST01N → SQLLST01) abgeschlossen | ☐ |
| 22 | SPNs verifiziert, keine Duplicate SPNs (setspn -X) | ☐ |
| 23 | Pester-Acceptance-Tests (12-Acceptance.Tests.ps1) bestanden | ☐ |
| 24 | Detached VMDKs & Cold-Clones für 30-Tage-Hypercare aufbewahrt | ☐ |
16. Qualifizierte Quellen
- Microsoft Learn – Upgrading Always On Availability Group Replica Instances:
learn.microsoft.com/.../upgrading-always-on-availability-group-replica-instances - Microsoft Learn – Supported version and edition upgrades (SQL Server 2025):
learn.microsoft.com/.../supported-version-and-edition-upgrades-2025 - Microsoft Learn – Hardware and software requirements for SQL Server 2025:
learn.microsoft.com/.../hardware-and-software-requirements-for-installing-sql-server-2025 - Microsoft Learn – Cluster Operating System Rolling Upgrade:
learn.microsoft.com/.../cluster-operating-system-rolling-upgrade - Microsoft Learn – Manage Cluster Quorum (Witness Types):
learn.microsoft.com/.../manage-cluster-quorum - Microsoft Learn – Distributed Availability Groups:
learn.microsoft.com/.../distributed-availability-groups - Microsoft Learn – Automatic Seeding for Always On Availability Groups:
learn.microsoft.com/.../automatically-initialize-always-on-availability-group - Microsoft Learn – Plan and test the Database Engine upgrade plan:
learn.microsoft.com/.../plan-and-test-the-database-engine-upgrade-plan - VMware – Architecting Microsoft SQL Server on VMware vSphere – Best Practices Guide (Broadcom/VMware Core Tech Zone)
- VMware – Setup for Failover Clustering and Microsoft Cluster Service (vSphere-Dokumentation, jeweils zur eingesetzten ESXi-Version)
Alle Microsoft-Links verweisen auf die offizielle Dokumentation learn.microsoft.com. Stand der Recherche: 2026-05-18.