Nginx(エンジンエックス)がIISを抜いて第2位のシェアをもつWebサーバーになったらしく、注目を浴びてます。そんなものをAzureで動かそうと思っていたら、すでに数ヶ月前に、たんたかさんのBlogに掲載されていました(nginxをWindows Azureで使ってみる | たんたか)。
とはいえ、ちょと違うアプローチでやってみようと思ったので、そのときのメモ。
Azureらしく
Azureらしくログなどは、ローカルストレージにはき出したいし、診断ログとしてBlobに転送したくなるのはAzurerだと思われますので、とりあえずは、その線で攻めてみましょう。
用意するもの
用意するものは以下。
- ngnix (nginx: download)
- sed
- Workerロール1つ
sedなんですけど、ファイルを書き換えたいためだけに用意します。そういった類のツールならなんでも構わないわけですが、Powershellとかでやるの面倒そうだったので。Gnu Windows版のバイナリは、他のGnu DLLを必要とするので、GNU sed with Oniguruma (Onigsed)を使ってます。試したら、sed.exe単独で動いたので(と思ったけどAzureには配置してないので、本当はなにか必要かも)
サービス構成ファイル
自動化するために、サービス構成ファイルを修正します。ポイントは以下。
- ProgramEntryPoint でnginxを起動 (なんとなく)
- スタートアップタスクで、ngnixの設定ファイルを修正するようにする。必要な情報は、RoleInstanceValue経由環境変数としてでコマンドに渡されます。
<?xml version="1.0" encoding="utf-8"?> <ServiceDefinition name="nginx" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition"> <WorkerRole name="WorkerRole1" vmsize="Small"> <Imports> <Import moduleName="Diagnostics" /> </Imports> <Startup> <Task commandLine="setup_test.cmd" executionContext="elevated" taskType="simple"> <Environment> <Variable name="xport"> <RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/Endpoints/Endpoint[@name='HttpIn']/@port" /> </Variable> <Variable name="xls"> <RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/LocalResources/LocalResource[@name='LocalStorage1']/@path" /> </Variable> </Environment> </Task> </Startup> <Runtime> <EntryPoint> <ProgramEntryPoint commandLine="nginx/nginx.exe" setReadyOnProcessStart="true" /> </EntryPoint> </Runtime> <Contents> <Content destination="nginx"> <SourceDirectory path="..\nginx-1.1.15" /> </Content> </Contents> <Endpoints> <InputEndpoint name="HttpIn" protocol="tcp" port="80" localPort="80" /> </Endpoints> <LocalResources> <LocalStorage name="LocalStorage1" cleanOnRoleRecycle="false" sizeInMB="1024" /> </LocalResources> </WorkerRole> </ServiceDefinition>
スタートアップタスク
エミュレータでのデバッグをかねて、スタートアップタスクはデバッグ用に間接的に呼び出します。以下のようにしておくと、コマンドプロンプトが開いた状態で中断するのでデバッグする場合に便利です。
以下、start_test.cmd
start /w setup.cmd
confファイルには、あらかじめ ###logs###などのようにプレースホルダを置いておいて、そこを置換してます。なにか別のうまい方法があるかもしれませんが、とりあえず。パスの区切り文字もスラッシュに変換してますけど本当に必要かは不明。
以下、start.cmd
del nginx\conf\nginx.conf set xlogs=%xls%logs set xtemp=%xls%temp mkdir %xlogs% mkdir %xtemp% sed.exe -e "s/##logs##/%xlogs:\=\/%\//g;s/##temp##/%xtemp:\=\/%\//g;s/##port##/%xport%/g" nginx\conf\nginx.conf.org > nginx\conf\nginx.conf
以下、ngnix.confファイル。ログ以外にも以外と、一時フォルダを指定する部分が多くて難儀しました。ただ、このファイルを読む前にログフォルダを作ろうとして警告がでますが、華麗にスルーです。worker_processなんかも、インスタンスサイズから自動的に設定したりするといいんでしょうかね。
worker_processes 1; working_directory ##temp##; error_log ##logs##error.log; pid ##logs##nginx.pid; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; client_body_temp_path ##temp##client_body_temp; proxy_temp_path ##temp##proxy_temp; fastcgi_temp_path ##temp##fastcgi_temp; scgi_temp_path ##temp##/scgi_temp; uwsgi_temp_path ##temp##uwsgi_temp; access_log ##logs##access.log; sendfile on; keepalive_timeout 65; server { listen ##port##; server_name localhost; location / { root html; index index.html index.htm; } error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } }
ログの出力
ログの出力は、diagnostics.wadcfg で行っています。エントリポイントを実行ファイルにしてしまったので、OnStartで実行できなくなってしまったので。
<?xml version="1.0" encoding="utf-8" ?> <DiagnosticMonitorConfiguration xmlns="http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration" configurationChangePollInterval="PT1M" overallQuotaInMB="4096"> <Directories bufferQuotaInMB="1000" scheduledTransferPeriod="PT1M"> <CrashDumps container="wad-crash-dumps" directoryQuotaInMB="256" /> <DataSources> <DirectoryConfiguration container="wad-custom" directoryQuotaInMB="256"> <LocalResource name="LocalStorage1" relativePath="logs"/> </DirectoryConfiguration> </DataSources> </Directories> </DiagnosticMonitorConfiguration>
エミュレーター上での実行
実行すると一端コマンドプロンプトで停止しますんで、環境変数とかみたり、デバッグっぽいことが可能です。exitで抜けると続行されます。
続行すると、ファイアーウォールの確認画面がでる場合があります。したがって、Azure上で実行するときはFirewallの設定をしないとだめです。今回はエミュレーター上での実行までなので、次回。
で実行されました。エミュレーターでの実行なので、ポート番号がちゃんと81番に書き換わってます。
ログもBLOBに転送されているようです。
問題と考察
デバッグを停止、アプリケーションが削除されてもngnix.exeが死にません。Compute Emulatorを停止しないと、プロセスが死んでくれません。OnStartでngnix.exeを起動して、OnStopでngnix.exe -s stopとかやるアプローチのほうが確実にサーバーを停止できるような気もしますが、せっかくProgramEntryPointがあるのにもったいない気もします。逆にAzure上では、問題にならないかも。
あとは、Webロールアクセラレータみたいに、confファイルの変更に対応したり、最初のコンテンツ展開をBLOBを経由して行ったり、まあ色々用途に合わせて実装してみるとおもしそうですが、用途があるんでしょうか。
まあ、色んなやり方が考えられるので、それを試すのは楽しいですね。実用に耐えるかともかくw。