支持
RVM 由志愿者社区维护,请将问题报告到 RVM 问题追踪器。
如果您能提供帮助或希望成为维护者之一,请开始帮助我们。 您可以在 RVM Github 组织 中找到更多与 RVM 相关的项目。
赞助商
Carbon Ads

部署最佳实践

警告

本文已过时,我们将发布更新,以下是已知错误列表,如果您能提供帮助,请帮助我们

  1. https://github.com/sm/sm/issues/50

使用 SM 框架项目

SM 框架 扩展可用于灵活的服务器端代码部署。 以下演练将解释一个示例中涉及的步骤。 此示例将从 GitHub 部署 Ruby on Rails 应用程序。 请注意,部署扩展不是“特定于 ruby 的”,可以用于部署任何所需的代码库。

演练

在部署 rvm 应用程序时,需要牢记一些事项。 请注意,所有这些都是我们推荐的做法,通常最好在新的机器上设置。

部署任何应用程序的最佳方法是为要部署的每个应用程序(项目/代码库)在目标系统上创建一个新用户。 然后,我们将每个应用程序部署到其自己的*隔离*环境中(例如,作为用户,在用户的 home 路径中); 最好用户名与应用程序的“短名称”相同。

为每个应用程序(项目)使用 RVM gemset

还要确保为每个项目使用 项目 .rvmrc ,用于开发和部署。

将 rvm_path 设置为面向用户的

appuser$ echo 'rvm_path="$HOME/.rvm"' >> ~/.rvmrc

现在安装 RVM,

appuser$ \curl -sSL get.rvm.io | bash -s stable

请注意,curl 前面有一个反斜杠,这可以防止在您使用其他选项对其进行别名或使用 .curlrc 文件时出现错误行为。 一旦您为目标应用程序用户安装了 RVM,您就可以开始设置部署了!

从生成默认的 ~/.smrc 开始

appuser$ sm smrc

接下来,更新您可能需要在 ~/.smrc 文件中更改的任何设置,例如环境、repository_url 以及可能要从中部署的分支

appuser$ vim ~/.smrc

例如,当我们部署一个 Redmine 实例时,我们在 ~/.smrc 文件中设置以下两个变量

appuser$ grep -E '^repository_url=|^branch=' ~/.smrc
repository_url="git://github.com/edavis10/redmine.git"
branch="1.2-stable"

对于 Ruby 应用程序,我们希望安装并使用“ruby”扩展集,其中包括 rvm、unicorn 和 rails 等扩展

root# sm set install ruby

接下来,运行 Rails 应用程序设置扩展操作;这将在应用程序用户的 ~/shared 路径中创建和设置目录和配置文件。它还将安装带有默认 ruby 的 RVM

appuser$ sm rails setup

在 ~/shared/config/ 中生成 unicorn 配置文件。如果您希望默认情况下运行超过 2 个 unicorn 工作进程,并调整任何 unicorn 设置,请编辑此文件

appuser$ sm unicorn setup

编辑默认生成的 database.yml 文件,并设置您的数据库连接信息

appuser$ vim ~/shared/config/database.yml

现在安装部署扩展

root# sm ext install deploy

现在我们可以使用部署扩展,它将使用存储库中的最新代码和 ~/.smrc 中定义的分支信息,用新的版本更新 ~/current

appuser$ sm deploy

如果您使用 rvm gemset 文件,请执行以下操作

appuser$ source ~/.rvm/scripts/rvm # load RVM into your current shell
appuser$ rvm gemset import ~/current/production.gems

如果您使用 bundler,请按如下方式引导您的 gem(注意:确保 'gem "unicorn"' 首先在 Gemfile 中,*没有指定版本*)

appuser$ cd ~/current
appuser$ gem install bundler && bundle install

一旦您的 Ruby 应用程序环境启动,就开始在 unicorn 下运行您的应用程序

appuser$ sm unicorn start

事情并不总是像独角兽和彩虹一样顺利,尤其是在更改和更新应用程序的代码库时。我曾经连续几天在额头上留下键盘印,因为无法启动应用程序的 unicorn 群,最后才发现是因为我的新代码库使用了新的 rubygem,而我忘记将其添加到应用程序的 Gemfile 中!当代码库更新成功但独角兽无法重启时,您可以通过检查 unicorn 日志来检查其状态;例如,要检查 unicorn 日志的最后 200 行,请发出以下命令

appuser$ tail -n 200 ~/shared/log/unicorn.log

然后,您找出错误告诉您的内容,修复问题并再次部署!是的,这是一个恶性循环;)

我们使用 Nginx web 服务器来提供 http/https 流量并代理到应用程序服务器。Nginx 扩展位于“servers”扩展集中

root# sm set install servers

我们运行 Nginx,所以我们按如下方式进行。请注意切换到以 root 身份运行(使用 sudo)

root# sm nginx install

现在,“配置系统” - 这意味着将 Nginx 配置目录复制到 /etc/nginx

root# sm nginx configure system

接下来,对于每个应用程序用户,您将生成一个应用程序服务器配置文件(位于 /etc/nginx/servers/ 中)。

