Friday, May 30, 2008

Capistrano 部署 Rails 项目速记

项目快上线了,以前一直采用传统的方式进行部署,从最早的 FTP 到后来的 SVN+SSH,既然现在是 Rails 项目,当然试一把 Capistrano。

安装

使用 Capistrano 进行部署只需要在本地机器安装 Capistrano 即可,Capistrano 通过 SSH 与服务器端进行交互。

gem install -y capistrano
当前最新版本是 2.3.0。

配置

Ubuntu 8.0.4 上 gem 包相关的 bin 目录并不在系统路径中,需要手工加入gem bin 路径:

$cat "export PATH=$PATH:/var/lib/gems/1.8/bin" >> .~/bashrc
$source ~/.bashrc

生成基础配置文件:

$cd RAILS_APP_DIR
$capify .

调整 config/deploy.rb 中相关配置项,并加入一行:

set :runner, "ACCOUNT_NAME"
用你服务器端的登录用户名取代 ACCOUNT_NAME,如果不设置此行,默认用户为 app,会导致设置失败。

初始化服务器端目录:

$cap deploy:setup
Capistrano > 2.3.0 开始默认启用 sudo,所以,服务器需要支持 sudo 支持,将 ACOUNT_NAME 加入到 sudo group, 并确认 /etc/sudoers 中设置:
# Uncomment to allow members of group sudo to not need a password
 %sudo ALL= ( ALL ) NOPASSWD: ALL

SSH 自动登录:

$ssh-keygen -t dsa
$chmod 700 ~/.ssh
$scp ~/.ssh/id_dsa.pub USER_NAME@REMOTE_SERVER
在服务器:
$cat id_dsa.pub >> ~/.ssh/authorized_keys
$rm -f id_dsa.pub

运行设定和依赖检查:

set :deploy_via, :remote_cache
set :runner, "josh"
depend :remote, :gem, "chronic", ">= 0.2.3"
depend :remote, :gem, "packet", ">= 0.1.5"
depend :remote, :command, "gnuplot"
depend :remote, :command, "svn"
depend :remote, :command, "mongrel_cluster_ctl" # make sure /usr/sbin in the $PATH
需要注意的是 debian 中的 mongrel_cluster_ctl 脚本在 /usr/sbin 下,而通过 ssh 获得的系统 $PATH 并没有包含 /usr/sbin 目录,需要修改 .ssh/environment 和 ssh 的相关配置加入 /usr/sbin 目录。 Mongrel && backgroundrb 启动配置
rails_env = "production"
set :mongrel_environment, "production"
set :mongrel_conf, "#{deploy_to}/current/config/mongrel_cluster.yml"

namespace :deploy do
  
  desc "Restart the Mongrel cluster and backgroundrb"
  task :restart, :roles => :app do
    stop
    start
  end
  desc "Start the mongrel cluster and backgroundrb"
  task :start, :roles => :app do
    mongrel.cluster.start
    start_backgroundrb
  end
  desc "Stop the mongrel cluster and backgroundrb"
  task :stop, :roles => :app do
    mongrel.cluster.stop
    stop_backgroundrb
  end

  desc "Start the backgroundrb server"
  task :start_backgroundrb , :roles => :app do
    begin
      puts "starting brb in folder #{current_path}"
      run "cd #{current_path} && RAILS_ENV=#{rails_env} nohup ./script/backgroundrb start > /dev/null 2>&1"
    rescue RuntimeError => e
      puts e
      puts "Problems starting backgroundrb – running already?"
    end
  end
  desc "Stop the backgroundrb server"
  task :stop_backgroundrb , :roles => :app do
    begin
      puts "stopping brb in folder #{current_path}"
      run "cd #{current_path} && ./script/backgroundrb stop"
    rescue RuntimeError => e
      puts e
      puts "Backgroundrb appears to be down already."
    end
  end
end

需要注意的是 Capistrano 每次 deploy 的时候会重新检出代码,用户上传文件需要单独做 link:
namespace :assets do
  task :symlink, :roles => :app do
    run <<-CMD
rm -rf #{release_path}/assets &&
ln -nfs #{shared_path}/assets #{release_path}/assets
CMD
  end
  after "deploy:update_code" , "assets:symlink"
  
  task :create_dirs, :roles => :app do
    %w(assets).each do |name|
      run "mkdir -p #{shared_path}/#{name}"
    end
  end
  after "deploy:setup", "assets:create_dirs"
end

参考文档: