Windows Azure PowerShell を使って Windows Azure クラウドサービスへのデプロイを自動化しよう

こんにちは、この投稿は PowerShell Advent Calendar 2013 の 5 日目の記事です。

はじめに

去年まで PowerShell とは縁がなく、自分には必要ない道具だと思っていました。

ところが、デプロイを自動化する業務で Azure PowerShell に初めて触れ、PowerShell の万能さに驚き、 今となっては Windows を使って仕事している人には PowerShell は必須の道具だと思うくらいに毒されてしまいました。 この投稿を機に Azure 使いが PowerShell に流入してくるといいなと思ってます。

今回作成するスクリプトは GitHub に置いていますが、 試すには Azure のサブスクリプションが必要です。 今回 Windows7 x64、Visual Studio 2012、Windows Azure SDK for .NET (VS 2012) - 2.2 の環境で検証しています。

Azure PowerShell

Azure PowerShell を使うと Web の Windows Azure 管理ポータルでできる操作はだいたいできます。 PowerShell のコマンドレットは MSDN で確認できるので、ざっと見れば雰囲気が掴めると思います。

Azure PowerShell の更新情報ですが、私はソースコードに含まれる ChangeLog.txt を確認しています。 着実にできることが増えてきているので、毎回のリリースが楽しみです。

Azure PowerShell のインストール&初期設定

では、最新版の Azure PowerShell を Web Platform Installer でインストールします。 直接 Web Platform Installer を起動してもいいし、 サイトからダウンロードしてきても OK です。 ただ Azure SDK も一緒にインストールされるので、環境を汚くしたくない人は VM などで試すのをオススメします 。

f:id:hikoma:20131206114239p:plain

インストールが完了したら PowerShell を起動して、サブスクリプションを設定します。

PS C:\Temp> Add-AzureAccount

ここで、説明が難しいのですが CurrentStorageAccountName を設定しろと怒られる場合があるので、適当に潰しておきます。

PS C:\Temp> Get-AzureSubscription -Current | Set-AzureSubscription -CurrentStorageAccountName _

以上で、PowerShell を使って Azure をあれこれ操作する準備が整いました。 簡単ですね。

デプロイパッケージの作成

次に、デプロイパッケージを作成します。 ビルドも PowerShell で記述したいところですが、残念ながらそのノウハウを持ち合わせておりません。 普通に MSBuild を用いてパッケージを作成します。 Visual StudioWindows Azure クラウドサービスプロジェクトを作成し(今回は省略)、生成された ccproj に対して Publish ターゲットで msbuild をすれば OK です。こんな感じになるかと思います。

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <OutputDir>$(MSBuildProjectDirectory)\output</OutputDir>
    <BuildProperties>VisualStudioVersion=11.0;Configuration=Release;Platform=AnyCPU</BuildProperties>
  </PropertyGroup>

  <ItemGroup>
    <ProjectFile Include="$(MSBuildProjectDirectory)\**\*.ccproj"/>
  </ItemGroup>

  <Target Name="Build">
    <MSBuild Targets="Publish" Projects="@(ProjectFile)"
             Properties="$(BuildProperties);PublishDir=$(OutputDir)\" />
  </Target>
</Project>

このファイルを適当な名前(今回は PowerShellDeploySample.msbuild)で保存し、コマンドプロンプトmsbuild を実行します。Visual Studio のコマンドプロントで msbuild を叩くか、下記のように msbuild.exe のフルパスを直接叩いても大丈夫です。 VisualStudioVersion=11.0 は Azure SDK for .NET のバージョンに応じて修正してください。

C:Temp> C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe PowerShellDeploySample.msbuild /t:Build

output フォルダに作成された cspkg と cscfg ファイルがデプロイパッケージです。

PowerShell でデプロイ

では、デプロイを始めましょう。 今回は「 ステージング環境にデプロイ → ステージング環境で動作確認 → 運用環境に切り替え 」 というシナリオでデプロイを行いたいと思います。

Blob ストレージにパッケージをアップロード

まず、cspkg ファイルと cscfg ファイルを Azure Blob ストレージにアップロードします。 この作業は必須ではないのですが、管理ポータルから再デプロイがやりやすくなるのでオススメです。

では、アップロードしましょう。 まずは、ストレージアカウントが必要なので作成します。

