結局Node.jsアプリケーションのデプロイはどうすればいいの？

node.js アプリケーションのデプロイをする時の選択肢が
あまりにもありすぎて、結局どうすればいいのよ？ってなったので、
いったん基礎からまとめてみます。

# デプロイとは何か？

アプリケーションのデプロイは大きく2つのフェーズに分かれます。

* **ファイルを所定の場所に置く**
* **置かれたファイルの再ローディング**

文章にするならば『ファイルを各サーバーの所定の場所におき、それらのファイルを再度ロードをする。』になると思います。

Webアプリケーションの場合
ファイルを所定の場所に置く前にテストを走らせたり
置いた後に静的ファイルを生成したりと、この２つの前後にはもっと色々なフェーズがありますが、
デプロイのタスクは、大きく分けてこの２つになります。

# ファイルを所定の場所に置く

サーバーにファイルを置く作業は、以下のような方法があります。

* FTP
* tar などで圧縮scpで転送して解凍
* rsync
* git

## capistrano(2系) の `deploy_via :copy` の場合

capistranoの2.xは、`deploy_via :copy`を設定することによって
デプロイ元でリポジトリからファイルを取ってきて
それをgzipして、デプロイ先に配布して展開します。
この場合、各デプロイ先にsshで接続出来るようにするだけでデプロイが可能になります。

## capistrano 3系の場合

capistrano3は `deploy_via` が無くなっています。
そのため上のやる場合はタスクを実装をする必要があります。

capistarno 3のデフォルトでは
まず各デプロイ先でデプロイ対象リポジトリを取得して
そこからgitの場合なら `git archive master | tar -x -C <デプロイ対象先>` と
対象のコミットの時点のものをデプロイ対象先に展開します。

## grunt-rsync の場合

[grunt-rsync](https://github.com/jedrichards/grunt-rsync)は`rsync`コマンドのラッパーです。
Gruntfile.js のタスクとしてrsyncが使えるようになります。

```javascript:Gruntfile.js
rsync: {
    options: {
        args: ["--verbose"],
        exclude: [".git*","*.scss","node_modules"],
        recursive: true
    },
     prod: {
        options: {
            src: "../dist/",
            dest: "/var/www/site",
            host: "user@live-host",
            syncDestIgnoreExcl: true
        }
    }
}

```

## pm2 の場合

Node.jsのプロセスマネジメントツールの[pm2](https://github.com/Unitech/pm2)ですが
`0.9.0`からデプロイコマンドがサポートされています。

`pm2 ecosystem`で必要なjsonファイルが作成されます。


```json:ecosystem.json
{
  "apps" : [{
    "name"      : "API",
    "script"    : "app.js",
    "env": {
      "COMMON_VARIABLE": "true"
    },
    "env_production" : {
      "NODE_ENV": "production"
    }
  },{
    "name"      : "WEB",
    "script"    : "web.js"
  }],
  "deploy" : {
    "production" : {
      "user" : "node",
      "host" : "212.83.163.1",
      "ref"  : "origin/master",
      "repo" : "git@github.com:repo.git",
      "path" : "/var/www/production",
      "post-deploy" : "pm2 startOrRestart ecosystem.json --env production"
    },
    "dev" : {
      "user" : "node",
      "host" : "212.83.163.1",
      "ref"  : "origin/master",
      "repo" : "git@github.com:repo.git",
      "path" : "/var/www/development",
      "post-deploy" : "pm2 startOrRestart ecosystem.json --env dev"
    }
  }
}
```

pm2もcapistrano3と同様に、デプロイ先でリポジトリを取得します。
`pm2 deploy ecosystem.json dev setup` で、対象のディレクトリでリポジトリを取得します。

あとは `pm2 deploy ecosystem.json dev` でデプロイができます。

ちなみに、一番後ろのステージ名はJSON`env_xxx` と連動していて、
ここに特定のステージでのみ設定したい環境変数を入れておきます。


#  置かれたファイルの再ローディング

ファイルを置いたら、おしまいというわけには行かず、
cssやjsの結合、圧縮や、アプリケーションのリスタートなどが必要になります。

この場合は

* デプロイタスクに、ファイル配置後にreload処理を入れる
* 対象ファイルを監視し、変更があった場合にreloadする

の2通りがあります。

## capistrano3 の場合

capistrano3では、下のような処理状況の前後に任意の処理を行うことが出来ます

```
deploy:starting    - start a deployment, make sure everything is ready
deploy:started     - started hook (for custom tasks)
deploy:updating    - update server(s) with a new release
deploy:updated     - updated hook
deploy:publishing  - publish the new release
deploy:published   - published hook
deploy:finishing   - finish the deployment, clean up everything
deploy:finished    - finished hook
```
http://capistranorb.com/documentation/getting-started/flow/


例えば、一連のデプロイ処理が終わった場合に、アプリケーションのリスタートをしたい場合は
以下のように、finished hook の後に再起動用の処理を書きます。

```ruby:config/deploy.rb

  after :finished, :restart do
    on roles(:web), in: :sequence, wait: 5 do
      # 再起動の処理を書く
    end
  end
```

## pm2 の `watch` を追加した場合

起動時のjsonファイルの中の設定や
`pm2 start app.js --name sampleApp —watch` と直接`--watch`と指定で
ファイルのwatchを行い、変更があれば再読み込みをすることが出来ます。
`pm2 describe <id>` でrestartされた回数やuptimeの時間を確認することが出来ます。

## forever の場合

`forever start app.js` でアプリを起動します。
すると、`forever list` でジョブが確認できるようになります。


```bash
$ forever list
info:    Forever processes running
data:        uid  command       script forever pid  logfile                         uptime
data:    [0] MEAN /usr/bin/node app.js 5006    5008 /home/vagrant/.forever/MEAN.log 0:0:0:10.670
```


jobを再起動する場合は、 `forever restart 0` とします。


# で、結局どうすればいいのか？


つまりは、最初の大きなフェーズの組み合わせによって、やり方がいくつもあったりします。
個人的には元々プロセスモニタリングツールの`pm2`に標準のデプロイ機能があるのが
素晴らしいのですが、ちょっと **複数環境同時にデプロイする方法が難しそう** なので
ファイルの配置は`capistrano` で、再起動が`pm2`。
最低限で良いならば`forever`あたりが妥当なんじゃないかなって思います。

----

でも、こういう話ってデプロイ時に
dockerのコンテナやらインスタンスを新規に作って
丸ごと差し替える時代が来そうなので、今は過渡期なんでしょうね。

# 追記

capistrano3がなんだかんだで使い勝手が良かったので、
[capistrano3のデプロイを把握する](http://qiita.com/taizo/items/afff46a260bd11588962)を書きました。