Azureの2リージョン間 BCDR-災害対策と待機系フェイルオーバ

今回は、Azureの特徴でもある二つのリージョンペアとストレージの仕組みを使って、2リージョン間のBCDR対策と待機系フェイルオーバを作ってみました。

容量にもよりますが、5分程度でフェイルオーバーできますし少ない費用で済みますので、VMの災害対策や復旧目標時間がシビアではない、稼働系・待機系のフェイルオーバーを考えている人にはちょうど良いと思います。

Azureのリージョン

Azureのリージョンは、東日本と西日本という感じで、リージョンはペアで構成されており、二つのリージョンの距離は可能な限り480km以上の距離で構築されています。

ビジネス継続性と障害復旧 (BCDR): Azure のペアになっているリージョン

[地理的な場所] ペアになっているリージョン
北米 米国中北部 米国中南部
北米 米国東部 米国西部
北米 米国東部 2 米国中部
ヨーロッパ 北ヨーロッパ 西ヨーロッパ
アジア 東南アジア 東アジア
中国 中国東部 中国北部
日本 東日本 西日本
ブラジル ブラジル南部 (1) 米国中南部
オーストラリア オーストラリア東部 オーストラリア南東部
米国政府 米国政府アイオワ州 米国政府バージニア州
インド インド中部 インド南部

AzureストレージのRA-GRS

Azure仮想マシンのVHD(仮想HDD)は、Azureストレージの上で稼働しています。
Azureストレージは、書き込まれたデータの可用性と災害対策を追加できる、GRSとRA-GRSという障害対策のオプションが組み込まれています。

Azure Storage のレプリケーション

仮想マシンの作成後でも、以下のようにVHDが設置されたストレージのオプションを変更すれば、RA-GRSに変更可能です。転ばぬ先の杖であり、保険と思って有効にする事をお勧めします。

capture20160709010611089

BCDR対策済みの構成を考える

今回は、以下の図のような構成を作ってみました。

  • 東日本と西日本にRA-GRSのディスク上に二台のVMを構築
  • RA-GRSにより、非同期でディスクデータがコピーされる
  • 東日本は稼働系、西日本は待機系なのでVMは停止しておく

待機系を用意しておくのは費用の無駄が・・・と思われるかもしれませんが、そこの奥さんAzureは

停止中のVMの料金は取られませんしストレージも使った分の請求

なのです。
待機系VMもあらかじめ作っておいて、気楽にBCDRの対策をできます。
例えば、127GB中64GBが使われているのであれば、64GB分の請求で済みますので、お得です。

ra-grs.png

災害時や障害発生時の復旧を行う場合、以下の手順で行います。

  1. 二台の稼働VMを停止(正常系であれば、東日本が停止、西日本は停止済み)
  2. 東日本から非同期レプリケーションされた、西日本のセカンダリのディスクを西日本のVMのディスクに上書きコピー
  3. 西日本のVMを起動して復旧

フェイルオーバースクリプトで自動化

今回の場合、サービス維持が目的となる短い時間でのフェイルオーバーでは無く、災害時にリージョンが破たんした場合など、とりあえず15分前のディスクを復旧する事ができると良いな!、程度の災害対策が目的のフェイルオーバーです。

私の環境では5分程度で切り替えができました。

復旧目標時間(RTO)が短い場合などの、完全なディスクの双方向同期が必要な場合は、他の方法を検討する必要があります。

しかし、無いよりは合った方が良いですし、少ない費用でVMの災害対策や稼働系・待機系のフェイルオーバーを考えている人にはちょうど良いでしょう。

以下のスクリプトは、ローカルのPowerShell用サンプル、Azure Automationに登録して、障害検知したらWebhookでキックするなどして、フェイルオーバーするなどもできるようになります。

Login-AzureRmAccount
Get-AzureRmSubscription
Select-AzureRmSubscription -SubscriptionName 'サブスクリプション名'

# 東日本のRGとVM名
$SrcRgName='FailoverJapanEast'
$SrcVmName='JapanEast'

# 西日本のRGとVM名
$DstRgName='FailoverJapanWest'
$DstVmName='JapanWest'

# 東日本のRA-GRSストレージアカウントの情報、
# 名前に-secondaryを付与する事で読み取り専用アクセスが可能になります。
$SrcStorageAccountName = 'failoverjapaneast5544'
$SrcStorageAccountKey = 'SpovzY3+XbzMeB8r+MdZO5oy2DSUHaL+kLlR18mzOTtJCMouE8q1w+RQR8fpXkRWVG0lXi7LZITDWFy0fI4gCw=='
$SrcContext = New-AzureStorageContext -ConnectionString "BlobEndpoint=https://$SrcStorageAccountName-secondary.blob.core.windows.net/;QueueEndpoint=https://$SrcStorageAccountName-secondary.queue.core.windows.net/;TableEndpoint=https://$SrcStorageAccountName-secondary.table.core.windows.net/;FileEndpoint=https://$SrcStorageAccountName-secondary.file.core.windows.net/;AccountName=$SrcStorageAccountName;AccountKey=$SrcStorageAccountKey"

