しばやん雑記

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

Deno を Azure App Service (Windows / IIS) で動かしてみた

Twitter で記事が流れてきたり、通知が飛んできたので Deno というランタイムを知ったわけですが、どうやらそのままだと Windows の App Service 上では動かなかったらしいです。

App Service はサンドボックス環境で動くので多少制限が厳しいですが、エラー内容に違和感を持ったので自分でも試してみることにしました。

Deno インストール用の posh はそのままだと動かなかったので、Kudu から curl と 7za を使って手動で D:\home\.deno\bin に exe を置きました。こういうのは Site Extension で撒いても良い感じです。

おもむろに実行してみると確かに Panic が発生して立ち上がってくれません。

f:id:shiba-yan:20191217173355p:plain

Home Directory が取れないというのは謎いので、もうちょっと深堀してみます。

該当の Issue に当たってみると FOLDERID_Profile についてコメントが書かれていたので、ユーザープロファイル周りが怪しいと感じ始めました。

Rust のドキュメントには Windows の場合は SHGetKnownFolderPath を使っていると書かれていたので、App Service はデフォルトでユーザープロファイルを読み込んでないことが原因だと思いました。

Windows:
This function retrieves the user profile folder using SHGetKnownFolderPath.

dirs::home_dir - Rust

なので App Settings に WEBSITE_LOAD_USER_PROFILE の設定を追加します。あまり表には出てこないですが、証明書を読み込む場合などでたまに使うこともあるので知っておいて損はないです。

f:id:shiba-yan:20191217173509p:plain

これで Worker Process がユーザープロファイルを読み込むようになるので、Deno をもう一度叩いてみると Panic を発生させることなく立ち上がりました。

f:id:shiba-yan:20191217173629p:plain

プロセスが立ち上がってしまえば、後は HttpPlatformHandler でプロセスの管理と HTTP のプロキシをさせてしまえばよいので簡単です。

考え方は Node.js のデプロイの時と同じなので、特に難しいことはありません。

以下のような web.config を作成しました。HttpPlatformHandler の一般的な定義です。

example.ts は元記事のものをそのまま貰ってきて wwwroot 以下に保存しました。

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.webServer>
    <handlers>
      <add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified" />
    </handlers>
    <httpPlatform processPath="D:\home\.deno\bin\deno" arguments="--allow-net example.ts -p %HTTP_PLATFORM_PORT%" />
  </system.webServer>
</configuration>

これで全ての準備が整ったので、App Service にアクセスしてみると無事にページが返ってくるはずです。

f:id:shiba-yan:20191217174100p:plain

Process Explorer を開くとフロント用の w3wp の下に deno がぶら下がっていることが確認できます。

f:id:shiba-yan:20191217174110p:plain

コールドスタートに関しては Node.js よりも速い気がしたので、今後に期待したいです。

App Service では PATH を通すことは出来ないですが、Site Extension を使うとランタイムの追加は自由に出来るので、暇があれば作ってみたいところです。