Tag Archives: Microsoft Azure

Azure の Storage Client と Diagnostics の旧バージョンサポート終了について

以前の記事で、Azure の Storage Client と Diagnostics の旧バージョンサポート終了に伴う移行方法を書きましたが、サポート終了日の延期が2回ほど告知されているため、改めて整理してみました。

Azure Storage Client

最新の告知では、Ver.1.7 ~ 1.5.1 が 無期限 に延期され、それ以前のバージョンが 2016年8月1日 に延期されました。当初予定されていた 2015年12月9日 にサポート終了されるバージョンはありませんが、Ver 2.0 以降で互換性が保証されない変更が行われていて移行作業が大変なので、早めの対応をお勧めします。

Azure Diagnostics

Cloud Services(Web Role, Worker Role)で診断ログを利用している場合、2015年12月9日 までに Azure SDK 2.5 以降から利用できる新しい診断ログに更新する必要があります。昨年の 12月に Azure サブスクリプション宛に届いたメールで告知されており、延期の告知はありません。Azure SDK 2.5 以降では Visual Studio 2010 を使った開発ができないため、Visual Studio 2013 or 2015 への更新が必要なケースもあります。現在、Azure SDK の最新バージョンは 2.7.1 ですが、以下の手順で移行することができます。

Azure SDK

Cloud Services(Web Role, Worker Role)では、少なくとも最新の 2 つの SDK バージョンをサポートするというサポート ポリシーがあります。Azure SDK 1.6 ~ 2.1 は 、2015年11月12日 にサポート終了しますので、診断ログを利用していなくても、新しいバージョンに移行する必要があります。

Azure Web Apps に Parameters.xml を使って WebDeploy する

ASP.NET MVC アプリケーションの WebDeploy パッケージを Azure Web Apps にデプロイする際に、Web.config に埋め込まれた Storage などの接続文字列を書き換えるために zip ファイルを展開する作業が非常に手間でした。

調べてみると、デプロイする際に Parameters.xml で Web.config の値を書き換えられることを知りました。この方法なら、zip ファイルを展開する必要はないですし、本番環境で使う接続文字列をソースコード管理に入れることなく、安心して開発できます。

前準備

ASP.NET MVC アプリケーションの Web.config に、Azure Storage の接続文字列を定義します。

<configuration>
  <appSettings>
    <add key="MyStorage" value="UseDevelopmentStorage=true"/>
  </appSettings>
</configuration>

プロジェクトの直下に Parameters.xml を追加し、書き換えルールを定義します。

<?xml version="1.0" encoding="utf-8" ?>
<parameters>
  <parameter name="appSettings_MyStorage" description="Azure Storage の接続文字列">
    <parameterEntry kind="XmlFile" defaultValue="UseDevelopmentStorage=true" scope="\\Web.config$" match="//appSettings/add[@key='MyStorage']/@value" />
  </parameter>
</parameters>

Visual Studio から WebDeploy パッケージを作成すると、WebApplication1.SetParameters.xml に書き換えの設定が追加されていることが分かります。

<?xml version="1.0" encoding="utf-8"?>
<parameters>
  <setParameter name="IIS Web Application Name" value="Default Web Site/WebApplication1_deploy" />
  <setParameter name="appSettings_MyStorage" value="UseDevelopmentStorage=true" />
</parameters>

この value の値を Azure Storage の接続文字列に変更すれば、Web.config を書き換えてデプロイすることができます。

コマンドからデプロイする

WebDeploy のコマンドを使って、デプロイします。「-setParamFile」の引数に SetParameters.xml のパスを渡します。ここでは、Azure Web Apps を 「deploytest」という名前で作成して、デプロイします。ユーザー名やパスワードは、Azure ポータルからダウンロードできる Publish プロファイルに記載されています。

