7.5 专业部署方案

现在注册页面可以使用了,该把应用部署到生产环境了。虽然我们从第 3 章就开始部署了,但现在应用才真正有点用,所以借此机会我们要把部署过程变得更专业一些。具体而言,我们要在生产环境的应用中添加一个重要功能,保障注册过程的安全性,还要把默认的 Web 服务器换成一个更适合在真实环境中使用的服务器。

为了部署,现在你应该把改动合并到 master 分支中:

$ git add -A
$ git commit -m "Finish user signup"
$ git checkout master
$ git merge sign-up

7.5.1 在生产环境中使用 SSL

在本章开发的注册表单中提交数据注册用户时,用户的名字、电子邮件地址和密码会在网络中传输,因此可能在途中被拦截。这是应用的重大潜在安全隐患,解决的方法是使用“安全套接层”(Secure Sockets Layer,简称 SSL),[12]在数据离开浏览器之前加密相关信息。我们可以只在注册页面启用 SSL,不过整站启用也容易实现。整站都启用 SSL 后,第 8 章实现的用户登录功能也能从中受益,而且还能防范 8.4 节讨论的会话劫持。

启用 SSL 很简单,只要在生产环境的配置文件 production.rb 中去掉一行代码的注释即可。如代码清单 7.27 所示,我们只需设置 config 变量,强制在生产环境中使用 SSL。

代码清单 7.27:配置应用,在生产环境中使用 SSL

config/environments/production.rb

Rails.application.configure do
  .
  .
  .
  # Force all access to the app over SSL, use Strict-Transport-Security,
  # and use secure cookies.
 config.force_ssl = true  .
  .
  .
end

然后,我们要在远程服务器中设置 SSL。这个过程包括为自己的域名购买和设置 SSL 证书,有很多工作要做。不过幸运的是,我们并不需要处理这些事,因为在 Heroku 中运行的应用(例如我们的演示应用),可以直接使用 Heroku 的 SSL 证书。所以,7.5.2 节部署应用后,会自动启用 SSL。(如果你想在自己的域名上使用 SSL,例如 www.example.com,参照 Heroku 对 SSL 的说明。)

7.5.2 生产环境中的 Web 服务器

启用 SSL 后,我们要配置应用,让它使用一个适合在生产环境中使用的 Web 服务器。默认情况下,Heroku 使用纯 Ruby 实现的 WEBrick,这个服务器易于搭建,但不能很好地处理巨大流量。因此,WEBrick 不适合在生产环境中使用,我们要换用能处理大量请求的 Puma

我们按照 Heroku 文档中的说明,换用 Puma。第一步,在 Gemfile 中添加 puma gem,如代码清单 7.28 所示。因为在本地不需要使用 Puma,所以我们把 puma 放在 :production 组中。

代码清单 7.28:在 Gemfile 中添加 Puma
source 'https://rubygems.org'
.
.
.
group :production do
  gem 'pg',             '0.17.1'
  gem 'rails_12factor', '0.0.2'
 gem 'puma',           '2.11.1' end

因为我们配置过 Bundler,不让它安装生产环境的 gem(3.1 节),所以代码清单 7.28 不会在开发环境中安装额外的 gem,不过我们还是要运行 Bundler,更新 Gemfile.lock

$ bundle install

下一步是创建文件 config/puma.rb,然后写入代码清单 7.29 中的内容。这段代码直接摘自 Heroku 的文档,[13]没必要理解它的意思。

代码清单 7.29:生产环境所用 Web 服务器的配置文件

config/puma.rb

workers Integer(ENV['WEB_CONCURRENCY'] || 2)
threads_count = Integer(ENV['MAX_THREADS'] || 5)
threads threads_count, threads_count

preload_app!

rackup      DefaultRackup
port        ENV['PORT']     || 3000
environment ENV['RACK_ENV'] || 'development'

on_worker_boot do
  # Rails 4.1+ 专用的职程设置
  # 详情参见:https://devcenter.heroku.com/articles/
  # deploying-rails-applications-with-the-puma-web-server#on-worker-boot
  ActiveRecord::Base.establish_connection
end

最后,我们要新建一个 Procfile 文件,告诉 Heroku 在生产环境运行一个 Puma 进程。这个文件的内容如代码清单 7.30 所示。Procfile 文件和 Gemfile 文件一样,应该放在应用的根目录中。

代码清单 7.30:创建 Puma 需要的 Procfile 文件

./Procfile

web: bundle exec puma -C config/puma.rb

生产环境的 Web 服务器配置好之后,我们可以提交并部署了:[14]

$ bundle exec rake test
$ git add -A
$ git commit -m "Use SSL and the Puma webserver in production"
$ git push
$ git push heroku
$ heroku run rake db:migrate

现在,注册页面可以在生产环境中使用了,注册成功后显示的页面如图 7.24。注意图中的地址栏,使用的是 https://,而且还有一个锁状图标——表明启用了 SSL。

signup in production 3rd edition图 7.24:在生产环境中注册

7.5.3 Ruby 的版本

部署到 Heroku 时,可能会看到类似下面的提醒消息:

###### WARNING:
       You have not declared a Ruby version in your Gemfile.
       To set your Ruby version add this line to your Gemfile:
       ruby '2.1.5'

经验表明,对本书面向的读者来说,明确指定 Ruby 的版本号要做很多额外工作,得不偿失,[15]所以现在你应该忽略这个提醒。为了让演示应用和系统中的 Ruby 版本保持最新,会遇到很多问题,而且不同的版本之间没有太大的差异。不过要记住,如果想在 Heroku 中运行重要的应用,建议在 Gemfile 中明确指定 Ruby 版本号,尽量减少开发环境和生产环境之间的差异。