锻造坊 - Phusion Passenger
我使用 Ruby on Rails 已经好几年了,并且我仍然惊叹于我可以如此轻松地创建复杂的 Web 应用程序。它并非完美,但事实是 Rails 已经使 Web 开发中最困难的部分变得相当轻松。ActiveRecord 让我可以几乎毫不费力地处理数据库,这显然是一项伟大的成就,但 Rails 的其他元素——从数据库迁移到模板系统再到整体 MVC 结构——常常以它们为常见问题提供的优雅解决方案让我感到惊讶。即将到来的与 Merb(Rails 的精简替代品)的合并让我相信,Rails 将继续为开发人员提供一个极好的环境来实践他们的技艺。
因此,令我和许多其他开发人员感到沮丧的是,尽管 Rails 使编写应用程序变得容易,但它使部署这些相同的应用程序变得困难。当然,那些您可以创建博客的著名截屏视频清楚地表明,您几乎可以在瞬间启动并运行。但是,那是使用 WEBrick,一个用 Ruby 编写的简单 HTTP 服务器,实际上没有人会在生产站点上使用它。
Apache,我自首次发布以来就一直使用的 HTTP 服务器,并且继续为世界上大多数网站提供支持,似乎是 Rails 部署的自然选择。毕竟,Rails 是一个开源项目,几乎每个开源 Web 框架都挂钩到 Apache,对吗?不幸的是,并非如此。Apache 和 Rails 之间的接口使用一种称为 FastCGI 或 FCGI 的协议,长期以来,Rails、FCGI 和 Apache 的组合被认为不如其他选项。
一直以来都有替代方案。一些站点使用 lighttpd,它对 FCGI 的支持被认为优于 Apache 提供的支持。其他站点切换到 Mongrel,它的设计部分是为了为 Rails 应用程序提供一个稳定且快速的选项。一些站点将 Mongrel 与另一个开源服务器 nginx(发音为“engine-x”)结合使用,后者擅长处理静态文件。《部署 Rails 应用程序》这本书,我推荐给任何在生产 Rails 站点上工作的人,它详细介绍了 Mongrel 和 nginx 的配置。
因此,几年来,部署 Rails 应用程序意味着学习使用一套新的服务器。这产生了几个负面影响。首先,它稍微提高了使用 Rails 的门槛;现在程序员不仅需要学习一个新的框架,还需要学习一个新的 HTTP 服务器。另一个结果是能够使用 Rails 的托管设施相对匮乏。PHP 在托管世界几乎无处不在,部分原因是它可以轻松地与 LAMP 堆栈(Linux、Apache 和 MySQL)的其他元素集成。由于 Rails 不容易与 Apache 集成,这意味着托管提供商需要学习一项新技能并维护一个新软件包,他们对此不感兴趣。
因此,在 2008 年,荷兰咨询公司 Phusion(过去几年一直在使用 Ruby)宣布发布了 Passenger,也称为 mod_rails,这是一个 Apache 模块,可以非常容易地启动并运行 Rails 应用程序,这引起了很大的轰动。我已经为我的 Rails 生产站点切换到 Passenger,并且对此没有任何抱怨或遗憾。而且,似乎我并不孤单;最初赞助 Ruby on Rails 开发的公司 37signals 表示,它在某些应用程序中使用了 Passenger,并且正在考虑将更多应用程序迁移到它。
现在我们可以使用 Apache 部署 Rails 应用程序的另一个优势是其他 Apache 模块的可用性。Apache 的设计具有高度模块化,允许开发人员包含他们需要的模块,同时排除那些会降低服务器效率的模块。多年来,这导致了数十个不同的 Apache 模块的开发,涵盖了从身份验证到日志记录,从内容协商到服务器管理的所有内容。访问大量有用的模块意味着我们的 Rails 应用程序可以以多种不同的方式进行自定义,从而在部署时为我们提供许多选择。
本月,我们将了解如何使用 Passenger 部署 Rails 应用程序。我们还将了解如何将其他 Apache 模块与 Passenger 结合使用,以获得定制的应用程序解决方案。
安装 Passenger 是一个非常容易的过程,前提是您的计算机上已经安装了 Apache。首先,您需要安装 Passenger 软件,它以 Ruby gem 的形式出现
sudo gem install passenger
这将安装 Ruby gem(在我的 Ubuntu 服务器上,它位于 /usr/lib/ruby/gems/1.8/gems 中),以及 /usr/bin 中的几个程序,我们将使用它们来运行 Passenger。我们使用其中的第一个来安装 Apache 的 Passenger 模块
passenger-install-apache2-module
这将启动在您的计算机上安装 Apache 模块的过程;Passenger 的安装程序脚本非常智能,可以找到许多不同版本的 Apache,在许多不同的位置。它会检查 Apache,确定需要安装什么,然后提示您自动安装所需的软件包。例如,这是 Passenger 安装程序的输出
Checking for required software... * GNU C++ compiler... found at /usr/bin/g++ * Ruby development headers... found * OpenSSL support for Ruby... found * RubyGems... found * Rake... found at /usr/bin/rake * Apache 2... found at /usr/sbin/apache2 * Apache 2 development headers... not found * Apache Portable Runtime (APR) development headers... found * Apache Portable Runtime Utility (APR) development headers... found * fastthread... found * rack... found
如果您缺少其中一个或多个程序,安装程序会告诉您需要运行哪些命令才能安装必要的程序。例如,我的 Ubuntu 服务器指示我需要安装 Apache 2 开发头文件,并建议我通过执行以下命令来完成此操作
apt-get install apache2-prefork-dev
我按照这些说明操作,它奏效了。一旦我通过 apt-get 完成安装其他软件包,我重新运行了passenger-install-apache2-module。这一次,它成功了,编译了 Apache 模块,并在 Apache 配置文件中添加了适当的 LoadModule 指令。
实际上,现在 Passenger 已经安装在我们的系统上,我们可以配置一个或多个网站。一个简单的配置——实际上是最短的配置——如下所示
<VirtualHost *:80> ServerName www.mysite.com DocumentRoot /home/reuven/public </VirtualHost>
请注意,DocumentRoot 指向 Rails 应用程序的 public 目录,而不是 Rails 根目录。Rails 应用程序本身被假定位于与 public 平行的 app 目录中。假设您的 Rails 应用程序已就位,重新启动 Apache 服务器将加载 Passenger 模块,然后运行您的应用程序。默认情况下,Passenger 假定您希望使用“production”环境运行应用程序,该环境针对系统效率进行了优化,而不是针对程序员交互性。但是,您可以使用 RailsEnv 配置指令将环境设置为其他内容
RailsEnv development
一旦您的服务器正在运行,Apache 将继续生成其标准日志文件(即,错误、访问和引用)。Rails 也将在应用程序的 log 目录中生成其标准日志文件,因此如果您习惯于查看 logs/production.log,则无需担心它会消失。
要重新启动 Rails 应用程序,您需要在应用程序的 tmp 目录中创建一个名为 restart.txt 的文件。创建此文件后,Passenger 将重新启动应用程序,确保不中断当前正在处理的任何 HTTP 请求。(仅凭这一点,它就明显优于完全重新启动 Apache。)
如果您使用 Capistrano 将程序部署到一个或多个生产服务器,您可能想知道它如何与 Passenger 协同工作。答案是 Capistrano 工作正常,但您确实需要考虑启用 Capistrano 的服务器的布局,以确保一切正常运行。
您可能知道,Capistrano 会保留 Web 应用程序的多个版本。每个版本都存储在 releases 目录中的自己的目录中。一个名为 current 的符号链接指向 releases 内部的子目录,该子目录对应于当前版本。这意味着恢复到以前的版本几乎是瞬间完成的,因为它涉及到重新定义符号链接以指向 releases 的以前的子目录。
因此,在启用 Capistrano 的系统上,您希望您的 Apache 配置如下所示
DocumentRoot /home/reuven/current/public/
请注意 DocumentRoot 中引入的 /current。这告诉 Apache 它应该使用 current 符号链接,因此,将 current 指向的任何内容都视为应用程序的活动版本。
但是,当您想要部署新版本的应用程序时会发生什么?Capistrano 非常智能,可以重写符号链接,但它本身并不知道如何重新启动服务器。幸运的是,正如我们之前看到的,重新启动涉及创建 restart.txt 文件,因此与 Passenger 友好的配方(在 deploy.rb 内部)可能如下所示
namespace :deploy do desc "Restart Application" task :restart, :roles => :app do run "touch #{current_path}/tmp/restart.txt" end end
现在,当我们发出cap deploy命令时,它知道通过在应用程序的 tmp 目录中创建 restart.txt 来重新启动服务器。如果我们只对重新启动服务器感兴趣,我们可以通过发出cap deploy:restart命令来完成,该命令仅运行 deploy 命名空间内的 restart 任务。
Passenger 附带了许多实用程序,可以轻松跟踪服务器的状态和资源使用情况。例如,passenger-memory-status 程序列出了 Apache 当前正在使用的所有进程,以及每个进程生成的线程数。然后,它描述了每个进程正在使用的内存量。例如,这是生产 Web 服务器上十个 Apache 进程的内存使用情况报告
root@kipling:~# passenger-memory-stats -------------- Apache processes --------------- PID PPID Threads VMSize Private Name ----------------------------------------------- 2941 15559 1 11.9 MB 0.5 MB /usr/sbin/apache2 -k start 2944 15559 2 132.5 MB 9.1 MB /usr/sbin/apache2 -k start 7392 20753 27 234.0 MB 6.8 MB /usr/sbin/apache2 -k start 13383 20753 2 124.0 MB 7.9 MB /usr/sbin/apache2 -k start 15559 1 1 11.9 MB 0.5 MB /usr/sbin/apache2 -k start 15563 15559 2 147.7 MB 8.7 MB /usr/sbin/apache2 -k start 17357 20753 1 11.9 MB 0.5 MB /usr/sbin/apache2 -k start 17362 20753 27 239.8 MB 12.8 MB /usr/sbin/apache2 -k start 17477 20753 27 236.6 MB 7.8 MB /usr/sbin/apache2 -k start 20753 1 1 11.9 MB 0.4 MB /usr/sbin/apache2 -k start ### Processes: 10 ### Total private dirty RSS: 54.95 MB
相同的命令还向我们显示了 Passenger(即 Ruby)进程的当前内存状态。Ruby 进程通常比 Apache 进程大得多,这应该不足为奇。实际上,监控 Rails 进程的内存使用情况是 Rails 开发人员需要做的一件重要事情;如果没有这种反馈,将很难衡量进程的工作效率。
最后,正如我之前提到的,使用 Apache for Rails 应用程序的最佳部分之一是您可以根据需要混合和匹配其他 Apache 模块。例如,我非常喜欢 mod_status 和 mod_info,这两个 Apache 模块可以查看服务器的当前配置和执行状态。
同样,我希望在文件从我的服务器发送到用户的浏览器时自动压缩文件。通过将 mod_deflate 合并到我的服务器配置中,我可以使用以下指令添加自动、即时压缩
SetOutputFilter DEFLATE
最后,我最近在一个简单的 Rails 站点上工作,该站点希望限制对 /admin URL 下的项目的访问,仅限于授权用户。我本可以使用 Rails 插件,例如 restful_authentication,但由于我使用的是 Passenger,我认为对我来说在 Apache 配置文件中定义的站点上使用 HTTP 身份验证可能同样容易和快速。果然,以下内容足以完成这项工作
<Location /admin> AuthName "Site admin" AuthType Basic AuthUserFile /opt/mysite/users require valid-user </Location>
当然,您可以争辩说,这种身份验证远不如基于 Rails 的身份验证灵活,您是对的。但是,对于需求非常简单的站点,并且不需要像 restful_authentication 这样花哨的东西,Apache 的内置(且文档完善)HTTP 身份验证是一个不错的解决方案。
Apache 的美妙之处在于其灵活性,而 Passenger 使我们能够将这种灵活性融入到我们的 Rails 应用程序中,使用我们多年来一直使用的相同服务器软件。
Phusion Passenger 使部署 Rails 应用程序变得更加容易,这对各地的 Rails 开发人员来说都是一件好事。它不仅允许您使用您现有的 Apache 服务器知识,还意味着您可以合并多年来为 Apache 开发的许多模块。
资源
您可以在 www.rubyonrails.com 了解有关 Ruby on Rails 的更多信息。有关 Phusion Passenger 的信息,请访问 www.modrails.com。该站点包含大量文档,包括配置指令的完整列表,允许您完全自定义为您的站点部署 Passenger 的方式。
Pragmatic Programmers 出版并由几位著名的 Rails 开发人员编写的《部署 Rails 应用程序》一书不包含对 Passenger 的描述。但是,它确实对推出 Rails 应用程序提出了许多其他好的建议,所有 Rails 开发人员都应该仔细阅读这本书,包括它提供的许多有用的提示。
Reuven M. Lerner,一位长期的 Web/数据库开发人员和顾问,是西北大学学习科学专业的博士候选人,研究在线学习社区。在芝加哥地区生活四年后,他最近(与他的妻子和三个孩子)返回以色列莫迪因的家。