Rails 应用部署流水帐之 CentOS + Nginx + Passenger + RVM + Capistrano
- 查看服务器的系统信息
$ lsb_release -a
LSB Version: :base-4.0-amd64:base-4.0-noarch:core-4.0-amd64:core-4.0-noarch:graphics-4.0-amd64:graphics-4.0-noarch:printing-4.0-amd64:printing-4.0-noarch
Distributor ID: CentOS
Description: CentOS release 6.4 (Final)
Release: 6.4
Codename: Final
- Google search “CentOS install nginx”
搜到一篇文章: https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-centos-6-with-yum 姑且按照此文章介绍的步骤操作下去,
$ sudo yum install epel-release
$ sudo yum install nginx
- 启动 Nginx
$ sudo /etc/init.d/nginx start
可以通过 ps 命令查看 nginx 是否正常启动,
$ ps aux | grep nginx
root 23497 0.0 0.0 96436 2020 ? Ss 19:47 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx 23498 0.0 0.0 96824 2668 ? S 19:47 0:00 nginx: worker process
获取服务器 IP:
$ ifconfig eth0 | grep inet | awk '{ print $2 }'
- 安装 RVM
用 google 搜索 “centos rvm”, 然后搜到一篇文章: https://www.digitalocean.com/community/tutorials/how-to-install-ruby-on-rails-on-centos-6-with-rvm 按照此文章介绍的步骤操作下去,
$ sudo yum update
$ sudo yum install curl
$ curl -L get.rvm.io | bash -s stable
安装的过程中遇到两个警告:
* WARNING: You have RUBYLIB set in your current environment.
This may cause rubies to not work as you expect them to as it is not supported
by all of them If errors show up, please try unsetting RUBYLIB first.
* WARNING: You have '~/.profile' file, you might want to load it,
to do that add the following line to '/home/itadmin/.bash_profile':
source ~/.profile
在 ~/.bash_profile 里加入了 source ~/.profile
, 对于第一个警告暂时不理会。
接着是 load RVM, 在这里我们不能照搬文章的步骤了:
# If you ran the installer as root, run:
source /usr/local/rvm/rvm.sh
# If you installed it through a user with access to sudo:
source ~/.rvm/rvm.sh
在安装的过程中有一段文字,
Installing RVM to /home/someuser/.rvm/
Adding rvm PATH line to /home/itadmin/.profile /home/itadmin/.mkshrc /home/someuser/.bashrc /home/someuser/.zshrc.
Adding rvm loading line to /home/someuser/.profile /home/someuser/.bash_profile /home/someuser/.zlogin.
Installation of RVM in /home/someuser/.rvm/ is almost complete:
* To start using RVM you need to run `source /home/someuser/.rvm/scripts/rvm`
in all your open shell windows, in rare cases you need to reopen all shell windows.
注意: 我用 someuser 替代了实际的用户名。
于是加载 RVM 的命令如下,
$ source /home/someuser/.rvm/scripts/rvm
查看 RVM 依赖:
rvm requirements
在我的服务器上显示:
Checking requirements for centos.
Installing requirements for centos.
Installing required packages: libyaml-devel, libffi-devel..itadmin password required for 'yum install -y libyaml-devel libffi-devel':
安装这些依赖(在实际的操作中,我没有使用 rvmsudo, 而是在上面文字的冒号后面直接输入密码就安装好了依赖)
$ rvmsudo yum install -y libyaml-devel libffi-devel
- 安装 Ruby
我要安装的版本是: 1.9.3p448
$ rvm install 1.9.3-p448
最后我又安装了 1.9.3-p551
$ rvm install 1.9.3-p551
查看安装了哪些 ruby,
$ rvm list
输出,
rvm rubies
* ruby-1.9.3-p448 [ x86_64 ]
=> ruby-1.9.3-p551 [ x86_64 ]
# => - current
# =* - current && default
# * - default
- 安装 RubyGems
$ rvm rubygems current
- 安装 bundler
$ gem install bundler
- 克隆项目代码并且安装 gems
$ cd ~
$ mkdir railsapp
$ cd railsapp
$ git clone app_name_git_url
$ cd app_name
$ bundle
bundle install
的过程中出现了错误:
Installing debugger-ruby_core_source 1.2.0
Gem::Ext::BuildError: ERROR: Failed to build gem native extension
An error occurred while installing debugger (1.5.0), and Bundler cannot continue.
Make sure that `gem install debugger -v '1.5.0'` succeeds before bundling.
修复方法:
$ gem install debugger
$ bundle
- 安装配置 Passenger
使用 google 搜索 “centos passenger”, 按照 https://www.digitalocean.com/community/tutorials/how-to-deploy-rails-apps-using-passenger-with-nginx-on-centos-6-5 写的步骤操作:
$ sudo yum groupinstall -y 'development tools'
$ sudo yum install -y nodejs
$ gem install passenger
$ rvmsudo passenger-install-nginx-module
Nginx 被重新安装到了 /opt/nginx
- 创建 Nginx 管理脚本
$ nano /etc/rc.d/init.d/nginx
#!/bin/sh
. /etc/rc.d/init.d/functions
. /etc/sysconfig/network
[ "$NETWORKING" = "no" ] && exit 0
nginx="/opt/nginx/sbin/nginx"
prog=$(basename $nginx)
NGINX_CONF_FILE="/opt/nginx/conf/nginx.conf"
lockfile=/var/lock/subsys/nginx
start() {
[ -x $nginx ] || exit 5
[ -f $NGINX_CONF_FILE ] || exit 6
echo -n $"Starting $prog: "
daemon $nginx -c $NGINX_CONF_FILE
retval=$?
echo
[ $retval -eq 0 ] && touch $lockfile
return $retval
}
stop() {
echo -n $"Stopping $prog: "
killproc $prog -QUIT
retval=$?
echo
[ $retval -eq 0 ] && rm -f $lockfile
return $retval
}
restart() {
configtest || return $?
stop
start
}
reload() {
configtest || return $?
echo -n $”Reloading $prog: ”
killproc $nginx -HUP
RETVAL=$?
echo
}
force_reload() {
restart
}
configtest() {
$nginx -t -c $NGINX_CONF_FILE
}
rh_status() {
status $prog
}
rh_status_q() {
rh_status >/dev/null 2>&1
}
case "$1" in
start)
rh_status_q && exit 0
$1
;;
stop)
rh_status_q || exit 0
$1
;;
restart|configtest)
$1
;;
reload)
rh_status_q || exit 7
$1
;;
force-reload)
force_reload
;;
status)
rh_status
;;
condrestart|try-restart)
rh_status_q || exit 0
;;
*)
echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
exit 2
esac
启动 Nginx
$ /etc/rc.d/init.d/nginx start
- 配置 capfile
$ sudo chown myuser /var/www
$ mkdir -p /var/www/staging/shared
$ mkdir -p /var/www/staging/releases
capfile 内容如下:
default_run_options[:pty] = true
set :application, "My Site"
set :repository, "git@github.com:My/site"
require 'bundler/capistrano'
set :scm, :git
set :user, "myuser"
ssh_options[:forward_agent] = true
set :branch, "staging"
set :keep_releases, 10
set :use_sudo, false
set :deploy_to, "/var/www"
set :deploy_via, :remote_cache
server "localhost", :app, :web
set :shared, %w{
config/database.yml
log
public/data
public/assets
public/files
public/company_documents
}
after "deploy:setup", "deploy:steup_settings_local_yml"
before "deploy:update", "god:terminate_if_running"
after "deploy:update", "god:start"
after 'deploy:create_symlink', 'deploy:create_my_symlink'
after "deploy:restart", "deploy:cleanup"#, "deploy:copy_resque_assets"
# If you are using Passenger mod_rails uncomment this:
# if you're still using the script/reapear helper you will need
# these http://github.com/rails/irs_process_scripts
namespace :deploy do
# task :start {}
# task :stop {}
# task :restart, :roles => :app, :except => { :no_release => true } do
# run "#{try_sudo} touch #{File.join(current_path,'tmp','restart.txt')}"
# end
desc 'restart passenger'
task :restart do
run "touch #{current_path}/tmp/restart.txt"
run 'curl -k https://localhost/distributor_contact?login=master'
run 'curl -k https://localhost/distributor_contact?login=master'
run 'curl -k https://localhost/distributor_contact?login=master'
run 'curl -k https://localhost/distributor_contact?login=master'
run 'curl -k https://localhost/distributor_contact?login=master'
run 'curl -k https://localhost/distributor_contact?login=master'
run 'curl -k https://localhost/distributor_contact?login=master'
run 'curl -k https://localhost/distributor_contact?login=master'
end
desc "Symlinks"
task :create_my_symlink, :roles => :app do
run "ln -nfs #{deploy_to}/shared/config/avalara.yml #{release_path}/config/avalara.yml"
run "ln -nfs #{deploy_to}/shared/config/ipay88.yml #{release_path}/config/ipay88.yml"
run "ln -nfs #{deploy_to}/shared/config/couch.yml #{release_path}/config/couch.yml"
run "ln -nfs #{deploy_to}/shared/config/hyperwallet.yml #{release_path}/config/hyperwallet.yml"
run "ln -nfs #{deploy_to}/shared/config/uniteller.yml #{release_path}/config/uniteller.yml"
run "ln -nfs #{deploy_to}/shared/config/captcha.yml #{release_path}/config/captcha.yml"
run "ln -nfs #{deploy_to}/shared/config/ipay88.yml #{release_path}/config/ipay88.yml"
run "ln -nfs #{deploy_to}/shared/config/paynamics_wpf.yml #{release_path}/config/paynamics_wpf.yml"
run "ln -nfs #{deploy_to}/shared/config/mongoid.yml #{release_path}/config/mongoid.yml"
run "ln -nfs #{deploy_to}/shared/config/database.yml #{release_path}/config/database.yml"
run "ln -nfs #{deploy_to}/shared/config/redis_store.yml #{release_path}/config/redis_store.yml"
run "ln -nfs #{deploy_to}/shared/config/settings.local.yml #{release_path}/config/settings.local.yml"
run "ln -nfs #{deploy_to}/shared/public/data #{release_path}/public/data"
run "ln -nfs #{deploy_to}/shared/images/oglogo.png #{release_path}/public/images/oglogo.png"
run "ln -nfs #{deploy_to}/shared/public/company_documents #{release_path}/public/company_documents"
run "ln -nfs #{deploy_to}/shared/public/assets #{release_path}/public/assets"
run "ln -nfs #{deploy_to}/shared/public/files #{release_path}/public/files"
run "ln -nfs #{deploy_to}/shared/public/star_achiever #{release_path}/public/star_achiever"
run "ln -nfs #{deploy_to}/shared/reports #{release_path}/reports"
end
desc 'setup settings.local.yml'
task :steup_settings_local_yml, :roles => :app do
put File.read("config/settings.local.yml"), "#{shared_path}/config/settings.local.yml"
end
desc "Copy resque-web assets into public folder"
task :copy_resque_assets do
target = File.join(release_path, 'public', 'resque')
run "cp -r #{`cd #{release_path} && bundle show resque`.chomp}/lib/resque/server/public #{target}"
end
end
namespace :god do
def god_is_running
!capture("#{god_command} status >/dev/null 2>/dev/null || echo 'not running'").start_with?('not running')
end
def god_command
"cd #{current_path}; bundle exec god"
end
desc "Stop god"
task :terminate_if_running do
if god_is_running
run "#{god_command} terminate"
end
end
desc "Start god"
task :start do
config_file = "#{current_path}/csite/god/resque.god"
environment = { :RAILS_ENV => rails_env, :RAILS_ROOT => current_path }
run "#{god_command} -c #{config_file}", :env => environment
end
end
- 启动应用
$ cap deploy
这个笔记是流水帐的记法属于做到哪写到哪的风格,所以看起来有些凌乱,现在对其做一个梳理提炼。
首先声明一个约定,我使用 myuser
作为实际用户的别名, mysite
作为实际站点的别名。
1. 确认部署蓝图
- 服务器: CentOS
- web 服务器: Nginx
- 应用服务器: Passenger
- Ruby 版本管理器: RVM
- 部署工具: Capistrano
2. 安装系统相关软件和库
$ sudo yum update
$ sudo yum install epel-release
$ sudo yum install curl
$ sudo yum groupinstall -y 'development tools'
$ sudo yum install -y nodejs
安装配置 RVM
$ curl -L get.rvm.io | bash -s stable
这里可能会出现警告,根据安装过程中输出的提示操作即可。
加载 RVM
$ source /home/myuser/.rvm/scripts/rvm
查看 RVM 依赖
$ rvm requirements
如果提示需要安装某些库,直接敲 Enter 键安装即可,
Checking requirements for centos.
Installing requirements for centos.
Installing required packages: libyaml-devel, libffi-devel..itadmin password required for 'yum install -y libyaml-devel libffi-devel':
安装 Ruby
安装你需要的 ruby 版本即可, 我使用的是 1.9.3-p551,
$ rvm install 1.9.3-p551
安装 RubyGems 和 Bundler
$ rvm rubygems current
$ gem install bundler
克隆项目并且安装 gems
$ cd ~
$ mkdir railsapp
$ cd railsapp
$ git clone app_name_git_url
$ cd app_name
$ bundle install
安装配置 Passenger
$ gem install passenger
$ rvmsudo passenger-install-nginx-module
Nginx 被安装到了 /opt/nginx 目录。
Nginx 的管理脚本在 /etc/rc.d/init.d/nginx
Nginx 的配置文件在 /opt/nginx/conf/nginx.conf
在这里我贴出 Nginx 的配置文件, 有两个, 第一个是 /opt/nginx/conf/nginx.conf,
worker_processes 4;
error_log /opt/nginx/logs/error.log;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
passenger_root /home/myuser/.rvm/gems/ruby-1.9.3-p551/gems/passenger-5.0.5;
passenger_ruby /home/myuser/.rvm/gems/ruby-1.9.3-p551/wrappers/ruby;
passenger_max_pool_size 30;
passenger_pool_idle_time 90;
passenger_max_requests 500;
client_max_body_size 20M;
include /opt/nginx/conf/mime.types;
default_type application/octet-stream;
access_log /opt/nginx/logs/access.log;
sendfile on;
keepalive_timeout 65;
gzip on;
gzip_disable "MSIE [1-6]\.(?!.*SV1)";
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_proxied any;
gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;
include /opt/nginx/conf/sites-enabled/localhost;
ssl_ciphers RC4:HIGH:!aNULL:!MD5:!kEDH;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
}
# 这些都是和 Passenger 相关的。
passenger_root /home/myuser/.rvm/gems/ruby-1.9.3-p551/gems/passenger-5.0.5;
passenger_ruby /home/myuser/.rvm/gems/ruby-1.9.3-p551/wrappers/ruby;
passenger_max_pool_size 30;
passenger_pool_idle_time 90;
passenger_max_requests 500;
第二个文件是 /opt/nginx/conf/sites-enabled/localhost, 这个文件里包含实际站点的配置内容,
server {
listen 443;
server_name notforpublic.mysite.com www.mysite.com;
proxy_set_header X-Forwarded-Proto https;
ssl on;
ssl_certificate /etc/ssl/certs/demo.mysite.com.crt;
ssl_certificate_key /etc/ssl/certs/demo.mysite.com.key.pem;
access_log logs/organogold443.access.log;
root /var/www/current/public;
location /distributor_contact {
return 200 "{}";
access_log off;
}
passenger_enabled on;
rails_env production;
passenger_max_preloader_idle_time 0;
location ~ /\.ht {
deny all;
}
}
server {
listen 9449;
server_name notforpublic.mysite.com
proxy_set_header X-Forwarded-Proto https;
ssl on;
ssl_certificate /etc/ssl/certs/demo.mysite.com.crt;
ssl_certificate_key /etc/ssl/certs/demo.mysitecom.key.pem;
access_log logs/organogold7443.access.log;
root /var/www/staging/current/public;
passenger_enabled on;
rails_env production;
passenger_max_preloader_idle_time 0;
}
# 这些都是和 Passenger 相关的。
passenger_enabled on;
rails_env production;
配置 Capfile
Capfile 是跟着项目走的, 其中的内容已经在流水帐里贴出了。
创建部署目录以及相关目录, 具体创建哪些目录需要看 config/deploy 文件里的配置
$ sudo mkdir /var/www
$ chown myuser /var/www
$ mkdir /var/www/staging
$ mkdir /var/www/staging/shared
$ cp -r /path/to/shared /var/www/staging/shared
$ mkdir /var/www/staging/releases
启动项目,
$ cd /home/myuser/railsapp/app_name
$ cap deploy