Visual Studioで作ったDjangoアプリをAzure App Serviceで動かす

Visual Studio 2015だとDjangoアプリをAzure App ServiceにPublishするだけで動くんですが、Visual Studio 2017、2019では色々手動で設定する必要があります。超面倒です。忘れないよう記録しておきます。

この情報は2019年1月時点の情報です。今後Azureの仕様が変更される可能性があります。

結論

いろいろ面倒くさいです。今はここまでしてDjangoでAzure App Serviceを使わなくていいかも。

Azure App ServiceにPython 3.6をインストールする

Azure App ServiceにデフォルトでインストールされているPythonのバージョンは3.4です。とりあえずPython 3.6をインストールしましょう。デフォルトのPython3.4だとインストールフォルダに書き込めないので以降の作業ができません。あと、新しい機能が動かなかったり、セキュリティ的にも不安です。

2018年の12月ごろにデフォルトPythonが3.6にバージョンアップされるというアナウンスがあったのですが、2019年1月現在まだ未反映の様です。もうちょっと彼らは頑張ってほしいです。

拡張機能」 -> 「追加」を選んで f:id:geroforce:20190109235914p:plain

->「拡張機能の選択」からインストールしたいPythonを選択します。 f:id:geroforce:20190110000044p:plain

x64でもx86でもどちらでもいいと思います。ここではx64にしました。x86でメモリ不足が発生するプログラムなどは、Azure App Serviceでは到底動かないのでまあどちらでもいいと思います。

python.exeパスの確認

拡張機能でインストールしたPythonのパスが後で必要になるので確認しておきます。 「高度なツール」->「移動」の順にクリックします。 f:id:geroforce:20190113022727p:plain

「Kudu」が開くので、「Debug console」->「CMD」の順にクリックします。 f:id:geroforce:20190113022823p:plain

コマンドプロンプト風の何かが表示されます。

f:id:geroforce:20190113023300p:plain

カレントディレクトリはD:\homeになっていると思います。「ls」コマンドでpython.exeを探しましょう。

f:id:geroforce:20190113023430p:plain

今回の場合はpython.exeは「D:\home\python364x64\python.exe」にインストールされていました。このパスを後で使用するので覚えておきましょう。

f:id:geroforce:20190113023633p:plain

web.configの編集

IISからDjangoが呼び出されるよう、Azure側のIISの設定を変更してやる必要があります。普段IISなんて触らないであろうパイソニスタにはこんなのわけわからんと思います。

プロジェクトフォルダ直下にweb.configを作ります。既にある場合は一旦削除して作り直しましょう。

作り方は、Visual Studio のソリューション エクスプローラーで、プロジェクトを右クリックして、[追加] > [新しい項目] を選択します。 表示されるダイアログ ボックスで、[Azure web.config (Fast CGI)] テンプレートを選択し、[OK] を選択します。

f:id:geroforce:20190110001053p:plain

次の行を

<add key="WSGI_HANDLER" value="app.wsgi_app"/>

次の行で置き換えます。

<add key="WSGI_HANDLER" value="django.core.wsgi.get_wsgi_application()"/>

その下に次の行を挿入してDjangoの設定ファイルを指定します。「プロジェクト名」はプロジェクト名で置き換えてください。今回の例ではDjangoWebProject2017ですね。(Visual StudioDjangoプロジェクトを作成すると、設定ファイル名はプロジェクト名になっているはずです。)

<add key="DJANGO_SETTINGS_MODULE" value="プロジェクト名.settings" />

以上編集後、次のような記述になります。

<appSettings>
    <add key="WSGI_HANDLER" value="django.core.wsgi.get_wsgi_application()"/>
    <add key="DJANGO_SETTINGS_MODULE" value="プロジェクト名.settings" />
    <add key="PYTHONPATH" value="D:\home\site\wwwroot"/>
    <add key="WSGI_LOG" value="D:\home\LogFiles\wfastcgi.log"/>
</appSettings>

handlersセクションのPython.exeのパスをさっき確認したパス「D:\home\python364x64\python.exe|D:\home\python364x64\wfastcgi.py」に置き換えます。

<handlers>
      <add name="PythonHandler" path="*" verb="*" modules="FastCgiModule" scriptProcessor="D:\home\python364x64\python.exe|D:\home\python364x64\wfastcgi.py" resourceType="Unspecified" requireAccess="Script"/>
</handlers>

Djangoプロジェクトの settings.py ファイルで、Azure App Serviceのドメインを ALLOWED_HOSTS に忘れずに追加します。まぁこれはAzureじゃなくてDjango特有の設定ですね。

ALLOWED_HOSTS = ['woohooapp.azurewebsites.net', 'localhost']

staticファイル転送用の設定

さらに面倒なのですが、staticファイルをIISに転送させるために、staticフォルダ直下にweb.configを作る必要があります。IISはフォルダごとに、設定ファイルが必要なようです。

f:id:geroforce:20190113031634p:plain

web.configの内容は以下に置き換えます。

