Ruby on Rails 终极部署方案 nginx+mina+puma
搭建工具介绍
Ruby on Rails
作为一款十分优秀的web开发框架,在当前web领域中慢慢占据了越来越重要,秉承rails快速开发的特点,很多快速部署rails的方案也越来越多。这篇文章中所选的方案是我个人认为十分优秀的部署方案。这套部署方案的结构是,nginx
作为反向代理服务器负责负载均衡,mina
作为自动化部署工具,puma
作为rails的web服务器
nginx
nginx
是一款优秀的代理服务器,其高效的性能已经得到了业界的广泛认可,相信作为web开发人员不会没听说过他的大名
mina
mina
是一款由ruby开发的自动化部署工具,其目的是为了简化每次rails代码提交时的部署,一键完成部署,杜绝了提交到git服务器后,又去服务器上git pull的情况
puma
puma
是一款专门针对rails的并发服务器,相对于passenger
,puma
可配置面更广,而且性能比passenger
更高,是rails web服务器的不二之选
部署前言
由于这篇文章需要很多铺垫,包括rails的安装下载,git的配置等等,需要读者自己去查阅资料或者查阅之前我写过的一些文章,如果期间有什么问题,请留言。。
mina
首先在你的rails项目的Gemfile
中加上
gem mina
运行bundle
安装 mina
,接着在你的rails项目根目录初始化mina
mina init
这是在你项目的config目录下会有一个deploy.rb
,配置deploy.rb
,列出重点部分,每一行的解释会附在代码的注释里
#服务器地址,是使用ssh的方式登录服务器
set :domain, 'root@192.168.0.103'
#服务器中项目部署位置
set :deploy_to, '/var/www/ruby_sample'
#git代码仓库
set :repository, 'https://github.com/gameFu/ruby_sample.git'
#git分支
set :branch, 'master'
# 中括号里的文件 会出现在服务器项目附录的shared文件夹中,这里加入了secrets.yml,环境密钥无需跟开发计算机一样
set :shared_paths, ['config/database.yml', 'log', 'config/secrets.yml']
# 这个块里面的代码表示运行 mina setup时运行的命令
task :setup => :environment do
# 在服务器项目目录的shared中创建log文件夹
queue! %[mkdir -p "#{deploy_to}/#{shared_path}/log"]
queue! %[chmod g+rx,u+rwx "#{deploy_to}/#{shared_path}/log"]
# 在服务器项目目录的shared中创建config文件夹 下同
queue! %[mkdir -p "#{deploy_to}/#{shared_path}/config"]
queue! %[chmod g+rx,u+rwx "#{deploy_to}/#{shared_path}/config"]
queue! %[touch "#{deploy_to}/#{shared_path}/config/database.yml"]
queue! %[touch "#{deploy_to}/#{shared_path}/config/secrets.yml"]
# puma.rb 配置puma必须得文件夹及文件
queue! %[mkdir -p "#{deploy_to}/shared/tmp/pids"]
queue! %[chmod g+rx,u+rwx "#{deploy_to}/shared/tmp/pids"]
queue! %[mkdir -p "#{deploy_to}/shared/tmp/sockets"]
queue! %[chmod g+rx,u+rwx "#{deploy_to}/shared/tmp/sockets"]
queue! %[touch "#{deploy_to}/shared/config/puma.rb"]
queue %[echo "-----> Be sure to edit 'shared/config/puma.rb'."]
# tmp/sockets/puma.state
queue! %[touch "#{deploy_to}/shared/tmp/sockets/puma.state"]
queue %[echo "-----> Be sure to edit 'shared/tmp/sockets/puma.state'."]
# log/puma.stdout.log
queue! %[touch "#{deploy_to}/shared/log/puma.stdout.log"]
queue %[echo "-----> Be sure to edit 'shared/log/puma.stdout.log'."]
# log/puma.stdout.log
queue! %[touch "#{deploy_to}/shared/log/puma.stderr.log"]
queue %[echo "-----> Be sure to edit 'shared/log/puma.stderr.log'."]
queue %[echo "-----> Be sure to edit '#{deploy_to}/#{shared_path}/config/database.yml'."]
end
#这个代码块表示运行 mina deploy时执行的命令
desc "Deploys the current version to the server."
task :deploy => :environment do
to :before_hook do
end
deploy do
#重新拉git服务器上的最新版本,即使没有改变
invoke :'git:clone'
#重新设定shared_path位置
invoke :'deploy:link_shared_paths'
invoke :'bundle:install'
invoke :'rails:db_migrate'
invoke :'rails:assets_precompile'
invoke :'deploy:cleanup'
to :launch do
queue "mkdir -p #{deploy_to}/#{current_path}/tmp/"
# queue "chown -R www-data #{deploy_to}"
queue "touch #{deploy_to}/#{current_path}/tmp/restart.txt"
end
end
end
这样一来mina的基本配置就完成,接下来只要将你开发环境的项目上传到git服务器,然后运行下面的命令就完成了
mina deploy
完成部署后,你就可以在指定的服务器目录下看到你的项目,目录结构如下
- current -当前版本目录也就是项目目录
- last_version -版本号
- releases/ -过去的版本
- scm/
- shared/ 先前shared_path所设定另外拉出来的文件都在这里
- tmp/
这里需要注意的几点
1.shared_path里面的文件不仅仅是表示这些文件会在服务器目录中出现在另外的目录里,也表示这些文件或者目录不会受到git版本库的控制,也就是说这些文件的配置必须在你服务器中手动去配置,这两个文件包括database.yml和secrets.yml,在shared/config目录下
2.针对deploy最好在服务器创建一个使用者,并针对他创建一个ssh authorized_keys,这里直接使用了root身份,参考centos7 服务器部署ssh证书授权登录,这样做能避免每次部署的时候都需要输入服务器账号密码
可能会遇到的问题
由于生产环境一般会搭配类似于postgresql
等成熟数据库,这里我就举出一个搭建postgresql
,首先是启动数据库时(centos 7下),如果遇到问题请使用下面的命令就能看到详细的错误信息
systemctl status postgresql-9.4.service -l
然后在跑mina deploy
时可能会报类似于这样的一个错误
Gem::LoadError: Specified 'postgresql' for database adapter, but the gem is not loaded. Add `gem 'pg'` to your Gemfile (and ensure its version is at the minimum required by ActiveRecord).
从错误信息上能很明显的看出是因为没有安装pg这个包导致的,但是有一种情况是明明在项目的Gemfile
上写上了pg但还是跑不过,造成这个的原因,可能是由于你的服务器环境缺少了pg的头文件导致的,如果是在centos下,只需要执行下面命令就能解决
yum install postgresql-libs
yum install postgresql-devel
Puma
首先在你的Gemfile
里加上
gem puma
然后在config目录下手动创建一个puma.rb
文件,配置puma.rb
文件
#!/usr/bin/env puma
#rails的运行环境
environment 'production'
threads 2, 64
workers 4
#项目名
app_name = "ruby_sample"
#项目路径
application_path = "/var/www/#{app_name}"
#这里一定要配置为项目路径下地current
directory "#{application_path}/current"
#下面都是 puma的配置项
pidfile "#{application_path}/shared/tmp/pids/puma.pid"
state_path "#{application_path}/shared/tmp/sockets/puma.state"
stdout_redirect "#{application_path}/shared/log/puma.stdout.log", "#{application_path}/shared/log/puma.stderr.log"
bind "unix://#{application_path}/shared/tmp/sockets/#{app_name}.sock"
activate_control_app "unix://#{application_path}/shared/tmp/sockets/pumactl.sock"
#后台运行
daemonize true
on_restart do
puts 'On restart...'
end
preload_app!
这里需要注意的地方
threads
-puma
的线程数,第一个参数是最小的线程数,第二个参数是最大线程数- bind - 这个指定的是
puma
运行时产生的socket
,后面nginx
会用到 - 这里所有对应的目录是在
deploy
配置中配置的,如果需要更改配置目录,deploy.rb
也需要相应的更改
Nginx
下载安装nginx
后,打开nginx
的配置文件nginx.conf
进行配置
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
#include /etc/nginx/conf.d/*.conf;
upstream deploy {
server unix:///var/www/ruby_sample/shared/tmp/sockets/ruby_sample.sock;
}
server {
listen 80;
server_name your.server.domain.ip; # change to match your URL
root /var/www/ruby_sample/current/public; # I assume your app is located at this location
location / {
proxy_pass http://deploy; # match the name of upstream directive which is defined above
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
location ~* ^/assets/ {
# Per RFC2616 - 1 year maximum expiry
expires 1y;
add_header Cache-Control public;
# Some browsers still send conditional-GET requests if there's a
# Last-Modified header or an ETag header even if they haven't
# reached the expiry date sent in the Expires header.
add_header Last-Modified "";
add_header ETag "";
break;
}
}
}
这里只需要注意的是
- upstream中 server 要配置成你在puma中bind的 socket就行了
- root要设置成你服务器项目的根目录,也就是
puma.rb
中的directory
接下里只需要重启nginx服务器,整个rails的环境就搭建完成了
nginx -s reload
如果完成了配置后访问站点是504,那么可能是两种情况,一是服务器防火墙问题,二是rails环境密钥的问题,请在使用passenger在Centos7部署nginx+Ruby on Rails中寻找答案