"C:\Program Files\IIS\Microsoft Web Deploy V3\msdeploy.exe" 
	-verb:sync -source:package="C:\Users\xxx\Desktop\Test\WebApplication1.zip" 
	-dest:auto,ComputerName="https://deploytest.scm.azurewebsites.net:443/msdeploy.axd?site=deploytest",UserName='$deploytest',Password='xxx',AuthType='Basic',IncludeAcls='true'
	-enableRule:DoNotDeleteRule -setParam:"IIS Web Application Name"='deploytest' 
	-setParamFile:"C:\Users\xxx\Desktop\Test\WebApplication1.SetParameters.xml"

C# のコードからデプロイする

コマンドはどうも苦手なので、やっぱり C# でコードを書いてデプロイしたいです。以前に帝国兵さんが書かれた記事とほぼ同じですが、SetParameters.xml を渡せるように改良しました。

コンソールアプリケーションなどを作成し、WebDeploy に必要なライブラリを NuGet からインストールしておきます。

引数には、Publish プロファイル、WebDeploy パッケージ、SetParameters.xml のパスを渡します。SetParameters.xml から読み取った値を DeploymentObject のパラメーターにセットしている部分がポイントです。

public static class WebAppsPublisherHelpler
{
    public static DeploymentChangeSummary Publish(string publishSettingsPath, string sourcePath, string parametersPath)
    {
        if (String.IsNullOrEmpty(publishSettingsPath)) throw new ArgumentNullException("publishSettingsPath");
        if (String.IsNullOrEmpty(sourcePath)) throw new ArgumentNullException("sourcePath");
        if (!File.Exists(publishSettingsPath)) throw new Exception(String.Format("{0}: Not found.", publishSettingsPath));
        if (!File.Exists(sourcePath)) throw new Exception(String.Format("{0}: Not found.", sourcePath));
        if (Path.GetExtension(sourcePath).Equals(".zip", StringComparison.InvariantCultureIgnoreCase) == false) throw new Exception("Extension supports only zip.");

        // PublishSettings
        var document = XElement.Load(publishSettingsPath);
        var profile = document.XPathSelectElement("//publishProfile[@publishMethod='MSDeploy']");
        if (profile == null)
        {
            throw new Exception(String.Format("{0}: Not a valid publishing profile.", publishSettingsPath));
        }
        var publishUrl = profile.SafeGetAttribute("publishUrl");
        var userName = profile.SafeGetAttribute("userName");
        var password = profile.SafeGetAttribute("userPWD");
        var siteName = profile.SafeGetAttribute("msdeploySite");
        var webDeployServer = string.Format(@"https://{0}/msdeploy.axd?site={1}", publishUrl, siteName);

        // Set up deployment
        var destinationOptions = new DeploymentBaseOptions{ ComputerName = webDeployServer, UserName = userName, Password = password, AuthenticationType = "basic", IncludeAcls = true, TraceLevel = TraceLevel.Info };
        destinationOptions.Trace += (sender, e) =>
        {
            Trace.TraceInformation(e.Message);
        };
        var syncOptions = new DeploymentSyncOptions { DoNotDelete = true };  // Please change as you want

        DeploymentChangeSummary result;
        try
        {
            // Start deployment
            using (var deploy = DeploymentManager.CreateObject(DeploymentWellKnownProvider.Package, sourcePath, new DeploymentBaseOptions()))
            {
                // Apply package parameters
                foreach (var p in deploy.SyncParameters)
                {
                    switch (p.Name)
                    {
                        case "IIS Web Application Name":
                            p.Value = siteName;
                            break;
                        default:
                            // SetParameters.xml
                            if (!String.IsNullOrEmpty(parametersPath))
                            {
                                var parameters = XElement.Load(parametersPath);
                                var setParameter = parameters.XPathSelectElement(String.Format("//setParameter[@name='{0}']", p.Name));
                                if (setParameter != null)
                                {
                                    p.Value = setParameter.SafeGetAttribute("value");
                                }
                            }
                            break;
                    }
                }
                result = deploy.SyncTo(DeploymentWellKnownProvider.Auto, siteName, destinationOptions, syncOptions);
            }
        }
        catch (Exception)
        {
            throw;
        }
        return result;
    }

}
public static class MethodExtention
{
    public static string SafeGetAttribute(this XElement node, string attribute, string defaultValue = null)
    {
        var attr = node.Attribute(attribute);
        return attr == null ? defaultValue : attr.Value;
    }
}

