しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

人生で初めて Azure Cloud Services の RoleEntryPoint で IIS の設定を弄った話

Azure Cloud Services の Web Role を使って IIS の設定を変更してみたかったので、田口社長のブログを検索して、その中の 1 つを参考にしつつ試しました。

http://blogs.gine.jp/taka/archives/2846

さすが安心と信頼の田口社長、クラウドサービスは全て田口社長で安心。と思っていたら田口社長は海外出張中なので、半泣きになりながら自分で調べました。

ちなみに題材としては前に書いた IIS 8.5 のカスタムログの設定を自動化してみます。

必要な設定は URL Rewrite の allowedServerVariables への追加と、ログにサーバー変数を書きだす設定の追加となります。簡単そうに見えますね。

Startup Task として書く方法と RoleEntryPoint の OnStart で書く方法があるみたいですが、IIS の設定を変える場合には OnStart で実行した方が良いみたいでした。

スタートアップ処理のスタートアップ タスク段階では IIS が完全に構成されていない可能性があります。そのため、ロール固有のデータが使用できない場合があります。ロール固有のデータが必要なスタートアップ タスクは Microsoft.WindowsAzure.ServiceRuntime.RoleEntryPoint.OnStart を使用してください。

https://msdn.microsoft.com/ja-jp/library/azure/hh180155.aspx

なので RoleEntryPoint を使うことにしました。

Microsoft.Web.Administration.dll を参照に追加

IIS の設定を弄るのに必要な Microsoft.Web.Administration.dll は IIS がインストールされているディレクトリと同じ場所にあります。*1

注意点としては IIS のバージョンと Microsoft.Web.Administration.dll のバージョンは対応しているみたいなので、このあたりだけ注意したいところです。

更にローカルマシンの IIS によって古いバージョンだったり、HintPath の都合で GAC を参照したりするみたいなので、プロジェクトにコピーしておくのが無難かもしれません。

RoleEntryPoint を追加する

IIS の設定を弄るためには権限を与えておかないといけないので、ServiceDefinition.csdef に以下のような設定を追加しておきます。

<Runtime executionContext="elevated"></Runtime>

これで RoleEntryPoint の OnStart で IIS の設定を弄れるようになります。

実際に書いた WebRole のコードは以下のような感じです。

public class WebRole : RoleEntryPoint
{
    public override bool OnStart()
    {
        using (var serverManager = new ServerManager())
        {
            // CustomLogFields
            var site = serverManager.Sites[RoleEnvironment.CurrentRoleInstance.Id + "_Web"];

            site.LogFile.CustomLogFields.Clear();
            site.LogFile.CustomLogFields.Add("SESSION_VALUE", "SESSION_VALUE", CustomLogFieldSourceType.ServerVariable);

            // allowedServerVariables
            var config = serverManager.GetApplicationHostConfiguration();

            var allowedServerVariablesSection = config.GetSection("system.webServer/rewrite/allowedServerVariables");
            var allowedServerVariablesCollection = allowedServerVariablesSection.GetCollection();

            var addAllowedServerVariablesElement = allowedServerVariablesCollection.CreateElement("add");

            addAllowedServerVariablesElement["name"] = @"SESSION_VALUE";

            allowedServerVariablesCollection.Clear();
            allowedServerVariablesCollection.Add(addAllowedServerVariablesElement);

            serverManager.CommitChanges();
        }

        return base.OnStart();
    }
}

注意点としてはインプレース更新の場合、既に反映済みの applicationHost.config に対して処理を行ってしまうので、設定を削除してから追加するようにしました。本来なら該当する項目だけ削除するのが良いんでしょうが、今回はめんどくさいので全部消します。

これでデプロイすると applicationHost.config に設定が追加されていることが確認出来ます。

Azure Web Apps チームがどのように大量の VM を管理しているのか、事例を聞いてみたいです。

*1:つまり C:\Windows\System32\inetsrv とか