使用Capistrano部署Node.js脚本
尝试部署Node.js时,我对于使用Capistrano还是使用shell脚本,以及什么是最佳实践等问题纠结了很久。
必须有两个基本要求。
-
- rollbackできるようにデプロイのバージョニング
- downtime無しで管理
需要
脚本本体+HTTP服务器
-
- nodejs
- coffee-script
进程管理
- pm2
部署
- capistrano
准备工作
软件包
$ npm i pm2@latest -g
宝石
$ bundle init
$ vim Gemfile
source 'https://rubygems.org'
gem 'capistrano', '~> 3.2.0'
gem 'capistrano-bundler', '~> 1.1.3'
gem 'capistrano-npm'
$ bundle
部署设置
初始化
$ cap init
帽子的设置
$ vim Capfile
# Load DSL and Setup Up Stages
require 'capistrano/setup'
# Includes default deployment tasks
require 'capistrano/deploy'
require 'capistrano/bundler'
require 'capistrano/npm'
require 'capistrano/console'
# Loads custom tasks from `lib/capistrano/tasks' if you have any defined.
Dir.glob('lib/capistrano/tasks/*.rake').each { |r| import r }
我要创建一个踢开PM2的脚本。
$ vim lib/capistrano/tasks/pm2.rake
require 'json'
require 'pry'
namespace :pm2 do
def start_app
within current_path do
execute :pm2, :start, fetch(:app_command)
end
end
def restart_app
within current_path do
execute :pm2, :restart, fetch(:app_command)
end
end
def stop_app
within current_path do
execute :pm2, :stop, fetch(:app_command)
end
end
def force_stop_app
within current_path do
execute :pm2, :stop, fetch(:app_command), '--force'
end
end
def graceful_reload_app
within current_path do
execute :pm2, :gracefulReload, fetch(:app_command)
end
end
def delete_app
within current_path do
execute :pm2, :delete, fetch(:app_command)
end
end
def app_status
within current_path do
ps = JSON.parse(capture :pm2, :jlist, fetch(:app_command))
if ps.empty?
return nil
else
# status: online, errored, stopped
return ps[0]["pm2_env"]["status"]
end
end
end
desc 'Start app'
task :start do
on roles(:app) do
start_app
end
end
desc 'Stop app'
task :stop do
on roles(:app) do
stop_app
end
end
desc 'Restart app gracefully'
task :restart do
on roles(:app) do
case app_status
when nil
info 'App is not registerd'
start_app
when 'stopped'
info 'App is stopped'
restart_app
when 'errored'
info 'App has errored'
restart_app
when 'online'
info 'App is online'
graceful_reload_app
end
end
end
desc 'Stop app immediately'
task :force_stop do
on roles(:app) do
force_stop_app
end
end
desc 'Delete app'
task :delete do
on roles(:app) do
delete_app
end
end
end
对于Capistrano的部署设置进行调整
$ vim config/deploy.rb
lock '3.2.1'
set :application, 'YOUR_APP_NAME'
set :app_command, 'egg.coffee'
set :repo_url, 'git@github.com:foo/foo.git'
set :deploy_to, "/var/www/#{fetch(:application)}"
set :log_level, :debug
set :linked_dirs, %w{ bin log node_modules }
set :default_env, { node_env: "local" }
namespace :deploy do
desc 'Restart application'
task :restart do
invoke 'pm2:restart'
end
after :publishing, :restart
end
创建一个名为target的本地(local)VM(虚拟机)作为目标。
$ vim config/deploy/local.rb
set :branch, ENV['BRANCH'] || 'master'
set :user, 'vagrant'
role :app, [ "#{fetch(:user)}@foo-server" ]
server 'foo-server', user: fetch(:user), roles: %w{ app }
将其发送到本地虚拟机中。
在虚拟机里安装PM2。
$ cap local deploy:check
$ cap local deploy
好
pm2的操作与rake相同。
附言
因为即使在PM2上,也可以使用Git进行部署(类似于Ruby中的Mina gem格式),所以可能使用这种方式更符合Node.js的理念。