介绍
当你准备部署你的 Ruby on Rails 应用程序时,有许多有效的设置需要考虑。本教程将帮助你在 Ubuntu 14.04 上部署你的 Ruby on Rails 应用程序的生产环境,使用 PostgreSQL 作为数据库,并使用 Unicorn 和 Nginx。
Unicorn 是一个应用服务器,类似于 Passenger 或 Puma,它使你的 Rails 应用程序能够并发处理请求。由于 Unicorn 不是设计为直接被用户访问,我们将使用 Nginx 作为反向代理,用于在用户和你的 Rails 应用程序之间缓冲请求和响应。
先决条件
本教程假设你已经在 Ubuntu 14.04 服务器上以部署应用程序的用户身份安装了以下软件:
- 使用 rbenv 的 Ruby on Rails
- 带有 Rails 的 PostgreSQL
如果你还没有进行设置,请按照上面链接的教程进行设置。我们将假设你的用户名称为 deploy。
另外,本教程不涵盖如何设置开发或测试环境。如果你需要帮助,请按照 PostgreSQL with Rails 教程中的示例进行设置。
创建 Rails 应用程序
理想情况下,你已经有一个要部署的 Rails 应用程序。如果是这种情况,你可以跳过本节,并在跟随过程时进行适当的替换。如果没有,第一步是创建一个使用 PostgreSQL 作为其数据库的新 Rails 应用程序。
以下命令将创建一个名为 “appname” 的新 Rails 应用程序,该应用程序将使用 PostgreSQL 作为数据库。请随意用其他内容替换下面突出显示的 “appname”:
rails new appname -d postgresql
然后切换到应用程序目录:
cd appname
让我们花点时间来创建将在你的 Rails 应用程序的生产环境中使用的 PostgreSQL 用户。
创建生产数据库用户
为了简化事务,让我们将生产数据库用户的名称与你的应用程序名称相同。例如,如果你的应用程序名为 “appname”,你应该像这样创建一个 PostgreSQL 用户:
sudo -u postgres createuser -s appname
我们希望设置数据库用户的密码,因此像这样进入 PostgreSQL 控制台:
sudo -u postgres psql
然后像这样为数据库用户(在示例中为 “appname”)设置密码:
\password appname
输入你想要的密码并确认。
使用以下命令退出 PostgreSQL 控制台:
\q
现在我们准备使用正确的数据库连接信息配置你的应用程序。
配置数据库连接
确保你在应用程序的根目录中(cd ~/appname
)。
使用你喜欢的文本编辑器打开应用程序的数据库配置文件。我们将使用 vi:
vi config/database.yml
在 default
部分下,找到一行写着 “pool: 5” 的行,并在其下添加以下行(如果尚不存在):
host: localhost
如果你滚动到文件底部,你会注意到 production
部分被设置如下:
username: appname password: <%= ENV['APPNAME_DATABASE_PASSWORD'] %>
如果你的生产用户名与之前创建的数据库用户不匹配,现在设置它。
请注意,数据库密码被配置为通过环境变量 APPNAME_DATABASE_PASSWORD
读取。最佳实践是将生产密码和密钥保存在应用程序代码库之外,因为如果你使用分布式版本控制系统(如 Git),它们很容易被暴露。接下来,我们将介绍如何使用环境变量设置数据库身份验证。
安装 rbenv-vars 插件
在部署生产 Rails 应用程序之前,你应该使用环境变量设置生产密钥和数据库密码。管理环境变量的一种简单方法是使用 rbenv-vars 插件,我们可以使用它在运行时将密码和密钥加载到我们的应用程序中。
要安装 rbenv-vars 插件,只需切换到 .rbenv/plugins
目录并从 GitHub 克隆它。例如,如果 rbenv 安装在你的主目录中,运行以下命令:
cd ~/.rbenv/plugins git clone https://github.com/sstephenson/rbenv-vars.git
设置环境变量
现在 rbenv-vars 插件已安装,让我们设置所需的环境变量。
首先,生成用于验证已签名 cookie 完整性的密钥:
cd ~/appname rake secret
复制生成的密钥,然后使用你喜欢的编辑器打开 .rbenv-vars
文件。我们将使用 vi:
vi .rbenv-vars
你在这里设置的任何环境变量都可以被你的 Rails 应用程序读取。
首先,设置 SECRET_KEY_BASE
变量如下(用你刚生成和复制的密钥替换下面突出显示的文本):
SECRET_KEY_BASE=your_generated_secret
接下来,设置 APPNAME_DATABASE_PASSWORD
变量如下(用你的应用程序名称替换下面突出显示的 “APPNAME”,用你的生产数据库用户密码替换 “prod_db_pass”):
APPNAME_DATABASE_PASSWORD=prod_db_pass
保存并退出。
你可以通过运行以下命令使用 rbenv-vars 插件查看为你的应用程序设置了哪些环境变量:
rbenv vars
如果你更改了密钥或数据库密码,请更新你的 .rbenv-vars
文件。请注意保持此文件私密,并不要将其包含在任何公共代码库中。
创建生产环境数据库
现在你的应用程序已经配置好与 PostgreSQL 数据库通信,让我们来创建生产环境数据库:
RAILS_ENV=production rake db:create
生成控制器
如果你正在按照示例进行操作,我们将生成一个脚手架控制器,这样我们的应用程序就有东西可以展示了:
rails generate scaffold Task title:string note:text
现在运行以下命令来更新生产环境数据库:
RAILS_ENV=production rake db:migrate
预编译资源
此时,应用程序应该可以运行,但是你需要预编译它的资源,以便任何图片、CSS 和脚本都能加载。为此,请运行以下命令:
RAILS_ENV=production rake assets:precompile
测试应用程序
要测试应用程序是否正常工作,你可以运行生产环境,并将其绑定到服务器的公共 IP 地址(替换为你服务器的公共 IP 地址):
RAILS_ENV=production rails server --binding=server_public_IP
现在在 Web 浏览器中访问以下 URL:
http://server_public_IP:3000/tasks
如果一切正常,你应该能看到这个页面:
!Tasks controller
返回到你的 Rails 服务器,按 Ctrl-c
停止应用程序。
安装 Unicorn
现在我们准备安装 Unicorn。
一个简单的方法是将它添加到你的应用程序的 Gemfile
中。在你喜欢的编辑器中打开 Gemfile
(确保你在应用程序的根目录下):
vi Gemfile
在文件末尾添加以下行来添加 Unicorn gem:
gem 'unicorn'
保存并退出。
要安装 Unicorn 和任何未解决的依赖项,请运行 Bundler:
bundle
Unicorn 现在已安装,但我们需要对其进行配置。
配置 Unicorn
让我们将 Unicorn 配置添加到 config/unicorn.rb
。在文本编辑器中打开该文件:
vi config/unicorn.rb
将以下配置复制并粘贴到文件中:
# 设置应用程序路径 app_dir = File.expand_path("../..", __FILE__) shared_dir = "#{app_dir}/shared" working_directory app_dir # 设置 Unicorn 选项 worker_processes 2 preload_app true timeout 30 # 设置套接字位置 listen "#{shared_dir}/sockets/unicorn.sock", :backlog => 64 # 日志 stderr_path "#{shared_dir}/log/unicorn.stderr.log" stdout_path "#{shared_dir}/log/unicorn.stdout.log" # 设置主进程 ID 位置 pid "#{shared_dir}/pids/unicorn.pid"
保存并退出。这将配置 Unicorn,指定应用程序的位置以及其套接字、日志和进程 ID 的位置。你可以随意修改文件,或添加任何其他你需要的选项。
现在创建配置文件中提到的目录:
mkdir -p shared/pids shared/sockets shared/log
创建 Unicorn 启动脚本
让我们创建一个启动脚本,这样我们就可以轻松地启动和停止 Unicorn,并确保它会在启动时启动。
使用以下命令创建脚本并打开它进行编辑(如果需要,请将高亮部分替换为你的应用程序名称):
sudo vi /etc/init.d/unicorn_appname
将以下代码块复制并粘贴到其中,并确保用适当的值替换 USER
和 APP_NAME
(高亮部分):
#!/bin/sh ### BEGIN INIT INFO # Provides: unicorn # Required-Start: $all # Required-Stop: $all # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: starts the unicorn app server # Description: starts unicorn using start-stop-daemon ### END INIT INFO set -e USAGE="Usage: $0 <start|stop|restart|upgrade|rotate|force-stop>" # 应用程序设置 USER="deploy" APP_NAME="appname" APP_ROOT="/home/$USER/$APP_NAME" ENV="production" # 环境设置 PATH="/home/$USER/.rbenv/shims:/home/$USER/.rbenv/bin:$PATH" CMD="cd $APP_ROOT && bundle exec unicorn -c config/unicorn.rb -E $ENV -D" PID="$APP_ROOT/shared/pids/unicorn.pid" OLD_PID="$PID.oldbin" # 确保应用程序存在 cd $APP_ROOT || exit 1 sig () { test -s "$PID" && kill -$1 `cat $PID` } oldsig () { test -s $OLD_PID && kill -$1 `cat $OLD_PID` } case $1 in start) sig 0 && echo >&2 "Already running" && exit 0 echo "Starting $APP_NAME" su - $USER -c "$CMD" ;; stop) echo "Stopping $APP_NAME" sig QUIT && exit 0 echo >&2 "Not running" ;; force-stop) echo "Force stopping $APP_NAME" sig TERM && exit 0 echo >&2 "Not running" ;; restart|reload|upgrade) sig USR2 && echo "reloaded $APP_NAME" && exit 0 echo >&2 "Couldn't reload, starting '$CMD' instead" $CMD ;; rotate) sig USR1 && echo rotated logs OK && exit 0 echo >&2 "Couldn't rotate logs" && exit 1 ;; *) echo >&2 $USAGE exit 1 ;; esac
保存并退出。这将允许你使用 service unicorn_appname
来启动和停止 Unicorn 和你的 Rails 应用程序。
更新脚本的权限并启用 Unicorn 在启动时启动:
sudo chmod 755 /etc/init.d/unicorn_appname sudo update-rc.d unicorn_appname defaults
现在启动它:
sudo service unicorn_appname start
现在你的 Rails 应用程序的生产环境正在使用 Unicorn 运行,并且它正在监听 shared/sockets/unicorn.sock
套接字。在你的应用程序对外开放给用户之前,你必须设置 Nginx 反向代理。
安装和配置 Nginx
使用 apt-get 安装 Nginx:
sudo apt-get install nginx
现在用文本编辑器打开默认的服务器块:
sudo vi /etc/nginx/sites-available/default
用以下代码块替换文件的内容。确保用适当的用户名和应用程序名称替换高亮部分:
upstream app { # Path to Unicorn SOCK file, as defined previously server unix:/home/deploy/appname/shared/sockets/unicorn.sock fail_timeout=0; } server { listen 80; server_name localhost; root /home/deploy/appname/public; try_files $uri/index.html $uri @app; location @app { proxy_pass http://app; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $http_host; proxy_redirect off; } error_page 500 502 503 504 /500.html; client_max_body_size 4G; keepalive_timeout 10; }
保存并退出。这将配置 Nginx 作为反向代理,因此 HTTP 请求将通过 Unix socket 转发到 Unicorn 应用程序服务器。随意根据需要进行任何更改。
重新启动 Nginx 以使更改生效:
sudo service nginx restart
现在,你可以通过服务器的公共 IP 地址或 FQDN 访问你的 Rails 应用程序的生产环境。要访问之前创建的 Tasks 控制器,请在 Web 浏览器中访问你的应用程序服务器:
http://server_public_IP/tasks
你应该看到与第一次测试应用程序时相同的页面,但现在它是通过 Nginx 和 Unicorn 提供的。
结论
恭喜!你已经使用 Nginx 和 Unicorn 部署了你的 Ruby on Rails 应用程序的生产环境。
如果你想改进生产环境中的 Rails 应用程序部署,你应该查看我们的教程系列《如何使用 Capistrano 自动化部署》。该系列基于 CentOS,但在自动化部署方面仍然应该有所帮助。