node.js アプリケーションのデプロイをする時の選択肢が
あまりにもありすぎて、結局どうすればいいのよ?ってなったので、
いったん基礎からまとめてみます。
デプロイとは何か?
アプリケーションのデプロイは大きく2つのフェーズに分かれます。
- ファイルを所定の場所に置く
- 置かれたファイルの再ローディング
文章にするならば『ファイルを各サーバーの所定の場所におき、それらのファイルを再度ロードをする。』になると思います。
Webアプリケーションの場合
ファイルを所定の場所に置く前にテストを走らせたり
置いた後に静的ファイルを生成したりと、この2つの前後にはもっと色々なフェーズがありますが、
デプロイのタスクは、大きく分けてこの2つになります。
ファイルを所定の場所に置く
サーバーにファイルを置く作業は、以下のような方法があります。
- 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はrsync
コマンドのラッパーです。
Gruntfile.js のタスクとしてrsyncが使えるようになります。
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ですが
0.9.0
からデプロイコマンドがサポートされています。
pm2 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
でデプロイができます。
ちなみに、一番後ろのステージ名はJSONenv_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
例えば、一連のデプロイ処理が終わった場合に、アプリケーションのリスタートをしたい場合は
以下のように、finished hook の後に再起動用の処理を書きます。
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
でジョブが確認できるようになります。
$ 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のデプロイを把握するを書きました。