リズムのじかん

javascript、typescriptなど中心に書きます。

node.jsアプリのデプロイをCapistrano3で自動化する

Capistranoまだよく分かってないけど、ひとまずワンパス通ったのでメモです。 あまり自信はありませんが、ご参考になれば幸いです。

capistranoはv3.2.1を使っています。

やりたいこと

node.jsアプリケーションのデプロイ作業を自動化したい。

サーバ環境

デプロイの流れ

  1. [ローカル]デプロイ資産をまとめる(js,cssファイルのminifyなど)
  2. [ローカル]まとめたデプロイ資産をデプロイ用リポジトリへpush
  3. [リモート]デプロイ用リポジトリからpull
  4. [リモート]npm install --production
  5. [リモート]アプリケーション再起動

1はgruntでタスクを組んでいます。

3〜5はcapistranoで自動化しています。

1,2,3〜5の各処理を呼び出すメインのshellscriptを作り、デプロイ時にはメインのshellscriptを実行するだけにしています。

Capistranoのセットアップ

上記のデプロイの自動化を実現するため、もろもろセットアップします。

さくらVPSにnodeとかインストールする

アプリケーションを実行するのに必要な各種ミドルウェアを、さくらVPSにインストールします。 また今回はforeverでnodeを実行する前提です。

  • nvmインストール
  • nodeインストール
  • foreverインストール
  • mongodbインストール

etc...

詳細は省略。 ググればたくさん良い記事があるので、そちらを参照してください。

ローカルからさくらVPSへ鍵認証で接続できるようにする

人に説明できるほど詳しくないので、詳細はググってください。 ここではsakura_rsaという名前で鍵を作っています。 以下のように.ssh/configを書いて、ssh sakuraでパスワードなしで接続できるようにしています。

[ローカル] ~/.ssh/config

Host sakura
 Hostname 192.168.222.222
 Port 9999
 IdentityFile ~/.ssh/sakura_rsa
 User qop
 Protocol 2

デプロイ用リポジトリへ鍵認証で接続できるようにする

デプロイ用リポジトリにローカルとリモートから鍵認証で接続できるようにします。 手順の詳細はググってください。

f:id:chords:20141108195239p:plain

自分はbitbucketを使っているので、その例を上げます。 鍵の名前は「id_rsa」です。

[ローカル] ~/.ssh/config

Host bitbucket
 HostName bitbucket.org
 IdentityFile ~/.ssh/id_rsa
 User git
 Port 22
 TCPKeepAlive yes
 IdentitiesOnly yes

[リモート] さくらVPSからのssh接続は以下が分かり易いです。

http://www.xn--vps-073b3a72a.com/6.html

Capistrano3のインストール

Capistrano3をインストールします。 以下は自分のGemFileです。(バージョン指定してないけど)

source "https://rubygems.org"

gem "capistrano"
gem "capistrano_colors"

Capistrano3でデプロイタスクをコーディング

config/deploy/production.rbに、本番環境の設定を記載。

server '192.168.222.222',
  user: 'qop',
  roles: %w[app web db],
  ssh_options: {
    keys: [File.expand_path('~/.ssh/sakura_rsa')],
    port: 9999,
    forward_agent: true,
    auth_methods: %w(publickey)
  }

config/deploy.rbに、デプロイタスクを記載。

lock '3.2.1'

set :application, 'app_name'
set :repo_url, 'git@bitbucket.org:account_name/repository_name.git'
set :deploy_to, '/remote/deploy/path'

# User
set :user, 'qop'

# Default value for default_env is {}
set :node_env, (fetch(:node_env) || fetch(:stage))
set :default_env, { node_env: fetch(:node_env) }
  
# Default value for keep_releases is 5
set :keep_releases, 5

set :pid_file_name, 'xxxxx.pid'
set :pid_file, "/home/#{fetch(:user)}/.forever/pids/#{fetch(:pid_file_name)}"

namespace :deploy do

  desc 'Install node modules non-globally'
  task :npm_install do
    on roles(:app) do
      execute "cd #{release_path} && npm install --production"
    end
  end
 
  desc 'Start application'
  task :start do
    on roles(:app) do
      within current_path do
        execute :forever, 'start', '--pidFile', fetch(:pid_file), "#{current_path}/app.js"
      end
    end
  end
 
  desc 'Stop application'
  task :stop do
    on roles(:app) do
      within current_path do
        execute :forever, 'stop', "#{current_path}/app.js"
      end
    end
  end
 
  desc 'Restart application'
  task :restart do
    on roles(:app), in: :sequence, wait: 5 do
      within current_path do
        if test("[ -e #{fetch(:pid_file)} ]") && execute("kill -0 `cat #{fetch(:pid_file)}` > /dev/null 2>&1")
          execute :forever, 'restart', '--pidFile', fetch(:pid_file), "#{current_path}/app.js"
        else
          execute :forever, 'start', '--pidFile', fetch(:pid_file), "#{current_path}/app.js"
        end
      end
    end
  end
 
  after :publishing, :restart
 
  before :restart, 'deploy:npm_install'
 
end

デプロイ

bundle exec cap production deployで無事デプロイできました。