しばやん雑記

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

Azure Web サイトで bundle install を実行するとビルドが必要な gem のインストールに失敗することがある

Azure Web サイトに Ruby on Rails を簡単にインストールするためのスクリプトを使った場合に、特定の gem でインストールに失敗することが分かったので、おーみさんや No.1 に協力してもらって調査しました。

ちなみに GitHub に Issue を登録して軽い気持ちで始めたのですが、かなり根が深い問題のようです。

Fail to install the native module (ex. json / thin) · Issue #2 · shibayan/AzureRubyDeployment · GitHub

なかなか原因らしきものに辿りつかず、混乱してきたのでまとめておきます。

無料だから?

最初は無料でのみ試していて、途中から占有に変えたら上手くデプロイ出来るようになった気がしました。

なので、無料では何らかの制限がかかっていたのではと思ったのですが、共有・占有でも失敗する時は失敗しました。どうやら Web サイトの SKU とは関係が無いみたいです。

bash だから?

先週末に品川で MVP Open Day があったので、両日共に北品川の芝社でパネポンをしていたわけですが、おーみさんから「DevKit と Git の bash でコンフリクトしてるんじゃないの?」と言われたのでバッチで書いて試してみました。

結果は bash の時と同じく上手くいったりいかなかったりでした。

関係ないですが、バッチへの移植を自分の方でやっていたら、おーみさんが先に移植を終わらせて PR を送ってくれました。初めての PR & マージでした。

CPU / メモリを使い過ぎだから?

Web サイトの無料を使うと CPU 時間やメモリ使用量に制限が付いているので、gem のビルドで CPU やメモリを使いすぎて、プロセスが止められてしまったのではないかと考えました。

しかし、おーみさんが start /low を使って優先度を変更してもダメだったと教えてくれました。

無料でもクオーターに引っかかるほど、ビルドでリソースを使うことは無いようです。

プロセス立ち上げ過ぎだから?

仕方ないので Gem::Ext 周りのソースコードを読むことにしたところ、どうやらバッククオートでのコマンド実行部分で落ちていることが分かりました。内部的には spawn を使っていて、そこで EINVAL が返ってきているようです。

remote: Errno::EINVAL
remote: Invalid argument - make  install 2>&1
remote: D:/home/site/wwwroot/bin/ruby/1.9.3/lib/ruby/site_ruby/1.9.1/rubygems/ext/builder.rb:55:in ``'
remote: D:/home/site/wwwroot/bin/ruby/1.9.3/lib/ruby/site_ruby/1.9.1/rubygems/ext/builder.rb:55:in `run'

新しくプロセスを立ち上げる部分で失敗していたのならば、make や make install で落ちるといった挙動の差にも納得がいきます。では、何故 spawn が失敗するのか分からないのですが、特に根拠なくプロセスやパイプの作りすぎなのではないかと考えました。

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

Kudu へ git push するとプロセスは上の画像のように立ち上がります。さらにビルドが必要な gem の場合には gcc や make が追加で立ち上がります。

極め付けが Kudu の Debug Console で発生したエラーです。ビルド中に発生しました。

[Win32Exception (0x80004005): Insufficient system resources exist to complete the requested service]
   System.Diagnostics.Process.CreatePipeWithSecurityAttributes(SafeFileHandle& hReadPipe, SafeFileHandle& hWritePipe, SECURITY_ATTRIBUTES lpPipeAttributes, Int32 nSize) +1815196
   System.Diagnostics.Process.CreatePipe(SafeFileHandle& parentHandle, SafeFileHandle& childHandle, Boolean parentInputs) +78
   System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo) +444
   System.Diagnostics.Process.Start() +6813874
   Kudu.Services.PersistentCommandController.CreateProcess(String connectionId, String shell) +608
   Kudu.Services.PersistentCommandController.StartProcess(String connectionId, String shell) +78

Process.CreatePipeWithSecurityAttributes を呼び出して、新しく cmd.exe を実行する部分でリソース不足の例外が投げられています。

となると、何らかの制限を Azure Web サイト側でかけている可能性が出てきました。ちなみに Debug Console から bundle install を実行してもエラーにはならないことから、I/O 周りの問題ではなさそうです。

カスタムデプロイスクリプトの実行時に立ち上がるプロセスを減らすことが出来れば、改善する可能性がありそうです。続きは @kosmosebi に任せたい気持ちでいっぱいです。