まとめ

Cloud Services では、構成ファイル(cscfg)に Storage の接続文字列を設定してデプロイできますが、Web Apps でも Parameters.xml を使うと同じようにデプロイできます。業務系の Web アプリケーションであっても、Web Apps ファーストで積極的に使っていきたいと思います。

Azure Cloud Services のデプロイが完了しない原因を特定する方法

久しぶりに Azure Cloud Services のデプロイでハマってしまったので共有しておきます。

Web Role や Worker Role のプロジェクトをデプロイした際、パッケージに問題があり、ビジー → 再開中 が繰り返されてデプロイが完了しないときがあります。ポータル上では、何かしらのエラーが発生してロールが起動しないことは分かりますが、詳しい原因までは分かりません。

portal

DebugView for Windows というツールでログを取得すると、エラーの詳細が分かることがあります。

使い方

  1. こちらのサイトから DebugView for Windows をダウンロードします。
  2. デプロイが完了しないロールのインスタンスにリモートデスクトップ接続して、先ほどダウンロードしたファイルをコピーします。
  3. ロールのインスタンス上で、DbgView.exe を管理者権限で起動します。debugview
  4. Capture メニューで、Capture Win32 と Capture Global Win32 にチェックを入れます。debugview4
  5. Options メニューで Clock Time にチェックを入れます。debugview5
  6. ビジー → 再開中 の繰り返しが何度か発生するまで、ログを取得します。
  7. File メニューで、Save As からログをファイルに保存します。

ログの解析

例えば、次のようなログ出力されている場合、System.Web.HTTP.dll がパッケージに含まれない可能性があります。

00000235	6:22:00 AM	[3128] System.TypeLoadException: Unable to load the role entry point due to the following exceptions:
00000236	6:22:00 AM	[3128] -- System.IO.FileNotFoundException: Could not load file or assembly 'System.Web.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.
00000237	6:22:00 AM	[3128] File name: 'System.Web.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'

このアセンブリを参照設定に追加して、ローカルにコピーするプロパティを True に設定すれば解決です。

また、次のようなログ出力されている場合、Microsoft.WindowsAzure.Storage.dll の古いバージョン(2.1.0.4)を意図せず参照している可能性があります。

00000128	8:15:45 AM	[3632] System.IO.FileLoadException: Could not load file or assembly 'Microsoft.WindowsAzure.Storage, Version=2.1.0.4, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
00000129	8:15:45 AM	[3632] File name: 'Microsoft.WindowsAzure.Storage, Version=2.1.0.4, Culture=neutral, PublicKeyToken=31bf3856ad364e35'

Web.config にリダイレクトの記載を追加すれば解決です。

<dependentAssembly>
        <assemblyIdentity name="Microsoft.WindowsAzure.Storage" publicKeyToken="31bf3856ad364e35" culture="neutral"/>
        <bindingRedirect oldVersion="0.0.0.0-4.3.0.0" newVersion="4.3.0.0"/>
</dependentAssembly>

まとめ

ビジー → 再開中 が繰り返されてデプロイが完了しない原因は、Web Role や Worker Role のプロジェクトが参照しているアセンブリがパッケージに含まれていなかったり、スタートアップタスク内でエラーが発生していることが考えられます。

ポータル上では詳しい原因までは分かりませんので、DebugView for Windows でログを取得して原因を特定するようにしましょう。

Azure SDK 2.6 の Azure Diagnostics に移行する

以前の記事でも書きましたが、Cloud Services で Azure Diagnostics を利用している場合、2015年12月9日までに Azure SDK 2.5 以降で利用できる Diagnostics 2.0 にアップグレードする必要があります。重複する部分もありますが、この記事では、Azure SDK 2.6 の Azure Diagnostics  に移行する方法を紹介していきます。

Azure SDK 2.6 の Azure Diagnostics とは?

概要や使い方については、このあたりのサイトが参考になります。

Build 2015 でも、Azure Diagnostics 関連のセッションが2つほどありました。

