Rendrで作られたnode.jsアプリをminaでデプロイする

Rendrで新しくアプリを作ろうとしていて、rendr-cliで プロジェクトの雛形を作ったので、では実際にデプロイどうしようと考えた時にminaを使ってやってみたので その際のメモ。

手順としては、

  • rendrアプリをデーモン化して稼働させるためにforeverで動く様にする
  • minaでデプロイするタスクを書く

minaのデプロイはここあたりに書いているので詳細は省略。

foreverでデーモン化する

rendr-cliで作られたアプリのベースには既にgruntを使って開発環境用のサーバを 稼働させたり、stylusをコンパイルするためのgruntタスクが既に用意されていて、開発環境であれば

$ grunt server

とすれば、一通りのコンパイルと手元でサーバ起動、そしてstyles等の更新を監視して再コンパイルをしてくれるのですが、 これをこのままproduction環境で動かす訳にはいかないので、foreverでデーモン起動、停止をする タスクを書き足します。

まず、foreverが使える様にするためにアプリケーションプロジェクトのルートで、

$ npm install forever --save

としてforeverをインストール。 --save を付けて package.json も更新します。

次にrendr-cliが作った Gruntfile.js にforeverを使ったアプリケーション起動、停止をするタスクを足します。

// Gruntfile.js
grunt.registerTask('startProductionNode', function () {
    grunt.util.spawn({
      cmd: 'node',
      args: ['./node_modules/forever/bin/forever', 'start', 'index.js'],
      opts: {
        stdio: 'inherit'
      }
    }, function () {
      grunt.fail.fatal(new Error("forever quit"));
    });
  });

  grunt.registerTask('stopProductionNode', function () {
    grunt.util.spawn({
      cmd: 'node',
      args: ['./node_modules/forever/bin/forever', 'stop', 'index.js'],
      opts: {
        stdio: 'inherit'
      }
    }, function () {
      grunt.fail.fatal(new Error("forever quit"));
    });
  });

ここまで設定すると、アプリケーションをデーモン化して起動、停止ができます。

起動は、*1

$ grunt startProductionNode
Running "startProductionNode" task

warn:    --minUptime not set. Defaulting to: 1000ms
warn:    --spinSleepTime not set. Your script will exit if it does not stay up for at least 1000ms
info:    Forever processing file: index.js

Done, without errors.

一方停止は、

$ grunt stopProductionNode
Running "stopProductionNode" task

info:    Forever stopped process:
data:        uid  command                                            script   forever pid   logfile                             uptime
[0] sKj9 /Users/hideack/.nodebrew/node/v0.11.11/bin/node index.js 34008   34012 /Users/hideack/.forever/sKj9.log 0:0:1:15.836

Done, without errors.

これで、Rendrアプリをデーモン化して動かせる様になりました。

minaでのデプロイ

続けて実際にデプロイする際には、リポジトリから最新のコードを取ってきてstylus等をコンパイルして上で作ったgruntタスクを利用してアプリケーションを再起動させます。

gitリポジトリから引っ張ってくるところまではRubyのアプリケーションの場合と同様ですが、アプリケーションサーバの起動のタスクは独自で書く必要があるので以下の様なタスクを書き足します。

# rendr
# =============
namespace :rendr do
  task :compile do
    queue 'echo "-----> Start compile tasks."'
    queue! %{
      cd #{deploy_to}/current
      grunt compile
    }
  end

  task :start do
    queue 'echo "-----> Start server."'
    queue! %{
      cd #{deploy_to}/current
      grunt startProductionNode
    }
  end

  task :stop do
    queue 'echo "-----> Stop server."'
    queue! %{
      cd #{deploy_to}/current
      grunt stopProductionNode
    }
  end
end

desc "Deploys the current version to the server."
task :deploy => :environment do
  deploy do
    # Put things that will set up an empty directory into a fully set-up
    # instance of your project.
    invoke :'git:clone'
    invoke :'deploy:link_shared_paths'

    to :launch do
      invoke :'rendr:compile'
      invoke :'rendr:stop'
      invoke :'rendr:start'
      queue "touch #{deploy_to}/tmp/restart.txt"
    end
  end
end

ここまで準備できれば手元から、

$ bundle exec mina deploy

でRendrアプリのデプロイ&アプリの再起動*2が行えます。

*1:warning出ているのはアプリのプロセスの監視条件を設定していないためなので設定するべきですね...

*2:ただこのままではgracefulな再起動になってないので今後直していく予定