演習 - 特定の時点に復元する
この演習では、ポイントインタイム リストア (PITR) を使って、一般的なエラーから回復する方法を学習します。 このプロセスは、ポータルまたはプログラムで簡単に実行できます。 この演習では、Azure CLI を使用してこれを行う方法を学習します。
セットアップ: スクリプトを使用して Azure SQL Database をデプロイする
右側のターミナルには Azure Cloud Shell が表示されます。これは、ブラウザーを使用して Azure と対話する方法です。 演習を開始する前に、AdventureWorks データベースを含む Azure SQL Database 環境を作成するためのスクリプトを実行する必要があります。 そのスクリプトで、パスワードとローカル IP アドレスの入力を求めるいくつかのプロンプトが表示されます。
これらのスクリプトは、完了するまでに 3 から 5 分かかります。 パスワード、一意の ID、およびリージョンは再表示されないため、メモしておいてください。
必要な IP アドレスを取得するには、VPN サービスから切断し、(このブラウザーではなく) ローカルの PowerShell ウィンドウで
(Invoke-WebRequest -Uri "https://ipinfo.io/ip").Content
を実行する必要があります。 結果として得られる IP アドレスを書き留めます。このページの右側にある Azure Cloud Shell で、次のスクリプトを実行して VM を作成します。 プロンプトが表示されたら、複雑なパスワードとパブリック IP アドレスを入力します。
$adminSqlLogin = "cloudadmin" $password = Read-Host "Your username is 'cloudadmin'. Please enter a password for your Azure SQL Database server that meets the password requirements" # Prompt for local IP address $ipAddress = Read-Host "Disconnect your VPN, open PowerShell on your machine and run '(Invoke-WebRequest -Uri "https://ipinfo.io/ip").Content'. Please enter the value (include periods) next to 'Address': " # Get resource group and location and random string $resourceGroup = Get-AzResourceGroup | Where ResourceGroupName -like "<rgn>[sandbox resource group name]</rgn>" $resourceGroupName = "<rgn>[sandbox resource group name]</rgn>" $uniqueID = Get-Random -Minimum 100000 -Maximum 1000000 $storageAccountName = "mslearnsa"+$uniqueID $location = $resourceGroup.Location # The logical server name has to be unique in the system $serverName = "aw-server$($uniqueID)"
Azure Cloud Shell で次のスクリプトを実行して、このモジュール全体で必要な情報を出力し、テキスト ファイルなどを (テキスト ファイルまたは同様の場所に) 保存します。 コードを貼り付けた後、最後の行は既定では実行されないため、おそらく Enter キーを選択する必要があります。
Write-Host "Please note your unique ID for future exercises in this module:" Write-Host $uniqueID Write-Host "Your resource group name is:" Write-Host $resourceGroupName Write-Host "Your resources were deployed in the following region:" Write-Host $location Write-Host "Your server name is:" Write-Host $serverName
重要
忘れずにパスワード、一意の ID、リージョンを書き留めてください。 この情報は、モジュール全体を通して必要になります。
次のスクリプトを実行して、Azure SQL データベースと論理サーバーを AdventureWorks サンプルと共にデプロイします。 このスクリプトによって、IP アドレスがファイアウォール規則として追加され、Microsoft Defender for Cloud が有効になり、今後のユニットで使うストレージ アカウントが作成されます。
# The logical server name has to be unique in the system $serverName = "aw-server$($uniqueID)" # The sample database name $databaseName = "AdventureWorks" # The storage account name has to be unique in the system $storageAccountName = $("sql$($uniqueID)") # Create a new server with a system-wide unique server name $server = New-AzSqlServer -ResourceGroupName $resourceGroupName ` -ServerName $serverName ` -Location $location ` -SqlAdministratorCredentials $(New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $adminSqlLogin, $(ConvertTo-SecureString -String $password -AsPlainText -Force)) # Create a server firewall rule that allows access from the specified IP range and all Azure services $serverFirewallRule = New-AzSqlServerFirewallRule ` -ResourceGroupName $resourceGroupName ` -ServerName $serverName ` -FirewallRuleName "AllowedIPs" ` -StartIpAddress $ipAddress -EndIpAddress $ipAddress $allowAzureIpsRule = New-AzSqlServerFirewallRule ` -ResourceGroupName $resourceGroupName ` -ServerName $serverName ` -AllowAllAzureIPs # Create a database $database = New-AzSqlDatabase -ResourceGroupName $resourceGroupName ` -ServerName $serverName ` -DatabaseName $databaseName ` -SampleName "AdventureWorksLT" ` -Edition "GeneralPurpose" -Vcore 2 -ComputeGeneration "Gen5" # Enable Azure Defender $azureDefender = Enable-AzSqlServerAdvancedDataSecurity ` -ResourceGroupName $resourceGroupName ` -ServerName $serverName # Create a storage account $storageAccount = New-AzStorageAccount -ResourceGroupName $resourceGroupName ` -AccountName $storageAccountName ` -Location $location ` -Type "Standard_LRS"
ローカル コンピューターで SSMS を開き、論理サーバーへの新しい接続を作成します。 サーバー名には、Azure SQL Database 論理サーバーの名前を入力します。 以前に名前を保存していない場合は、その名前を取得するために Azure portal を参照することが必要になる場合があります。 (例:
aw-server\<unique ID>.database.windows.net
)。Azure portal が表示されたら、検索ボックスに「AdventureWorks」と入力して、データベースとそれに関連付けられている論理サーバーを見つけることができます。
[認証] ボックスでは [SQL Server 認証] を入力します。 対応するサーバー管理者の [ログイン] と [パスワード] を入力します (前の演習でデプロイ時に指定したもの) を入力します。
[パスワードを記憶する] ボックスをオンにして、次に [接続] を選びます。
Note
ローカル構成 (VPN など) によっては、クライアントの IP アドレスが、デプロイの間に Azure portal で使用した IP アドレスと異なる場合があります。 その場合は、"このクライアント IP アドレスではサーバーにアクセスできません。 アクセスできるようにするには、Azure アカウントにサインインし、新しいファイアウォール規則を作成します。" このメッセージが表示されたら、サンドボックスに使用しているアカウントでサインインし、クライアント IP アドレスのファイアウォール規則を追加します。 SSMS のポップアップ ウィザードを使用して、これらの手順を完了できます。
PITR の完了
先に進む前に、PITR を実行するための推奨プロセスを理解しておくことが重要です。
- テーブルまたはデータベースが誤って削除されます。
- 戻る必要がある時間を決定します。エラーが発生する前である必要があります。
- PowerShell または Azure portal を使用して、この時点に戻るために PITR を完了します。 このプロセスにより、新しいデータベースがデプロイされ、データベースのコピーが復元されます。 次に例を示します。AdventureWorks-copy。
- 新しいデータベース (たとえば AdventureWorks-copy) が正しい (誤りが発生する前と同じ) 状態であることを確認します。
- 元のデータベースの名前を変更します。 たとえば、AdventureWorks という名前を AdventureWorks-old に変更します。
- 新しいデータベースの名前を元のデータベースの名前に変更します。 たとえば、AdventureWorks-copy という名前を AdventureWorks に変更します。
- 元のデータベースを削除します。 次に例を示します。AdventureWorks-old。
この演習では、これらの手順を行います。
データの削除をシミュレートする
まず、"誤って" 削除するテーブルが存在し、その中にデータが含まれていることを確認しましょう。 SalesLT. OrderDetail の値の一部を見てみましょう。
SSMS に移動し、接続を確認または更新します。 [ファイル]>[オブジェクト エクスプローラーを接続] を選んでから、[オプション] ボタンを選びます。
使用する接続が論理サーバーに接続されるが、特定のデータベースに接続されないことを確認します (たとえば、次のスクリーンショットに示されているように、<default> を使用します)。また、[追加の接続パラメーター] タブにテキストが含まれていないことも確認します。
Databases フォルダーを展開し、次に AdventureWorks データベースを右クリックして、[新しいクエリ] を選びます。 次のクエリを入力し、[実行] を選んで実行してから、結果を確認します。
SELECT TOP 10 * from SalesLT.SalesOrderDetail
データベース内のテーブルを削除して、データの損失をシミュレートします。
同じクエリ ウィンドウで次のクエリを実行し、[結果] ウィンドウで [メッセージ] タブを選び、完了時間をメモします。
DROP TABLE SalesLT.SalesOrderDetail
重要
完了時刻を保存します。 この情報は後で必要になります。 次に例を示します:
Completion time: 2020-06-22T09:20:27.1859237-07:00
。最後に、データベースを復元する手順を開始する前に、このページの右側の Azure Cloud Shell で次のコードを実行して、環境を構成します。
$resourceGroup = Get-AzResourceGroup | Where ResourceGroupName -like <rgn>[sandbox resource group name]</rgn> $server = Get-AzureRmSqlServer -ResourceGroupName $resourceGroup.ResourceGroupName $logical_server = $server.ServerName $resource_group = $resourceGroup.ResourceGroupName # Specify your default resource group and Azure SQL Database logical server az configure --defaults group=$resource_group sql-server=$logical_server # Confirm the defaults are set az configure --list-defaults
返される
group
パラメーターとsql-server
パラメーターは、Microsoft Learn リソース グループと Azure SQL Database 論理サーバーの名前に一致するはずです。
データベースを復元する時点を特定する
最初の手順は、データベースを復元する時点を把握することです。 "無効な" トランザクションの前の、最後の "正常な" トランザクションがいつ発生したかを確認する必要があります。 無効なトランザクションの前、かつ最後の正常なトランザクションの後に復元します。
削除時刻を調べる方法の 1 つは、前の手順でメモした DROP ステートメントの完了時刻を確認することです。
代わりの方法として、Azure portal で監査ログを使用します。 この演習では、Log Analytics に対する監査を構成しなかったのですが、その場合に何ができるかを見ていきましょう。 Azure portal で Azure SQL データベースに移動します。 左側のペインの [セキュリティ] で、[監査] を選んでから、[監査ログの表示] を選びます。 その後 [Log Analytics] を選ぶと、Kusto 照会言語 (KQL) を使用してログのクエリを実行できるクエリ エディターが表示されます。 SQL の専門家は、このクエリ言語を使用して、ログのクエリを簡単に実行できます。
その後、次の KQL クエリを実行できます。
search database_name_s == "AdventureWorks" | where Category == 'SQLSecurityAuditEvents' and statement_s like 'DROP' | project format_datetime(event_time_t, 'yyyy-MM-dd hh:mm:ss.fff'), ResourceGroup, server_instance_name_s, database_name_s, statement_s, succeeded_s,client_ip_s, server_principal_name_s, application_name_s | sort by event_time_t desc
結果は次のようになりますが、日付と時刻は異なります。
Note
ログがここに表示されるまでに 5 から 10 分かかる場合があるため、この演習の目的上、省略しています。代わりに、前の手順でメモした完了時間を使います。 (ただし、GMT に変換する必要があります)。実際の状況では、完了時刻を示すウィンドウが表示されない可能性が高いため、監査が非常に役立ちます。
この例では、日付と時刻は Log Analytics からは
2020-07-24 08:06:24.386
で、SSMS からは2020-07-24T13:06:24.386-07:00
です。 必要な形式は少し異なります。 この例を参考にして、正しい形式を確認してください。 確実にエラーが発生する "前" の時点に復元するために、0.001 秒減算することもできます。- Log Analytics の形式:
2020-07-24 08:06:24.386
- SSMS の形式:
2020-07-24T13:06:24.386-07:00
- 必要な形式:
2020-07-24T20:06:24.385
- Log Analytics の形式:
$before_error_time
を結果の値に設定し、この例の時刻を実際の時刻に置き換えます。$before_error_time ="2020-07-24T20:06:24.385"
データベースを復元し、欠落しているデータを確認する
このセクションでは、az cli db restore
を使用して、データベースを、テーブルが削除される前の時点に復元します。
このウィンドウの右側にあるターミナルで次のスクリプトを実行します。
# Restore the database to a time before the database was deleted az sql db restore --dest-name "AdventureWorks-copy" --name "AdventureWorks" --time $before_error_time --verbose
復元には約 5 から 10 分かかります。 復元を実行すると、Azure によって、新しい Azure SQL データベースが Azure SQL Database 論理サーバーにデプロイされます。 新しいデータベースの構成オプションは、元と同じです。 Azure SQL データベースがデプロイされると、Azure により、データベースが新しい Azure SQL データベースに復元されます。
SSMS でデータベースのビューを更新することで状態を確認できます。 Databases フォルダーを右クリックし、[最新の情報に更新] を選びます。 データベースがデプロイされた後は、復元が進行中であると表示されます。
復元が進行中であることが表示されたら、復元にはあと 2 から 3 分かかります。 終了したことは、コマンドの完了によってわかります。 また、更新を開始すると、コピー データベースの横に "(復元中...)" と表示されなくなります。
上記の時間よりも長くかかっていることがわかった場合は、Microsoft Learn 環境が原因である可能性があります。 1 つのサブスクリプションに対して一度に処理または送信できる復元要求の数には制限があります。 待機中の PITR に関する制限と関連する詳細について詳しくは、「Azure SQL Database のバックアップからデータベースを復元する」を参照してください。
ここで、新しいデータベースが正しい状態 (アクシデントが発生する前の状態) であることを確認します。 SSMS で論理サーバーを右クリックし、[更新] を選択して、Azure SQL Database 論理サーバーへの接続を更新します。
新しいデータベース (AdventureWorks-copy など) を右クリックし、[新しいクエリ] を選択します。
次のクエリを使用して、テーブルが存在することを確認します。
SELECT TOP 10 * from SalesLT.SalesOrderDetail
次のスクリーンショットに示す結果と同様の結果が表示されます。 この結果により、データベースが目的の場所に復元されたことが確認されます。
データベースを入れ替えてクリーンアップする
次に、元のデータベースの名前を AdventureWorks-old に変更します。これにより、後で、元のデータベース名を使って新しいデータベースの名前を変更できます。 このように変更すれば、アプリケーションで再試行ロジックが使用されている限り、接続文字列を変更する必要はありません。
ある時点でデータベースが使用できなくなった場合 (たとえば、接続を更新したときに SSMS のデータベースに接続できない場合)、DNS テーブルに更新が行われていることが原因である可能性があります。 そのため、データベースは物理的に使用できない状態ではありませんが、これを解決することはできません。 1 分ほど待つと、通常の活動を再開できるようになります。
次のコマンドを使用してデータベースの名前を変更します。
az sql db rename --name "AdventureWorks" --new-name "AdventureWorks-old"
元のデータベース名が使用されなくなったので、Azure Cloud Shell を使用して、コピー データベースの名前を元の名前に変更できます。
az sql db rename --name "AdventureWorks-copy" --new-name "AdventureWorks"
古いデータベースは必要なくなったため、
az sql db delete
を使用して削除できます。az sql db delete --name "AdventureWorks-old" --yes Write-Host "Database deleted"
次のコマンドを使用して、古いデータベースが存在しなくなったことを確認できます。
az sql db list -o table
以上、Azure SQL Database で PITR を使用する方法について説明しました。 PITR は、Azure SQL Managed Instance でも使用できますが、インスタンス全体ではなくデータベースに対して使用できます。 az sql db
ではなく az sql midb
を使用する点を除いて、ほぼ同じコマンドを使用できます。