Azure SDK 2.5 と 2.6 の Azure Diagnostics には、次のような機能の違いがあります。

  • ローカルのエミュレーターでも診断ログを収集できる
  • 診断ストレージ アカウントの接続文字列(Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString)の復活
  • パッケージを作ると、Extensions サブフォルダに PaaSDiagnostics.<ロール名>.PubConfig.xml という構成ファイルが作られる

Cloud Services で Azure Diagnostics を利用する方法

以下の手順で、Azure SDK 2.6 の Azure Diagnostics を Cloud Services で利用することができます。Visual Studio のプロジェクトで、ロールの WebRole1 のプロパティから診断の有効化と構成が可能です。

wad12

wad19

似たような GUI で Azure SDK 2.5 も診断構成できましたが、診断ストレージ アカウントの接続文字列が復活したので、診断構成でストレージ アカウントを設定できなくなっています。

診断構成したプロジェクトからパッケージを作成し、Azure 管理ポータルからデプロイすると診断機能が無効になっています。Visual Studio か PowerShell のどちらかで診断機能を有効にする必要があるのは、Azure SDK 2.5 と変わりません。なお、Visual Studio から直接デプロイすると、診断機能が有効になった状態でデプロイできます。

Visual Studio のサーバーエクスプローラ

クラウドサービスのロールを右クリックして、診断を有効にできます。診断構成を変更することも可能です。

wad14

PowerShell の Set-AzureServiceDiagnosticsExtension コマンド

Set-AzureServiceDiagnosticsExtension コマンドの引数の DiagnosticsConfigurationPath で指定する診断構成ファイルは、Azure SDK 2.6 でパッケージを作ると、Extensions サブフォルダに PaaSDiagnostics.<ロール名>.PubConfig.xml という構成ファイルが作られるので、これをそのまま使えます。Azure SDK 2.5 のように、手動で作成する必要はなくなりました。

wad15

この診断構成ファイルを使って、Set-AzureServiceDiagnosticsExtension コマンドを実行します。Azure Storage や Service の名前は、環境に合わせて置き換えてください。

$storageContext = New-AzureStorageContext –StorageAccountName <storagename> –StorageAccountKey <key>
Set-AzureServiceDiagnosticsExtension -ServiceName <servicename> -Slot Production -Role WebRole1 -StorageContext $storageContext -DiagnosticsConfigurationPath C:\Users\xxx\Desktop\PaaSDiagnostics.WebRole1.PubConfig.xml

診断機能が有効になると、各種のログが Azure Storage に転送されるようになります。

Azure SDK 2.5 以前から移行する方法

Azure Diagnostics には、診断構成にいくつかの方法があります。大きく4つのパターンに分類します。どのパターンでも、Visual Studio で Azure SDK をアップグレードするまでは同じです。アップグレード後の手順が異なるので、順番に説明していきます。

Visual Studio 上の GUI で構成していた場合

Visual Studio のプロジェクトで、ロールの WebRole1 のプロパティから診断構成画面で構成していた場合です。

wad01

Azure SDK 2.0 以降のバージョンで作成したプロジェクトがこのケースに該当するので、最も多いと思われます。プロジェクトのアップグレードが完了すると、ロールの WebRole1 に diagnostics.wadcfg が残っているので削除します。Azure SDK 2.5 以降では、diagnostics.wadcfgx を使いますので、右クリックして「診断構成の追加」を実行します。

wad02

あとは、前述した Azure SDK 2.6 で新しくプロジェクトを作成した場合の手順通りに、診断構成を再構成します。

diagnostics.wadcfg ファイルで構成していた場合

Visual Studio のプロジェクトで、WebRole の直下に diagnostics.wadcfg を配置して構成していた場合です。

wad03

Azure SDK 1.x のバージョンで作成したプロジェクトは、このケースに該当します。プロジェクトのアップグレードが完了すると、WebRole の直下に diagnostics.wadcfg が残っているので削除します。ロールの WebRole1 に diagnostics.wadcfgx がありませんので、右クリックして「診断構成の追加」を実行します。あとは、前述した Azure SDK 2.6 で新しくプロジェクトを作成した場合の手順通りに、診断構成を再構成します。