PS C:\Temp> $storageAccountName = 'deployaccount'
PS C:\Temp> New-AzureStorageAccount -StorageAccountName $storageAccountName -Location 'East Asia'

StorageAccountName は Azure 内で一意である必要があるので、試す場合は変更してください。 次に、Blob を入れるコンテナが必要なので作成します。

PS C:\Temp> $blobContainerName = 'deploycontainer'
PS C:\Temp> $storageKey = Get-AzureStorageKey -StorageAccountName $storageAccountName
PS C:\Temp> $storageContext = New-AzureStorageContext -StorageAccountName $storageAccountName -StorageAccountKey $storageKey.Primary
PS C:\Temp> New-AzureStorageContainer -Context $storageContext -Container $blobContainerName

最後に Blob をアップロードします。

PS C:\Temp> $cspkgFile = Get-Item *.cspkg
PS C:\Temp> $cscfgFile = Get-Item *.cscfg
PS C:\Temp> $cspkg = Set-AzureStorageBlobContent -Context $storageContext -Container $blobContainerName -File $cspkgFile
PS C:\Temp> $cscfg = Set-AzureStorageBlobContent -Context $storageContext -Container $blobContainerName -File $cscfgFile

次に、アップロードしたパッケージを、ステージング環境にデプロイします。

ステージング環境にデプロイ

まずはクラウドサービスを作成します

PS C:\Temp> $cloudServiceName = 'PowerShellDeploySample'
PS C:\Temp> New-AzureService -ServiceName $cloudServiceName -Location 'East Asia'

ServiceName は Azure 内で一意である必要があるので、試す場合は変更してください。 次に、ステージング環境にパッケージをデプロイします。

PS C:\Temp> $pakcageUri = $cspkg.ICloudBlob.Uri.AbsoluteUri
PS C:\Temp> New-AzureDeployment -ServiceName $cloudServiceName -Slot Staging -Package $pakcageUri -Configuration $cscfgFile

これで、デプロイ完了だ! ステージング環境で動作確認やるぞ! と行きたいところですが、実はまだインスタンスの起動終わっていません!!!実際に確認してみます。

PS C:\Temp> $deployment = Get-AzureDeployment -ServiceName $cloudServiceName -Slot Staging
PS C:\Temp> $deployment.RoleInstanceList.InstanceStatus
CreatingVM
CreatingVM

この InstanceStatus が全て ReadyRole になるまで待つ必要があります。 ReadyRole になったら、ステージング環境にアクセスしてみます。 接続先 URL は $deployment から取得することができます。

PS C:\Temp> $deployment.Url.AbsoluteUri
http://5bb82cb2a3be4e66ba9b7f5941ecc71d.cloudapp.net/

この URL にアクセスすれば、ステージング環境の動作確認ができます。

ステージング環境を運用環境に移す

一通りステージング環境で動作確認ができたら、運用環境に移します。 ここでは Azure の Vip スワップという機能を利用します。

PS C:\Temp> Move-AzureDeployment -ServiceName $cloudServiceName

操作はこれだけです。接続先 URL を確認します。

PS C:\Temp> (Get-AzureDeployment -ServiceName $cloudServiceName -Slot Production).Url.AbsoluteUri
http://powershelldeploysample.cloudapp.net/

この URL にアクセスして、動作確認ができたらデプロイ成功です!

ビルドとデプロイのスクリプト化

以上の手続きに、コメントやエラー処理などを入れたスクリプト Deploy.ps1 を GitHub に上げています。 Deploy.ps1 を直接叩いてもいいし、PowerShellDeploySample.msbuild でサンプルプロジェクトをビルドしてデプロイを試してみることもできます。 ちょっとエラー処理やりすぎている感じがしますが -ErrorAction SilentlyContinue でも普通に動くので、裁量はお任せします。

さいごに

Azure PowerShell 自体はコマンドレットのパラメータを見ながら使うだけなので割とさくっとスクリプトは書けるようになると思います。 Azure PowerShell の最大の敵は Azure 側の更新が遅いということに尽きると思います。 スクリプトの検証に時間がかかるので、ほんのささいなミスでがっかりすることが何度あったことやら。 それに加えて、Azure 側の操作はたまに失敗します(特にストレージ周り)。 例外を捕捉したら、リトライ処理が必要なケースが度々出てきます。 とは言っても PowerShell のおかげで例外処理自体は記述しやすいかと思います。