root# sm nginx server add {{appuser}}

注意:这将创建一个 /etc/nginx/servers/{{appuser}}.conf 文件;默认配置为代理到在 Unix 域套接字 (UDS) 上运行的 unicorn。

现在,确保 appuser 的目录可供 Nginx 读取。

root# chmod go+rx /home/{{appuser}}

最后,启动 Nginx 服务。

root# sm nginx service start

不要忘记备份!!! 对于大多数人来说,这只是一个事后诸葛亮,只有在他们没有做好准备的事件发生后才会想到。为了避免这种痛苦,Rails 扩展提供了一个 backup_database 操作。这将根据 database.yml 文件将数据库备份到 ~/shared/backups/ 目录中。(如果您希望将它们放在其他位置,请使用文件系统符号链接。)

user$ sm rails backup_database

将命令添加到 cron 中,以便它在每天凌晨 2:00 运行。

user$ crontab -e

0 2 * * * sm rails backup_database

注意:这将很快更改为“sm rails backup database”(注意空格)。

使用包装脚本管理诸如 god 之类的东西。

user$ rvm help wrapper

部署特定分支和修订版。

BDSM 部署扩展还允许您指定要从应用程序存储库中使用的分支和/或修订版。例如,如果您使用 git,您可以在 ~/.smrc 文件中设置其中一个或两个,如下所示。

branch="production"
revision="asdf4269"

部署钩子。

在上面的演练中,我向您展示了如何使用一些 BDSM 框架扩展来完成 Ruby on Rails 部署。我们现在有一台运行着应用程序代码并在端口 80 上提供服务的服务器。我们正在运行 Unicorn 和 Nginx Web 服务器堆栈。

对于那些刚接触部署的人来说,一个说明:'Unicorn' 被称为“应用程序服务器”,这意味着它运行实际的 Ruby 代码。Nginx,即“Web 服务器”,用于提供静态文件(css、图像、javascript 等)并将所有其他请求代理到 Unicorn 集群(应用程序服务器)。

您必须在每次想要将代码更新到服务器上的最新版本时执行上述步骤中的几个步骤。我们现在将向您展示如何进一步自动化这些步骤,以便您只需键入“sm deploy”即可!安装后,除非您要将扩展和扩展集更新到较新版本,否则无需重新安装或更新它们。也不需要重新配置项目、数据库和 unicorn 配置,这些都是一次性任务。

如果您使用 rvm gemsets 和/或 bundler(是的,您可以像我一样同时使用两者),那么每次部署新版本的应用程序时,您都需要确保您的 gems 是最新的。

这可以在部署过程中自动完成。为了完成部署,需要执行几个步骤。大多数步骤发生在暂存位置($stage_path)。部署扩展为部署过程中的每个步骤提供了前后挂钩。为了在过程中的任何这些挂钩点执行操作,您需要在 config/deploy/ 中创建一个可执行文件。

让我们以在替换当前应用程序代码库之前更新您的 gems 为例,这样您就可以确保应用程序不会暂时出现故障。我们在应用程序代码库“config/deploy/before_replace_current”中创建以下可执行文件

#!/bin/bash
enter "${stage_path}"
command_exists bundle || gem install bundler --no-rdoc --no-ri
bundle --without development,test

一旦将包含此内容的文件检入应用程序代码库,下次在服务器上以 {{appuser}} 身份运行“sm deploy”时,该文件将在部署扩展替换当前部署的代码目录之前运行。

需要注意的是,此文件是一个 shell 脚本!这意味着您可以运行任何命令来完成在替换当前运行的代码之前在服务器上需要完成的任何操作。

为了使您的网站更改其运行的代码库,必须执行的另一个步骤是重新启动应用程序服务器(unicorn),以便它重新加载新的代码库。使用 unicorn 扩展执行此操作的方法是

appuser$ sm unicorn restart

我们希望在替换当前目录后发生这种情况。因此,我们可以使用 after_replace_current 挂钩!让我们使用以下内容创建文件“config/deploy/after_replace_current”

#!/bin/bash
enter ${release_path} # Not necessary but it makes me feel warm and fuzzy.
sm unicorn restart

unicorn 重新启动将向正在运行的 unicorn 进程发出信号,以重新加载代码库,而不会丢弃请求。如果 unicorn 集群尚未运行,那么这将启动 unicorn 集群,这等效于“sm unicorn start”。

我个人在所有 Ruby 应用程序中使用 airbrakeapp(以前称为:hoptoadapp)来进行应用程序运行时错误通知,我发现它是一个非常有用的产品!因此,我的应用程序还具有一个“config/deploy/after_deploy”可执行挂钩文件,该文件向 airbrake 应用程序发送部署通知

#!/bin/bash
enter ${release_path}
rake hoptoad:deploy TO="$environment" \
  REVISION="$(cat "${release_path}/revision")"

请注意,这次“进入 ${release_path}”是必要的,因为这里的 rake 命令必须在应用程序的已部署代码库中运行,以便它可以找到应用程序的 Rakefile。