(追記)ServiceConfiguration.Local.cscfg がないと、「エラー1 unable to get setting value パラメーター名:profileName」というエラーが発生して、診断ログを有効できないバグがあります。Azure SDK 1.4 より古いバージョンで作成したプロジェクトが該当します。その際には、Visual Studio の機能を利用して、ServiceConfiguration.cscfg のコピーを作成してください。ServiceConfiguration.Local.cscfg と ServiceConfiguration.Cloud.cscfg の2つを作成したら、元の ServiceConfiguration.cscfg を削除しましょう。

コードで構成していた場合

WebRole クラスの OnStart() メソッドで、Microsoft.WindowsAzure.Diagnostics 名前空間の API を使って構成していた場合です。

public class WebRole : RoleEntryPoint
{
    public override bool OnStart()
    {
        // 診断ログを構成
        DiagnosticMonitorConfiguration config = DiagnosticMonitor.GetDefaultInitialConfiguration();
        config.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);
        config.Logs.ScheduledTransferLogLevelFilter = Microsoft.WindowsAzure.Diagnostics.LogLevel.Error;
        config.Directories.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);
        DiagnosticMonitor.Start("Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString", config);

        return base.OnStart();
    }
}

Azure SDK 1.x のバージョンで作成したプロジェクトは、diagnostics.wadcfg ファイルとコードのどちらでも構成できましたが、コードで構成していたケースは少ないはずです。プロジェクトのアップグレードが完了すると、DiagnosticMonitor クラスなどに Obsolete の警告が表示されますので、コードを削除します。ロールの WebRole1 に diagnostics.wadcfgx がありませんので、右クリックして「診断構成の追加」を実行します。あとは、前述した Azure SDK 2.6 で新しくプロジェクトを作成した場合の手順通りに、診断構成を再構成します。

Azure SDK 2.5 に移行していた場合

Azure SDK 2.4 以前からの移行が完了しており、Azure SDK 2.5 を使っていた場合です。

wad10

Azure SDK 2.6 で新しくプロジェクトを作成した際の画面とは異なりますが、「接続文字列を追加」ボタンから診断ストレージ アカウントの設定ができます。設定すると、通常の画面に戻ります。

wad11

診断構成の画面も少し変わっています。ここに表示されているストレージ アカウントは使われないので、diagnostics.wadcfgx ファイルから削除しておきましょう。

wad17

 まとめ

Azure SDK 2.6 の Diagnostics  は、慌ててリリースされた感のある 2.5 でのいくつかのバグも修正されており、やっと実運用で使える品質になったという印象です。

診断ログの仕組みとして、2.4 以前のデプロイメント モデルから 2.5 以降のエクステンション モデルに変更されたことで、アプリケーションとログ収集が完全に切り離されました。デプロイ パッケージに診断機能に関する情報が含まれません。これ自体は良いことですが、 Azure 管理ポータルからデプロイすると診断機能が無効になっているので、実際の運用作業で VIP Swap する際には、PowerShell で診断機能を有効にする作業を忘れないように注意しましょう。今後、Azure 管理ポータルからも診断機能を有効にできると便利だと思います。

Global Azure Boot Camp 2015 in Japan に参加して LT してきました

先日、Global Azure Boot Camp 2015 in Japan に参加して、LTしてきました。

Azure App Services のネタが中心だったので、最近仕事でも使い始めた Web Apps の話をしました。LT の最後に紹介した孤独のグルメのアプリは、Azure Active Directory の認証を外して公開しました。スマートフォンで見ると、地図アプリとも連携できます。趣味でも使える Web Apps いいですね。

孤独のグルメ 巡礼サイト

グローバル感はあまりありませんでしたが(笑)、妖怪の話はゆるふわで面白かったですし、懇親会も含めて楽しい時間を過ごせました。クラウドの啓蒙には、コミュニティが果たす役割が重要だと感じていますので、微力ながら貢献していけたらいいなと思います。