# 西日本のRA-GRSストレージアカウントの情報
$DstStorageAccountName = 'failoverjapanwest7632'
$DstStorageAccountKey = 'Ks6+yOgwOQcUdE7qjwaaszJKl1sDJ8UACTsWLm6HFszNFxjHBsizvKaEGpkv2tnnifggDChUfhhWvttEGuCCNA=='
$DstContext = New-AzureStorageContext -StorageAccountName $DstStorageAccountName -StorageAccountKey $DstStorageAccountKey

# 東日本のコピー元VHDを指定、複数DISKはカンマ区切りで
$SrcContainerName = 'vhds'
$SrcBlobNames = @('JapanEast20166911355.vhd')

# 西日本のコピー先VHDを指定、複数DISKはカンマ区切りで
$DstContainerName = 'vhds'
$DstBlobNames = @('JapanWest20166911454.vhd')

## function
# VMのステータス確認と起動
function Start-Vm($RgName, $VmName) {
    $VmDetail = Get-AzureRmVM -ResourceGroupName $RgName -Name $VmName -Status -ErrorAction 'SilentlyContinue' -WarningAction 'SilentlyContinue'| Select-Object -ExpandProperty Statuses| Select-Object -ExpandProperty Code
    $VmState = $VmDetail[-1]
    if ($VmState -like 'PowerState/deallocated'){
        Start-AzureRmVM -ResourceGroupName $RgName -Name $VmName
        do {
            Write-host "Waiting for" $VmName " to have a 'Running' status ...." $VmState    
            Start-Sleep -s 5
            $VmDetail = Get-AzureRmVM -ResourceGroupName $RgName -Name $VmName -Status -ErrorAction 'SilentlyContinue' -WarningAction 'SilentlyContinue'| Select-Object -ExpandProperty Statuses| Select-Object -ExpandProperty Code
            $VmState = $VmDetail[-1]
        }until($VmState -like 'PowerState/running')   
    }
}

# VMのステータス確認と停止
function Stop-Vm($RgName, $VmName) {
    $VmDetail = Get-AzureRmVM -ResourceGroupName $RgName -Name $VmName -Status -ErrorAction 'SilentlyContinue' -WarningAction 'SilentlyContinue'| Select-Object -ExpandProperty Statuses| Select-Object -ExpandProperty Code
    $VmState = $VmDetail[-1]
    if ($VmState -like 'PowerState/running'){
        Stop-AzureRmVM -ResourceGroupName $RgName -Name $VmName -Force
        do {
            Write-host "Waiting for" $RgName " to have a 'Stopped' status ...." $VmState    
            Start-Sleep -s 5
            #Check the power status
            $VmDetail = Get-AzureRmVM -ResourceGroupName $RgName -Name $VmName -Status -ErrorAction 'SilentlyContinue' -WarningAction 'SilentlyContinue'| Select-Object -ExpandProperty Statuses| Select-Object -ExpandProperty Code
            $VmState = $VmDetail[-1]
        }until($VmState -like 'PowerState/deallocated')   
    }
}

# ターゲットとなるVHDのLeaseを解除
function Break-lease($vhdObj) {
    If($vhdObj.ICloudBlob.Properties.LeaseStatus -eq 'Locked') 
    { 
        Try 
        { 
            $vhdObj.ICloudBlob.BreakLease($(New-TimeSpan), $null, $null, $null) | Out-Null
        } 
        Catch 
        { 
            Write-host 'Failed to break lease on '$vhdObj' blob.' -ForegroundColor Red 
        } 
    } 
}

## Main
# 西日本のVMが起動している場合は停止
Stop-Vm $DstRgName $DstVmName

# 東日本のVMの停止(リージョンは死んでいる想定なので、本動作の期待はできない)
Stop-Vm $SrcRgName $SrcVmName

# ディスクの本数分Loop
for ($i=0; $i -lt $DstBlobNames.length; $i++) {
    $DstBlobName=$DstBlobNames[$i]
    $SrcBlobName=$SrcBlobNames[$i]
    $DstVhd = Get-AzureStorageBlob –Context $DstContext -Prefix $DstBlobName -Container $DstContainerName | Where-Object  { (!$_.ICloudBlob.IsSnapshot) -and $_.Name -eq $DstBlobName }
    Break-lease $DstVhd
    # 東日本から西日本のレプリケーションされたSecondaryから、西日本ディスクに上書きコピー
    $copyBlob = Start-AzureStorageBlobCopy -ConcurrentTaskCount 32 -SrcContainer $SrcContainerName -SrcBlob $SrcBlobName -Context $SrcContext –DestContainer $DstContainerName -DestBlob $DstBlobName -DestContext $DstContext  -Force
    $copyBlob | Get-AzureStorageBlobCopyState -WaitForComplete
}
Start-Sleep -s 30
# 西日本のVMの起動
Start-Vm  $DstRgName $DstVmName

exit