<configuration>
  <system.webServer>
    <handlers>
      <clear />
      <add
          name="StaticFile"
          path="*" verb="*"
          modules="StaticFileModule,DefaultDocumentModule,DirectoryListingModule"
          resourceType="Either"
          requireAccess="Read" />
    </handlers>
    <staticContent>
      <mimeMap fileExtension=".*" mimeType="application/octet-stream" />
    </staticContent>
  </system.webServer>
</configuration>

ここで一旦サーバーに発行します。デプロイスロットを使用している場合は、発行先を間違えないように気を付けてください。別スロットに発行するとファイルがみつからなくて悩みます。

発行が完了すると、次のエラーメッセージが表示されますがそれでOKです。

The page cannot be displayed because an internal server error has occurred.

Pythonパッケージをインストールする

さて、先ほどのエラーはDjango等のパッケージがAzure側にインストールされていないため表示されています。これから手動で必要なPythonパッケージをインストールします。超面倒くさいですね。

マイクロソフトのご案内によると、手動でインストールしろとのことなので、とりあえずその通りやってみます。

ちなみにVisual Studio 2015の場合は、ローカルのvirtualenvのフォルダをそのままAzure側にアップロードして実行していたようなのですが、手動インストールに変更されたようです。他の環境からvirtualenvのフォルダをコピーしても動作する保証なんて全くありませんので、さすがに彼らもまずいと気付いたのでしょう。

パッケージをインストールするには、先ほど使用した「Kudu」の、「Debug console」->「CMD」を使います。

python.exeのインストールフォルダ(今回の場合はD:\home\python364x64)に移動して次のコマンドを実行します。

python -m pip install --upgrade -r /home/site/wwwroot/requirements.txt

requirements.txtには必要なpythonパッケージが列挙されています。requirements.txtの作成方法がわからなければググってください。

コマンドの実行画面は次の様になります。 f:id:geroforce:20190113025530p:plain

これで動くはず

さっきエラーメッセージが表示されたAzure App ServiceのURLをリロードするとDjangoのWebサイトが表示されるはずです。staticファイルがダウンロードできるかも確認しましょう。表示されない場合は一度Azure App Serviceを再起動してみると表示されるかもしれません。

ちなみに、アプリケーション設定画面の「プラットフォーム」は32bitにしても64bitにしても関係なく64bitのpythonが動きます。不思議です。「プラットフォーム」ってなんなんでしょうか? f:id:geroforce:20190113030527p:plain

所感その2

以上、いかがでしたか?超面倒くさくないですか?

IISを覚えろってことなのかも知れませんが、Nginxの方が私的には機能が豊富で便利なので移行したくないですね。 しかも今後Pythonパッケージを追加するたびに、インストールコマンドを手打ちですからね。

私はAzure App Serviceでホスティングするのはやめて、普通にバーチャルマシン+Dockerを使うことにしました。 今まであえてVisual StudioPython開発に挑戦してたんですが、やっぱり普通にPyCharmがいいと思います。

さらに設定は続く

今回、拡張機能でインストールしたPythonインスタンス数が16とかなり多めに設定されているという罠があって、メモリ消費多めのWebアプリかつAzure App Serviceの安いプランだと同時アクセスされた時にメモリがスワップして激遅になります。

Azure App Serviceのメトリックだとスワップしているのかしてないのか、よくわからないので原因を突き止めるのに時間がかかりました。そういう点でもシステムの情報を把握しやすいDockerの方が生のAzure App Serviceより良いのではと思いました。

で、このインスタンス数を変更するのも面倒です。

インスタンス数の設定

AzureのIISを設定するには、Windowsにインストールされている(or する)IISマネージャーを使ってAzureに接続することで以前はできてたらしいのですが、今は接続できません。正直全く意味がわかりませんが、AzureではIISを使うなというMicrosoftからのメッセージなのでしょうか。

現在、AzureのIISを設定するには、前述の「拡張機能」から「IIS Manager」を追加するのが手軽です。 f:id:geroforce:20190615214553p:plain

IIS Managerをクリックして、 f:id:geroforce:20190615215901p:plain

参照をクリックすると、 f:id:geroforce:20190615215930p:plain

このような画面でIISの設定を直接変更できます。とりあえず作者のshibayanさんに感謝です。 f:id:geroforce:20190615220033p:plain

で、この設定の中に、今回「拡張機能」で追加したpython3.6.4のエントリがあるので、maxInstancesの値をお好みの値に変えてやればOKです。

<application fullPath="D:\home\python364x64\python.exe" arguments="D:\home\python364x64\wfastcgi.py" maxInstances="16" idleTimeout="21600" instanceMaxRequests="10000000" signalBeforeTerminateSeconds="60">

お好みの値をどうやって探ればいいのかはわかりません。誰か教えてください。前述のとおりAzure App Serviceのメトリックだとメモリ消費量とかが分かりにくいです。

参考にしたshibayanさんのページです。 blog.shibayan.jp