Azure Web サイトに Ruby on Rails を簡単にインストールするためのスクリプトを使った場合に、特定の gem でインストールに失敗することが分かったので、おーみさんや No.1 に協力してもらって調査しました。
何で bundle install だと json のインストールに失敗するんやろ。gem 直叩きならいけるのに
— しばやん (@shibayan) 2014, 12月 5
ちなみに GitHub に Issue を登録して軽い気持ちで始めたのですが、かなり根が深い問題のようです。
なかなか原因らしきものに辿りつかず、混乱してきたのでまとめておきます。
無料だから?
最初は無料でのみ試していて、途中から占有に変えたら上手くデプロイ出来るようになった気がしました。
@kosmosebi 何故か無料だとエラーになって、標準・基本にしたらインスコに成功したりするんですが(
— しばやん (@shibayan) 2014, 12月 5
なので、無料では何らかの制限がかかっていたのではと思ったのですが、共有・占有でも失敗する時は失敗しました。どうやら Web サイトの SKU とは関係が無いみたいです。
bash だから?
先週末に品川で MVP Open Day があったので、両日共に北品川の芝社でパネポンをしていたわけですが、おーみさんから「DevKit と Git の bash でコンフリクトしてるんじゃないの?」と言われたのでバッチで書いて試してみました。
結果は bash の時と同じく上手くいったりいかなかったりでした。
バッチにしてみたけど、途中で失敗するのは変わらんな
— Takekazu Omi (@takekazuomi) 2014, 12月 8
関係ないですが、バッチへの移植を自分の方でやっていたら、おーみさんが先に移植を終わらせて PR を送ってくれました。初めての PR & マージでした。
CPU / メモリを使い過ぎだから?
Web サイトの無料を使うと CPU 時間やメモリ使用量に制限が付いているので、gem のビルドで CPU やメモリを使いすぎて、プロセスが止められてしまったのではないかと考えました。
CPU時間での制限はあったけど一気にってのはどうなんだろう
— こすもす.えび (@kosmosebi) 2014, 12月 8
CPU100%が結構長い間続くと思われます。
— Takekazu Omi (@takekazuomi) 2014, 12月 8
しかし、おーみさんが 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 が失敗するのか分からないのですが、特に根拠なくプロセスやパイプの作りすぎなのではないかと考えました。
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 に任せたい気持ちでいっぱいです。