SQL Server データベース ファイルが複数のディスクに分散している場合は、アプリケーションとデータの整合性を維持しながら、すべてのディスクを同時にバックアップできます。Compute Engine のインスタント スナップショットの整合性グループを使用すると、ディスク グループ全体でデータをバックアップできるため、この正確なポイントインタイム バックアップ を実現できます。
このチュートリアルでは、Compute Engine スナップショットと、SQL Server 2022 以降で使用できる Transact-SQL(T-SQL)スナップショット機能を使用して SQL Server データベースをバックアップする方法について説明します。 このソリューションは、Windows と Linux の両方のデプロイをサポートし、本番環境のワークロードへのパフォーマンスの影響を最小限に抑えます。
仕組み
ワークフローは、コンピューティング インスタンスで実行されるスクリプトによって管理される次の主なステップで構成されます。
- データベースをフリーズする: スクリプトは、ターゲット データベースのすべての書き込みオペレーションを 一時停止する T-SQL コマンドを SQL Server に送信します。これにより、データベース ファイルがバックアップ用に一貫した状態になります。
- インスタント スナップショットを作成する: データベースがフリーズしている間に、データベースのデータファイルとログファイルが保存されている ディスクのインスタント スナップショットのグループを作成します。これは、ハードウェアまたはサービスレベルのスナップショット メカニズムを使用するのと同じです。 Google Cloud
- 記録して解凍する: スクリプトは、
バックアップ メタデータを記録する別の T-SQL コマンドを SQL Server に送信します。このコマンドは、インスタント スナップショットの整合性
グループを指す小さなバックアップ ファイルを作成し、
msdbバックアップ履歴に記録します。完了すると、 SQL Server はデータベースを自動的に解凍し、通常のオペレーションを再開します。
通常、このプロセス全体は 1 秒以内に完了するため、データベースの書き込みフリーズの期間を最小限に抑えることができます。フリーズ中は、データの読み取りはできますが、書き込みはできません。データベースの SUSPEND_FOR_SNAPSHOT_BACKUP=OFF を設定すると、フリーズ状態を手動でキャンセルできます。
目標
このチュートリアルでは、次のタスクを完了する方法について説明します。- 2 つのデータディスクを使用して SQL Server インスタンスを作成します。
- データファイルとログファイルが別々のディスクにある新しいデータベースを作成します。
- SQL Server を実行している VM のすべてのディスクの整合性グループを作成します。
- ディスク グループのインスタント スナップショットを作成します。
- インスタント スナップショットから新しいディスクを作成します。
費用
このドキュメントでは、課金対象である次のコンポーネントを使用します。 Google Cloud
料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。
このドキュメントに記載されているタスクの完了後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。
始める前に
このチュートリアルでは Google Cloud プロジェクトが必要です。新しいプロジェクトを作成するか、既存のプロジェクトを選択します。
-
コンソールのプロジェクト セレクタページで、プロジェクトを選択または作成します。 Google Cloud Google Cloud
プロジェクトを選択または作成するために必要なロール
- プロジェクトを選択する: プロジェクトの選択には特定の IAM ロールは必要ありません。ロールが付与されているプロジェクトを選択できます。
-
プロジェクトを作成する: プロジェクトを作成するには、プロジェクト作成者ロール
(
roles/resourcemanager.projectCreator)が必要です。これにはresourcemanager.projects.create権限が含まれています。詳しくは、ロールを付与する方法をご覧ください。
-
コンソールで Cloud Shell をアクティブにします。 Google Cloud
-
Microsoft SQL Server 2022 以降がインストールされ、実行されていることを確認します。
必要な権限
標準の読み取りアクセス権に加えて、SQL Server 管理者がターゲット データベースに対する ALTER DATABASE 権限を付与していることを確認してください。
インスタンスを作成してスナップショットを作成するために必要な権限を取得するには、プロジェクトに関する次の IAM ロールを付与するよう管理者に依頼してください。
-
インスタンスの管理:
compute.instanceAdmin.v1 -
スナップショットの作成:
compute.storageAdmin
ロールの付与については、プロジェクト、フォルダ、組織へのアクセス権の管理をご覧ください。
Compute Engine SQL インスタンスを作成する
SQL Server インスタンスを作成します。
Google Cloud コンソールで、[Cloud Shell をアクティブにする]
ボタンをクリックして Cloud Shell を開きます。
SQL Server インスタンスを作成します。次のコマンドを貼り付けます。
REGION=REGIONZONE=$REGION-a VM_NAME=VM_NAMEgcloud compute instances create $VM_NAME \ --boot-disk-auto-delete \ --boot-disk-size 100 \ --boot-disk-type hyperdisk-balanced \ --image-family sql-std-2022-win-2025 \ --image-project windows-sql-cloud \ --machine-type c4-highmem-4 \ --zone $ZONE \ --network-interface subnet=default \ --tags sql-server-instant-snapshot \ --scopes=cloud-platform,service-control,service-management,monitoring-write,logging-write,storage-rw \ --create-disk=device-name=$VM_NAME-data-disk1,mode=rw,name=$VM_NAME-data-disk1,size=100,type=hyperdisk-balanced \ --create-disk=device-name=$VM_NAME-data-disk2,mode=rw,name=$VM_NAME-data-disk2,size=100,type=hyperdisk-balanced
次のように置き換えます。
- リージョン: 新しいインスタンスがデプロイされるリージョン。
- VM_NAME: 新しい SQL Server インスタンスの名前。
ディスクの整合性グループを作成する
整合性グループを作成します。
gcloud compute resource-policies create disk-consistency-group $VM_NAME-snap-grp \ --region=$REGIONVM のディスクを整合性グループに追加します。
gcloud compute disks add-resource-policies $VM_NAME \ --zone=$ZONE \ --resource-policies=$VM_NAME-snap-grp gcloud compute disks add-resource-policies $VM_NAME-data-disk1 \ --zone=$ZONE \ --resource-policies=$VM_NAME-snap-grp gcloud compute disks add-resource-policies $VM_NAME-data-disk2 \ --zone=$ZONE \ --resource-policies=$VM_NAME-snap-grp
新しいデータベースを作成する
- VM インスタンスに ユーザー名とパスワードを作成します。
- リモート デスクトップを使用して VM に接続し 前のステップで作成したユーザー名とパスワードを使用してログインします。
- [スタート] ボタンを右クリックするか Win+X を押して、[ターミナル(管理者)] をクリックします。
- 特権昇格を確認するプロンプトが表示されたら [はい] をクリックします。
開いたターミナル ウィンドウで次の PowerShell スクリプトを実行します。このスクリプトは、データディスクを初期化し、64 KB のブロックサイズでディスクをフォーマットして、ドライブ文字を割り当てます。
$availableDisks = Get-PhysicalDisk -CanPool $True $diskLetters = [char[]] (68..72) | Where-Object { !(Get-PSDrive $_ -ErrorAction SilentlyContinue) } $diskCount = 0 foreach ($disk in $availableDisks) { $diskLetter = $diskLetters[$diskCount] $diskLabel = "$diskLetter-DataDisk" Initialize-Disk -Number $disk.DeviceId -PartitionStyle MBR -PassThru New-Partition -DiskNumber $disk.DeviceId -UseMaximumSize ` -DriveLetter $diskLetter | Format-Volume -FileSystem NTFS ` -NewFileSystemLabel $diskLabel -AllocationUnitSize 65536 -Confirm:$false New-Item -ItemType Directory -Path "$($diskLetter):\MSSQL" $diskCount = $diskCount +1 }SQL Server Management Studio(SSMS)を開きます。管理者として実行します。
[サーバーに接続] ダイアログで、サーバー名が
localhostに設定されていることを確認し、[接続] を選択します。ファイル メニューで、現在の接続で [File] > [New] > [Query] を選択します。
次のコードを新しく開いたクエリ ウィンドウにコピーします。
USE Master; GO CREATE DATABASE SnapBackupDB ON PRIMARY ( NAME = 'SnapBackupDB_Data', FILENAME = 'D:\MSSQL\SnapBackupDB.mdf', SIZE = 500MB, MAXSIZE = UNLIMITED, FILEGROWTH = 64MB ) LOG ON ( NAME = 'SnapBackupDB_Log', FILENAME = 'E:\MSSQL\SnapBackupDB_log.ldf', SIZE = 250MB, MAXSIZE = 2GB, FILEGROWTH = 64MB );
スナップショット スクリプトをデプロイする
このスクリプトは、SQL Server を実行している VM に接続されたディスクのアプリケーション整合性スナップショットを作成するために必要なプロセス全体を自動化します。
- 同じリモート デスクトップ セッションを使用して、メモ帳を開きます。
- 次のスクリプトの内容をコピーして、開いたメモ帳ウィンドウに貼り付けます。
ファイルを
c:\scriptsにtake-snapshot.ps1として保存します。# Import Modules Import-Module -Name SQLPS # Set variables $formattedTimestamp = Get-Date -Format 'yyyyMMdd-HHmmss' $backupLocation = 'D:\MSSQL\Backup' $dbName = 'SnapBackupDB' $bkmFile = Join-Path -Path $backupLocation -ChildPath ("${dbName}_${formattedTimestamp}.bkm") $sqlServer = 'localhost' # SQL Commands $suspendDbCmd = "ALTER DATABASE [$dbName] SET SUSPEND_FOR_SNAPSHOT_BACKUP=ON WITH NO_WAIT;" $backupMetadataCmd = "BACKUP DATABASE [$dbName] TO DISK='$bkmFile' WITH METADATA_ONLY, FORMAT;" $unsuspendDbCmd = "ALTER DATABASE [$dbName] SET SUSPEND_FOR_SNAPSHOT_BACKUP=OFF;" # --- Helper Function for SQL Execution --- function Invoke-MySqlCommand { param( [Parameter(Mandatory=$true)] [string]$CommandText, [Parameter(Mandatory=$true)] [System.Data.SqlClient.SqlConnection]$SqlConnection ) Write-Host "Executing SQL Command: $($CommandText)" try { $Command = New-Object System.Data.SqlClient.SqlCommand($CommandText, $SqlConnection) $Result = $Command.ExecuteNonQuery() return $true } catch { Write-Host "Error executing SQL Command: $($CommandText)`n$($_.Exception.Message)" -ForegroundColor Red return $false } } $sqlConn = New-Object System.Data.SqlClient.SqlConnection $sqlConn.ConnectionString = "server='$sqlServer';database='$dbName';Integrated Security=True;" $databaseSuspended = $false if (-not(Test-Path $backupLocation)) { New-Item -Path $backupLocation -ItemType directory -Force } try { $instanceName = (Invoke-RestMethod -Headers @{"Metadata-Flavor"="Google"} -Uri "http://metadata.google.internal/computeMetadata/v1/instance/name") $vmConfigString = (gcloud compute instances list --filter="name=('$instanceName')" --format=json --quiet) if ($LASTEXITCODE -ne 0) { Write-Host "Error querying gcloud for VM instances (exit code: $LASTEXITCODE). Exiting." -ForegroundColor Red exit 1 } $vmConfig = $vmConfigString | ConvertFrom-Json # Open SQL Server connection $sqlConn.Open() # Suspend Database Write-Host "Suspending database '$dbName' for snapshot..." if (-not (Invoke-MySqlCommand -CommandText $suspendDbCmd -SqlConnection $sqlConn)) { Write-Host "Failed to suspend database. Exiting." -ForegroundColor Red exit 1 } $databaseSuspended = $true # Take a disk snapshot try { $consistencyGroupListStr = (gcloud compute resource-policies list --filter='name:*-snap-grp' --format=json --quiet) if ($LASTEXITCODE -ne 0) { throw "gcloud resource-policies list failed (exit code: $LASTEXITCODE)." } $consistencyGroupList = $consistencyGroupListStr | ConvertFrom-Json if (@($consistencyGroupList).Count -eq 0) { throw "No consistency group found matching '*-snap-grp'." } if (@($consistencyGroupList).Count -gt 1) { Write-Warning "More than one consistency group found, using the first one." } $consistencyGroupSelfLink = $consistencyGroupList[0].selfLink $zoneName = Split-Path $vmConfig[0].zone -Leaf $snapshotName = "$($vmConfig.Name)-${formattedTimestamp}" $snapshotCmd = "gcloud compute instant-snapshot-groups create $snapshotName --source-consistency-group=$consistencyGroupSelfLink --zone=$zoneName --quiet" Invoke-Expression $snapshotCmd if ($LASTEXITCODE -ne 0) { throw "gcloud compute instant-snapshot-groups create failed (exit code: $LASTEXITCODE)." } Write-Host "Instant snapshot group created successfully." } catch { Write-Host "Error during snapshot creation: $($_.Exception.Message)" -ForegroundColor Red exit 1 # Exit after handling in finally } # Backup database metadata if (-not (Invoke-MySqlCommand -CommandText $backupMetadataCmd -SqlConnection $sqlConn)) { Write-Host "Failed to backup database metadata." -ForegroundColor Red exit 1 } # Unsuspend Database Write-Host "Unsuspending database '$dbName'..." if (-not (Invoke-MySqlCommand -CommandText $unsuspendDbCmd -SqlConnection $sqlConn)) { Write-Host "Failed to unsuspend database after successful snapshot and metadata backup. Manual intervention may be required." -ForegroundColor Red exit 1 } $databaseSuspended = $false # Successfully unsuspended } catch { Write-Host "An unhandled error occurred: $($_.Exception.Message)" -ForegroundColor Red exit 1 } finally { if ($databaseSuspended -and ($sqlConn.State -eq [System.Data.ConnectionState]::Open)) { if (-not (Invoke-MySqlCommand -CommandText $unsuspendDbCmd -SqlConnection $sqlConn)) { Write-Host "Failed to unsuspend database in finally block. Manual intervention may be required." -ForegroundColor Red } } # Ensure SQL connection is closed if ($sqlConn.State -eq [System.Data.ConnectionState]::Open) { $sqlConn.Close() } }[スタート] ボタンを右クリックするか Win+X を押して、[ターミナル(管理者)] をクリックします。
特権昇格を確認するプロンプトが表示されたら [はい] をクリックします。
次のコマンドを実行してスクリプトを実行します。
C:\scripts\take-snapshot.ps1
インスタント スナップショットが作成されたことを確認する
Cloud Shell で以下のコマンドを実行します。
スクリプトでスナップショットが作成されたことを確認します。
gcloud compute instant-snapshots list --filter="name:$VM_NAME*"インスタント スナップショット グループを一覧表示します。
gcloud compute instant-snapshot-groups list --zones $ZONEインスタント スナップショット グループの詳細を表示します。
gcloud compute instant-snapshot-groups describe \INSTANT_SNAPSHOT_NAME--zone=$ZONEselfLink値をコピーして、次のセクションで使用します。
インスタント スナップショットを新しいディスクに復元する
コンソール ウィンドウで次のコマンドを実行します。 Google Cloud
インスタント スナップショットの整合性グループからディスクを作成します。
gcloud compute disks bulk create --source-instant-snapshot-group \INSTANT_SNAPSHOT_NAME_URL\ --source-instant-snapshot-group-region $REGION --zone=$ZONEゾーン内のディスクを一覧表示して、スナップショットが復元されたことを確認します。
gcloud compute disks list --zones=$ZONE --filter="name:$VM_NAME-*"新しく作成したディスクから新しい VM を作成します。
REGION=
REGIONZONE=$REGION-a VM_NAME=VM_NAMEgcloud compute instances create $VM_NAME \ --machine-type c4-highmem-4 \ --zone $ZONE \ --network-interface subnet=default \ --tags sql-server-instant-snapshot \ --disk=name=BOOT_DISK_NAME,boot=yes,auto-delete=no \ --disk=name=DATA_DISK_1_NAME,mode=rw,auto-delete=no \ --disk=name=DATA_DISK_2_NAME,mode=rw,auto-delete=no
次のように置き換えます。
- リージョン: 新しいインスタンスがデプロイされるリージョン。
- VM_NAME: 新しい SQL インスタンスの名前。
- BOOT_DISK_NAME: 前のステップで作成したブートディスクの名前。
- DATA_DISK_1_NAME: 前の ステップで作成した最初のデータディスクの名前。
- DATA_DISK_2_NAME: 前のステップ で作成した 2 番目のデータディスクの名前。
これで、ディスクを新しい VM または既存の VM に接続できます。
クリーンアップ
このチュートリアルで使用したリソースについて Google Cloud アカウントに課金されないようにするには、プロジェクトを削除します。
プロジェクトの削除
- コンソールで [**リソースの管理**] ページに移動します。 Google Cloud
- プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
- ダイアログでプロジェクト ID を入力し、 [Shut down] をクリックしてプロジェクトを削除します。
次のステップ
- Google Cloud に関するリファレンス アーキテクチャ、図、ベスト プラクティスを確認する。Cloud アーキテクチャ センターをご覧ください。