内容


将您的 Linux 应用程序迁移到 Amazon 云,第 1 部分

初始迁移

如何将您的应用程序迁移到云中

Comments

系列内容:

此内容是该系列 # 部分中的第 # 部分: 将您的 Linux 应用程序迁移到 Amazon 云,第 1 部分

敬请期待该系列的后续内容。

此内容是该系列的一部分:将您的 Linux 应用程序迁移到 Amazon 云,第 1 部分

敬请期待该系列的后续内容。

基础设施即服务(Infrastructure as a Service,IaaS)是一个极好的概念:您使用计算资源并支付费用。需要的资源越多,支付的费用也就越高。这个模式的不足之处在于,您看不到正在使用的计算机,您对那些计算机真的知之甚少。但一旦克服这一点,使用 IaaS 可以带来很多好处。

由于 IaaS 模式与传统的购买服务器的模式差别很大,因此您管理您的虚拟计算机的方法也随之发生改变。这还意味着,您在云中运行应用程序的方式也发生了改变。以前想当然的东西,比如服务器之间无足轻重的延迟,现在不再理所当然。

本系列文章将跟随一个 Web 应用程序从一个单一物理服务器到 Amazon Elastic Compute Cloud (Amazon EC2) 的迁移过程。途中,您将了解如何调整您的应用程序以适应云环境,以及如何利用云提供的特性。首先,您将看到从一个物理服务器到一个云服务器的直接迁移。

使用 Amazon EC2

Amazon EC2 允许拥有信用卡的任何人按小时支付服务器费用,通过一个应用程序编程接口(API)来打开和关闭服务器。您可以选择各种各样的服务器 — 取决于您的主要考虑因素是内存、磁盘还是 CPU — 以及从永久性磁盘到负载平衡器的一套附件。您只需为使用的资源付费,这使得 Amazon 服务成为您的应用程序的一个颇具吸引力的选择。

与 Amazon EC2 产品一起提供的还有其他一些服务,它们向您提供付款处理、数据库和消息排队等功能。在本文中,您将使用 Amazon Simple Storage Service (Amazon S3),该服务基于即用即付模式提供磁盘空间访问。

应用程序

本系列用作示例的 Web 应用程序是一个称为 SmallPayroll.ca 的工资表服务,使用 Ruby on Rails 框架和一个 PostgreSQL 后端编写。它是一个典型的 Web 应用程序:拥有一个数据库层、一个应用程序层、以及一组静态文件,比如层叠样式表(CSS)和 JavaScript 文件。用户导航各种表单以输入和操作数据,这些表单将用于生成报告。

使用的各种组件是:

  • Nginx。静态文件和中间层的平衡器的前端 Web 服务器。
  • Mongrel。应用程序服务器本身。
  • Ruby。用于编写应用程序的语言。
  • Gems。您将使用第三方插件和库完成从数据库加密到应用程序级别监控的所有任务。
  • PostgreSQL。Structured Query Language 数据库引擎。

站点的使用已经超越了现在托管该站点的单个服务器的能力。因此,需要迁移到一个新环境,这是迁移到云的最好时机。

理想的改进

从一个服务器迁移到基于云的少量服务器不能自动利用云的功能,也不会达到令人兴奋的读取效果。在迁移过程中,您需要进行一些改进,有些改进只有在云环境中才可能实现:

  • 提高的可靠性。由于可以选择在云中运行的服务器的大小,因此可运行多个小服务器以留取冗余空间。
  • 上下缩放能力。随着服务增长,服务器也逐渐被添加到池。但是,服务器的数量也可以增加以应对短期流量剧增,或在一定的间歇期间减少。
  • 云存储。应用程序数据备份将使用 Amazon S3 完成,消除了磁带存储的必要性。
  • 自动化。Amazon 环境中任何事物 — 从服务器到存储再到负载平衡器 — 都可以自动化。管理应用程序需要的时间更少,这意味着可以花费在其他生产力更高的任务上的时间更多。

在本系列中,您将逐渐实现这些改进。

测试和迁移策略

当您第一次部署一个应用程序时,您通常拥有能够测试和调整应用程序而免受生产流量干扰的便利。相比之下,迁移则拥有用户这个增加的元素,这些用户正在站点上放置一个负载。一旦新环境接收生产流量,用户将期待一切运转正常。

迁移并不一定意味着零停机。如果允许服务离线一段时间,那么迁移将更容易。您将使用这个停用窗口来执行最终数据同步并允许任何网络更改趋于稳定。这个窗口不应用于执行对新环境的初始部署 — 即,新环境在迁移开始前应该处于操作状态。记住这一点,关键问题是环境与网络更改之间的数据同步。

当您准备制定您的迁移策略时,首先检查一下您的当前环境是很有帮助的。回答以下问题:

  • 服务器上使用什么软件来运行这个应用程序?
  • 服务器上使用什么软件来管理和监控应用程序和服务器资源?
  • 所有用户数据存储在什么地方?数据库和文件呢?
  • 静态文件(比如图像、CSS 和 JavaScript 文件)存储在其他位置吗?
  • 要进入其他系统,应用程序需要什么样的接触点?
  • 所有资料最近都备份了吗?

通知用户

通常,在迁移之前最好先通知用户,即使您预计不会出现停机。在 SmallPayroll.ca 应用程序案例中,用户通常以一致的间隔定期使用站点,这个间隔对应于他们的双周发薪周期。因此,提前两星期的通知将是个合理的周期。Google AdWords(这是 Google 广告平台的管理界面)这样的站点提供提前一周的通知。如果您的 Web 站点主要是一个新闻站点,停机一小时不会对用户造成太大的影响,那么您可以选择停用当天再通知用户。

根据您的站点性质以及当前与您的客户的沟通方式,通知的形式也会有所不同。对于 SmallPayroll.ca,在用户登录时显示一条显眼的消息就可以了。例如,这条消息可能是 “系统将于东部时间 2010 年 6 月 17 日 12:01 a.m. 至 1:00 a.m. 之间停用。在此时间前输入的内容将被保存。要了解更多信息,单击此处。” 这条信息提供用户需要了解的三点关键信息:

  • 停用将发生的时间,包括时区。
  • 保证他们的数据将是安全的。
  • 了解更多信息的联系方式。

如果可能,避免使用 12:00 a.m. 或 12:00 p.m. 之类的时间,包括词汇 midnight。这些时间和词汇可能会使人们感到困惑,因为许多人不能确认 6 月 17 日 midnight 指的是凌晨(12:01 a.m.)还是午夜(11:59 p.m.)。同样,许多人也搞不清 noon 指的是 12 a.m. 还是 12 p.m。最好添加一个分钟,使时间更清楚。

您的详细信息可能会不同,特别是您预期停用期间的部分功能时。如果您决定您只需在停用期间张贴通知(比如对一个新闻站点而言),那么上面的信息仍然有用。我最喜欢的停用屏幕显示的消息是 “本站点将停用以进行维修,请在 3 p.m. EST 左右进行备份。等待期间可以玩玩 Asteroids 游戏!”

也不要忽略您的内部用户。如果您拥有客户代表,则需要通知他们,以免他们的客户提出问题。

DNS 考虑事项

域名系统(DNS)负责将 www.example.com 这样的名称转换为 192.0.32.10 这样的 IP 地址。您的计算机连接到 IP 地址,因此这种转换很重要。当您从一个环境迁移到另一个环境时,几乎肯定要使用另一个 IP 地址(惟一的例外是您仍处于相同的物理建筑内)。

计算机将这个名称缓存到 IP 映射一段时间,这个时间段称为 time to live (TTL),以减少总响应时间。当您从一个环境切换到另一个环境时 — 因此也是从一个 IP 地址切换到另一个 IP 地址 — 缓存了这个 DNS 条目的人将继续尝试使用原来的环境。应用程序的 DNS 条目及其关联 TTL 必须小心管理。

TTLs 通常位于 1 小时和 1 天之间。但是,为准备一次迁移,您需要 TTL 处于较短的时间段,比如 5 分钟。在您打算更改地址之前,必须提前至少 1 个 TTL 时间段执行更改,因为计算机将把 TTL 以及名称缓存到 IP 映射。比如,如果 www.example.com 的 TTL 设置为 86,400 秒(一天),那么您需要至少在迁移之前一天将 TTL 重置为 5 分钟。

解耦合新旧环境

在迁移之前全面测试您的新环境很关键。所有测试都应该与生产环境隔离,最好使用一个生产数据快照,以便您能够更好地测试新环境。

使用一个生产数据快照来执行一个全面测试有两个目的。第一,使用真实数据更容易定位错误,因为真实数据比开发期间使用的测试数据更难预测。真实数据 可能指您在测试过程中忘记复制或需要某些配置而您又忘记了的文件。

第二,您可以在加载数据的同时练习您的迁移。您应该能够对迁移计划的大多数方面胸有成竹,除了环境的实际切换。

即使您能像生产环境一样模拟您的新环境,但只有一个环境可以与应用程序的主机名关联。绕过这个要求的一种最简单的方法是覆盖您的主机文件中的一个 DNS。在 UNIX® 中,这个文件位于 /etc/hosts 中;在 Windows® 中,它位于 C:\windows\system32\drivers\etc\hosts 中。只需遵循现有 DNS 行的格式,添加一个条目以将您的应用程序的主机名指向它的未来 IP 地址。不要忘记对任何映像服务器或要迁移的任何对象执行相同的操作。您可能必须重新启动您的浏览器,此后,您将能够输入您的生产 URL 并转到您的新环境。

Amazon EC2 入门

Amazon EC2 服务允许您按小时支付一台虚拟机(VM)费用。Amazon 提供几种不同类型的机器并根据它们的 CPU、内存和磁盘配置文件分类。Amazon 按照 GB 计量内存和磁盘,按照 Amazon EC2 Compute Units (ECU) 计量 CPU。1 ECU 基本等同于 1.0 到 1.2GHz AMD Opteron 或 Intel® Xeon® 处理器(2007 era)。例如,标准小型实例提供 1.7GB 内存、160GB 磁盘空间和 1 ECU CPU。本文撰写之时,最大的机器是 High-memory Quadruple Extra Large,它拥有 68.4GB 内存,1.7TB 磁盘空间和 26 个 ECU(跨 8 个虚拟核心分割)。价格从最少的每小时 8.5 美分到最多的每小时 2.40 美元。

Amazon EC2 实例从一个 Amazon Machine Image (AMI) 开始执行其任务,AMI 是您用于构建任意数量的 VMs 的模板。Amazon 发布一些 AMIs,您也可以构建自己的 AMI 并与他人共享。一些用户创建的 AMIs 可以免费使用;而另一些 AMIs 则在 Amazon 小时收费的基础上按小时计费。例如,IBM 发布了几个收费 AMI,允许用户按小时付费获取许可。

当您想要启动一个 VM 时,您选择机器类型和一个 AMI。AMI 存储在 Amazon S3 中并在您启动实例时复制到您的 VM 的根分区。根分区的大小总是 10GB。与机器类型关联的存储空间称为实例存储(instance storage)临时存储(ephemeral storage),并作为一个单独的驱动器呈现给您的 VM。这种存储之所以称为临时存储,是因为当您关闭您的实例时,信息将永远消失。您需要定期备份您的数据以免损失。这还意味着如果运行您的实例的物理主机崩溃,您的实例将关闭,临时磁盘将丢失。

Amazon Machine Image

所有 AMIs 都由 Amazon 分配一个标识符,比如 ami-0bbd5462。Amazon 提供一些公共 AMIs,其他人公开他们自己的 AMIs。您可以选择从一个公共 AMI 开始并进行自己的修改,也可以从头开始构建自己的 AMI。无论何时您对一个 AMI 的根文件系统进行修改,都可以将其保存为一个新 AMI,这个过程称为重新绑定(re-bundling)

在本系列中,您将从一个可公用的 CentOS 映像开始,当然您也可以选择另一个映像。明智的做法是花点时间仔细检查您使用的映像,确保没有额外帐户且包已更新。也可以从头开始构建自己的 AMI,但这超出了本文的范围。

Amazon API

启动、停止、使用 Amazon EC2 云需要的所有功能都通过使用一个 Web 服务提供。Amazon 发布了这个 Web 服务的规范并提供了一组命令行工具。您应该首先下载这些工具(参见 参考资料)。我还建议您浏览一下快速开始指南(参见 参考资料)以设置您的环境,这将为您节省大量输入时间。

使用安全凭证验证到这个 API。这些凭证来自 Amazon Web Services (AWS) 管理控制台(参见 参考资料)中的 Account 链接。您将需要您的 X.509 证书文件和您的访问密匙。拥有它们的任何人都能使用 AWS 资源并代表您引发费用。

启动第一个实例之前

当您启动您的第一个实例之前,您必须生成 Secure Shell (SSH) 密匙来验证到您的新实例并设置虚拟防火墙来保护您的实例。清单 1 展示了如何使用 ec2-add-keypair 命令来生成一个 SSH 密匙对。

清单 1. 生成一个 SSH 密匙对
[sean@sergeant:~]$ ec2-add-keypair main
KEYPAIR main    40:88:59:b1:c5:bc:05:a1:5e:7c:61:23:5f:bc:dd:fe:75:f0:48:01
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAu8cTsq84bHLVhDG3n/fe9FGz0fs0j/FwZiDDovwfpxA/lijaedg6lA7KBzvn
...
-----END RSA PRIVATE KEY-----
[sean@sergeant:~]$ ec2-describe-keypairs
KEYPAIR main    40:88:59:b1:c5:bc:05:a1:5e:7c:61:23:5f:bc:dd:fe:75:f0:48:01

第一条命令告诉 Amazon 使用名称 main 生成一个密匙对。结果的第一行提供了密匙散列。输出的其余部分是未加密的 PEM 私匙。您必须将这个密匙存储在某个位置 — 比如 ~/.ssh/main.pem。Amazon 保留这个密钥的公共部分,这个部分将提供给您启动的 VMs。

第二条命令 ec2-describe-keypairs 向 Amazon 请求当前密匙对列表。结果是密匙对名称,后跟散列数据。

每个实例都通过一个虚拟防火墙保护,一开始阻止所有访问。Amazon EC2 调用这些安全组 并使用 API 调用和命令来操作它们。稍后时机成熟时我们将详细介绍安全组。同时,清单 2 展示如何查看您的当前组。

清单 2. 显示当前安全组
[sean@sergeant:~]$ ec2-describe-group
GROUP   223110335193    default default group

清单 2 显示一个安全组,名称为 default,描述为 “default group”。与组相关的用户 ID 是 223110335193。这个组中没有规则。如果有,它们将在左边的列中这个组下使用单词 PERMISSION 来描述。

准备云环境

第一步是准备云环境来测试应用程序。这个新环境将模拟当前生产环境。

首先启动 AMI,这个 AMI 的 ID 是 ami-10b55379清单 3 展示了正在被启动的 AMI 和检查状态。

清单 3. 启动 CentOS AMI
[sean@sergeant:~]$ ec2-run-instances ami-10b55379 -k main
RESERVATION  r-750fff1e  223110335193  default
INSTANCE  i-75aaf41e  ami-10b55379  pending  main  0  m1.small
2010-05-15T02:02:57+0000 us-east-1a  aki-3038da59  ari-3238da5b  monitoring-disabled
instance-store  
[sean@sergeant:~]$ ec2-describe-instances i-75aaf41e
RESERVATION  r-750fff1e  223110335193  default
i-75aaf41e  ami-10b55379  pending  main  0  E3D48CEE  m1.small
2010-05-15T02:02:57+0000 us-east-1a  aki-3038da59  ari-3238da5b  monitoring-disabled
instance-store  
[sean@sergeant:~]$ ec2-describe-instances i-75aaf41e
RESERVATION  r-750fff1e  223110335193  default
INSTANCE  i-75aaf41e  ami-10b55379  ec2-184-73-43-141.compute-1.amazonaws.com
domU-12-31-39-00-64-71.compute-1.internal  running  main  0  E3D48CEE  m1.small
2010-05-15T02:02:57+0000  us-east-1a  aki-3038da59  ari-3238da5b  monitoring-disabled
184.73.43.141  10.254.107.127  instance-store

第一条命令使用 ami-10b55379 AMI 启动这个实例并指定 清单 1 生成的密匙对将用于验证到机器。这个命令返回几条信息,最重要的是实例标识符(i-750fff1e),这是 Amazon EC2 云中的这台机器的身份。第二条命令使用 ec2-describe-instances 命令,该命令列示所有正在运行的实例。在 清单 3 中,实例标识符已经在命令行上传递以只显示关于该实例的信息。这个实例的状态列示为 pending,表示该实例还在等待启动。IBM AMI 比较大,因此它通常要花费 5-10 分钟来启动。稍后运行相同的命令显示状态变为 running,外部 IP 地址为 184.73.43.141。从 10 开始的内部 IP 地址对于在 Amazon EC2 内通信有用,但现在没有用。

然后,您可以使用 SSH 来连接到服务器,这还要用到您刚才生成的密匙。但是首先,您必须允许 SSH (22/TCP) 进入防火墙。清单 4 展示了如何授权这个连接并登录您的新服务器。

理解 SSH 密匙

如果您对 SSH 密匙不熟悉,那么知道 SSH 能够使用密匙而不是密码来验证用户是很有帮助的。您生成了一个密匙对,它由一个公共密匙和一个私有密匙组成。您将私有密匙保存为私有,并将公共密匙上传到一个名为 authorized_keys 的文件,该文件位于 $HOME/.ssh 目录中。当您使用 SSH 连接到服务器时,客户端会尝试使用该密匙验证。如果成功,您就登录进来。

密匙对的一个特性是使用密匙对中的一个密匙加密的消息只能使用另一个密匙解密。当您连接到服务器时,服务器能够使用 authorized_keys 文件中存储的公共密匙加密一条消息。如果您能使用您的公共密匙解密该消息,那么服务器就知道您被授权无需密码即可登录。

下一个逻辑问题是:“authorized_keys 文件如何使用存储在 Amazon 中的公共密匙填充?”每个 Amazon EC2 实例都能够与 Amazon EC2 云中的一个位于 http://169.254.169.254 的 Web 服务器进行通信并检索关于该实例的元数据。其中的一个 URL 是 http://169.254.169.254/latest/meta-data/public-keys/0/openssh-key,它返回与该映像关联的公共密匙。

启动时,这个 AMI 检索公共密匙并将其存储在 authorized_keys 中。这在样例 AMI 的 /etc/init.d/getssh 中完成。这与在 rc.local 中一样容易发生。

实例元数据的另一个用途是将信息传递到映像。您可能拥有一个通用 AMI,它可能是一个 Web 服务器或一个后台作业服务器,并让实例根据您启动映像时传入的参数来决定启动哪些服务。

清单 4. 连接到实例
[sean@sergeant:~]$ ec2-authorize default -p 22 -s $MYIP/32
...
[sean@sergeant:~]$ ssh -i ~/.ssh/main.pem root@184.73.43.141
The authenticity of host '184.73.43.141 (184.73.43.141)' can't be established.
RSA key fingerprint is af:c2:1e:93:3c:16:76:6b:c1:be:47:d5:81:82:89:80.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '184.73.43.141' (RSA) to the list of known hosts.
...

第一条命令认可来自您的 IP 地址的一个源的端口 22(TCP 是默认选项)。/32 意味着只有主机受支持,而不是整个网络。ssh 命令使用私有密匙连接到服务器。

安装 Ruby

CentOS 包含一个旧版 Ruby,因此您将安装 Ruby Enterprise Edition (REE),这是一个高性能 Ruby 解释器,与 Ruby 的当前 1.8.7 分支兼容。尽管其名称听起来价格昂贵,但实际上该软件是开源的。清单 5 展示如何安装 REE。

清单 5. 安装 REE
# rpm -e ruby ruby-libs
# yum -y install gcc-c++ zlib-devel openssl-devel readline-devel
...
Complete!
# wget http://rubyforge.org/frs/download.php/71096/ruby-enterprise-1.8.7-2010.02.tar.gz
...
# tar -xzf ruby-enterprise-1.8.7-2010.02.tar.gz
# ruby-enterprise-1.8.7-2010.02/installer -a /opt/ree

清单 5 的前两条命令移除默认 Ruby 安装并安装一个 C 编译器和几个必要的开发包。wget 下载当前 REE tarball,然后通过 tar 解包。最后,最后一条命令运行安装程序,选择接受所有默认值,并将结果放置在 /opt/ree 中。如果您缺少一些包,安装程序足够智能,能够告诉您必须运行的命令,因此,如果安装不能工作,请仔细查看输出。

安装 Ruby 后,使用 export PATH="/opt/ree/bin:$PATH" 将 bin 目录添加到您的路径,您可以将其放置到系统范围内的 /etc/bashrc 中或您的主目录中的 .bashrc 目录中。

安装 PostgreSQL

PostgreSQL 服务器是 CentOS 发行版的一部分,因此您需要做的是使用 yum 实用程序安装它。清单 6 展示如何安装 PostgreSQL 并确保它将在系统引导时启动。

清单 6. 安装 PostgreSQL
# yum -y install postgresql-server postgresql-devel
...
Installed: postgresql-devel.i386 0:8.1.21-1.el5_5.1 
   postgresql-server.i386 0:8.1.21-1.el5_5.1
Dependency Installed: postgresql.i386 0:8.1.21-1.el5_5.1 
   postgresql-libs.i386 0:8.1.21-1.el5_5.1
Complete!
# chkconfig postgresql on

yum 命令将从一个存储库安装包。在 清单 7 中,您正在安装 PostgreSQL 服务器组件和开发库。这样做将自动安装核心数据库实用程序和您需要的其他任何包。您现在还不需要开发包,但当您需要集成 Rails 和 PostgreSQL 时,您将需要 postgresql-devel 中的库。

默认情况下,数据库将其文件存储在 /var/lib/pgsql/data 中,这是根文件系统的一部分。您将这个目录移动到 /mnt 上的实例存储,如 清单 7 所示。

清单 7. 将 PostgreSQL 数据存储移动到 /mnt
# mv /var/lib/pgsql/data /mnt
# ln -s /mnt/data /var/lib/pgsql/data
# service postgresql start

输入 清单 7 中的命令后,PostgreSQL 逐步用尽 /mnt 目录空间。

接下来,您必须为 payroll_prod 数据库(将在下一步创建)启用密码登录。默认情况下,PostgreSQL 并不使用密码:它使用一个内部身份系统。只需添加:

host    "payroll_prod" all  127.0.0.1/32   md5

到 /var/lib/pgsql/data/pg_hba.conf 的顶部,然后运行:

su - postgres -c 'pg_ctl reload'

以使更改生效。通过这个配置,到 PostgreSQL 的普通登录不需要密码(这就是 reload 命令不需要密码的原因),但对 payroll 数据库的任何访问都将需要密码。

最后一步是从命令行设置 Rails 数据库。运行 su - postgres -c psql,并执行 清单 8 中的命令。

清单 8. 创建用户和数据库
postgres=# create user payroll with password 'secret';
CREATE ROLE
postgres=# create database payroll_prod;
CREATE DATABASE
postgres=# grant all privileges on database payroll_prod to payroll;
GRANT

这样就创建了数据库。

迁移数据

为了测试,您应该从您的生产环境的某个时点抓取一个数据库转储,以便您拥有可以测试的数据。SmallPayroll 应用程序将数据存储在数据库和文件系统中。数据库将使用 PostgreSQL 自带的 pg_dump 命令来转储;文件系统将使用 rsync。由于数据库转储的性质,所以必须擦除数据库并通过重新传输进行迁移,但文件系统只需传输新文件和更改后的文件,因为当文件更改后 rsync 能够检测到。这样,计划的测试部分能够帮助加速迁移,因为大部分数据已经在那里了。

复制数据库的最快方法是在您的生产机器上运行:

pg_dump payroll_prod | gzip -c > /tmp/dbbackup.gz

将 dbbackup.gz 复制到云服务器,然后运行:

zcat dbbackup.gz | psql payroll_prod

这条命令只是从一个服务器创建一个压缩转储,然后在另一台服务器上重播所有事务。

rsync 同样简单。从您的生产服务器,运行:

rsync -avz -e "ssh -i .ssh/main.pem" /var/uploads/ root@174.129.138.83:/var/uploads/

这条命令将 /var/uploads 中的所有内容从当前生产服务器复制到新服务器。如果再次运行该命令,只有更改后的文件被复制,为您节省了稍后的同步时间。

由于您正在复制数据库,因此您不必先应用您的 Rails 迁移。Rails 将认为数据库是最新的,因为您已经复制了 schema_migrations 表。

部署 Rails 应用程序

此时,您已经设置好基服务器,但您的应用程序还没有设置。在您的应用程序运行之前,您必须安装一些基础 gems,以及您的应用程序需要的任何 gems。清单 9 展示了更新您的 gems 的命令。注意,您必须位于您的 Rails 应用程序的根中,因此应首先将其复制到您的服务器。

清单 9. 更新 RubyGems 并安装您的 gems
# gem update --system
Updating RubyGems
Nothing to update
# gem install rails mongrel mongrel-cluster postgres
Successfully installed rails-2.3.8
Building native extensions.  This could take a while...
Successfully installed gem_plugin-0.2.3
Successfully installed daemons-1.1.0
Successfully installed cgi_multipart_eof_fix-2.5.0
Successfully installed mongrel-1.1.5
Successfully installed mongrel_cluster-1.0.5
Building native extensions.  This could take a while...
Successfully installed postgres-0.7.9.2008.01.28
7 gems installed
...
# rake gems:install
(in /home/payroll)
gem install haml
Successfully installed haml-3.0.12
1 gem installed
Installing ri documentation for haml-3.0.12...
Installing RDoc documentation for haml-3.0.12...
gem install money
...

第一条命令确保 RubyGems 本身是最新的。第二条命令安装一些有用的 gems:

  • railsRuby on Rails 框架。
  • postgres允许您使用 PostgreSQL 和 ActiveRecord 的数据库驱动程序。
  • mongrel用于托管 Rails 应用程序的应用程序服务器。
  • mongrel_cluster允许您同时启动和停止 mongrels 组的实用程序。

最后一条命令运行一个 Rails 任务来安装这个应用程序需要的所有其他 gems。如果您没有在您的 config/environment.rb 文件中使用 config.gem 指令,那么您可能必须使用 gem install gemname 命令来安装您的其他 gems。

尝试使用 RAILS_ENV=production script/console 命令来启动您的应用程序。如果这条命令成功,那么停止它,然后使用以下命令启动您的 mongrels 包:

mongrel_rails cluster::start -C /home/payroll/current/config/mongrel_cluster.yml

如果第一条命令没有成功,您将得到大量错误消息以帮助您找到问题,这个问题通常是缺失一个 gem 或文件。这也是返回去并加入任何缺失的 config.gem 指令的好机会,这样您将来就不会忘记这个 gem。

安装一个前端 Web 服务器

Nginx 是许多虚拟环境的首选 Web 服务器。它拥有较低的开销,擅长将连接代理到 mongrel 这样的后端服务。清单 10 展示如何安装 nginx。

清单 10. 安装 nginx
# rpm -Uvh http://download.fedora.redhat.com/pub/epel/5/i386/epel-release-5-3.noarch.rpm
...
# yum install nginx
...
Running Transaction
Installing     : nginx                                             [1/1]
Installed: nginx.i386 0:0.6.39-4.el5
Complete!
# chkconfig nginx on

清单 11 安装 Extra Packages for Enterprise Linux® (EPEL) 存储库,然后安装 nginx 并确保将它在启动时出现。

清单 11.针对 rails 应用程序的 nginx 配置
# Two mongrels, balanced based on least connections
upstream mongrel-payroll {
	fair;
	server 127.0.0.1:8100;
	server 127.0.0.1:8101;
}

server {
	listen 80;
	server_name  app.smallpayroll.ca;

	root   /home/payroll/current/public;
	gzip_static on;

	access_log  /var/log/nginx/app.smallpayroll.ca_log  main;
	error_page  404       /404.html;

	location / {
		# Because we're proxying, set some environment variables indicating this
		proxy_set_header X-Real-IP  $remote_addr;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header Host $http_host;
		proxy_redirect false;
		proxy_max_temp_file_size 0;


		# Serve static files out of Root (eg public)
		if (-f $request_filename) {
			break;
		}

		# Handle page cached actions by looking for the appropriately named file
		if (-f $request_filename.html) {
			rewrite (.*) $1.html;
			break;
		}

		# Send all other requests to mongrel
		if (!-f $request_filename) {
			proxy_pass http://mongrel-payroll;
			break;
		}
	}
	error_page   500 502 503 504  /500.html;
	location = /500.html {
		root   /home/payroll/current/public;
	}
}

清单 11 展示了一个非常典型的 nginx 配置,还添加了一些元素来处理 Rails 页面缓存并将动态请求发送到一个上游 mongrel。如果需要,您可以在这里将其他 URLs 映射到文件名。

这个配置准备好后,使用 service nginx start 来启动 Web 服务器。

测试

对于测试,能够使用您的应用程序的常规域名来引用您的云实例将会有所帮助,因为您想确保您现在使用的是测试站点而不是生产站点。这可以通过一个本地 DNS 覆盖来实现。在 Windows 中,编辑 C:\windows\system32\drivers\etc\hosts;在 UNIX 中,编辑 /etc/hosts。添加如下代码行:

x.x.x.x  app.smallpayroll.ca

其中 x.x.x.x 是您的云服务器的 IP 地址,app.smallpayroll.ca 是您的应用程序的名称。重新启动您的浏览器,浏览到您的 Web 站点。现在您正在使用您的应用程序的云版本。(如果您想返回到生产版本,不要忘了注释掉刚才添加的行!)

此时,您应该能够通过测试确保您的应用程序的云版本与生产版本的效果一样好并修复您发现的任何问题。详细记录您发现的所有问题,因为如果您启动第二台服务器,您需要对那些问题编写修复脚本。由于您正在使用您的应用程序的云版本,您可以删除并恢复您的数据库,这不会引起用户的抱怨。

绑定新 AMI

最后需要完成的任务是重新绑定您的 AMI。无论何时您启动一个新实例,您都会失去 /mnt 中的内容,您的根分区被重置为 AMI 中的内容。然而您对这个 /mnt 问题无可奈何,但重新绑定确保您的 AMI 保持原有状态。

如果您启动的 AMI 没有 AMI 工具,您可以使用以下命令安装这些工具:

rpm -i --nodeps http://s3.amazonaws.com/ec2-downloads/ec2-ami-tools.noarch.rpm

AMI 绑定过程分为三步:

  1. 在实例本身上创建映像。
  2. 将映像上传到 Amazon S3。
  3. 注册 AMI。

在继续之前,先关闭您的 mongrel 和 PostgreSQL 实例,这只是为了确保任何打开的文件都得到正确处理。您还必须将您的 X.509 密匙(可在 Amazon Console 中找到)复制到您的服务器上的 /mnt。清单 12 展示了前两个绑定步骤,它们在 VM 本身上完成。

清单 12. 绑定 AMI
# ec2-bundle-vol -d /mnt -e /mnt --privatekey /mnt/pk-mykey.pem  \
--cert /mnt/cert-mycert.pem --user 223110335193 -p centos-ertw
Please specify a value for arch [i386]:
Copying / into the image file /mnt/centos-ertw...
...
Generating digests for each part...
Digests generated.
Creating bundle manifest...
ec2-bundle-vol complete.
# ec2-upload-bundle -b ertw.com -m /mnt/centos-ertw.manifest.xml \
--secret-key MYSECRETKEY --access-key MYACCESSKEY
Creating bucket...
Uploading bundled image parts to the S3 bucket ertw.com ...
...
Uploaded centos-ertw.part.37
Uploading manifest ...
Uploaded manifest.
Bundle upload completed.

第一条命令生成绑定,规定 /mnt 将被忽略且绑定将进入 /mnt(分别是 -e-d 选项)。-k--cert--user 选项指向您的安全凭证和 AWS 用户 ID,它们都可以在您的 AWS Management Console 的帐户设置中找到。最后一个选项 -p 允许您命名这个 AMI,以便与其他 AMI 区分开。

第一条命令将运行约 10 分钟,具体时间取决于您的根分区有多满。第二条命令将这个绑定上传到 Amazon S3。-b 选项指定一个 bucket 名称,如果该名称还不存在,就会被创建。-m 选项指向在最后一步中创建的清单文件。最后两个选项是您的 Amazon S3 凭证,可以在 AWS Management Console 中您的 X.509 凭证的右边找到。只需记住 X.509 凭证用于 Amazon EC2 操作,而 Amazon S3 使用文本密匙。

最后,运行命令:

ec2-register ertw.com/centos-ertw.manifest.xml

以注册这个 AMI,您将看到从现在起将使用的 AMI 标识符。注意,ec2-register 并不与这个 AMI 一起分发,因此从您启动原始 AMI 的服务器运行它是最简单的方法。您也可以将这些 Amazon EC2 工具安装在您的 Amazon EC2 实例上。

执行迁移

现在您已经使您的云环境运行了,迁移本身应该相当简单。您已经验证一切都已正常工作:剩下的工作就是重新同步数据并按顺序执行了。

预迁移任务

在迁移之前的某个时间,确保将您的域名记录的 TTL 降低到 5 分钟。您还应该制定一个迁移步骤检查表、验证一切都能正常工作需要执行的测试,以及必要时返回更改前状态的流程。

确保您的用户已接收到迁移通知!

在迁移之前,再次检查您的云环境,确保它已准备好同步并接收生产流。

迁移应用程序

要迁移应用程序,执行以下步骤:

  1. 禁用当前生产站点或将其设置为只读模式,具体情况取决于站点的性质。

    由于 SmallPayroll 的大部分请求涉及对数据库或文件系统执行写操作,该站点应该被禁用。Capistrano 部署 gem 包含一个任务 cap deploy:web:disable,它在站点上放置一个维护页面,通知用户站点关闭以进行维护。

  2. 通过终止您的 mongrel 进程来停止云环境中的应用程序服务,为数据迁移做好准备。
  3. 按照测试中的方法复制您的数据库。
  4. 必要时再次运行 rsync
  5. 使用以下命令重新启动应用程序服务器:
    mongrel_rails cluster::start -C /home/payroll/current/config/mongrel_cluster.yml
  6. 确保您的主机文件正指向云环境,执行一些烟雾测试(smoke test)。确保用户能够登录并浏览站点。

更改 DNS

如果您的烟雾测试成功,那么将您的 DNS 记录更改为指向您的云环境。此时,我发现在 Web 服务器的日志文件上运行 tail -f 来监视进入站点的用户很有帮助。

您的本地 DNS 服务器可能仍旧在接下来的 5 分钟内缓存原来的信息。您可以通过使用 dig 命令来验证这一点,如 清单 13 所示。

清单 13. 验证 DNS 服务器正在缓存查询
# dig  app.smallpayroll.ca @172.16.0.23

; <<>> DiG 9.3.4 <<>> app.smallpayroll.ca @172.16.0.23
; (1 server found)
;; global options:  printcmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 38838
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 13, ADDITIONAL: 0

;; QUESTION SECTION:
;app.smallpayroll.ca.           IN      A

;; ANSWER SECTION:
app.smallpayroll.ca.    251     IN      A       69.164.205.185
...

在 ANSWER 部分,您可以看到,在条目失效之前还有 251 秒钟。重要的是要使用 dighostnslookup 这样的工具来验证 DNS,因为您的主机文件此刻正在覆盖 DNS。要使用主机内的资源,使用 ping 命令。

在等待 DNS 广播时,执行您的最后接受测试。

结束语

您已经将一个应用程序成功迁移到云了!基本的流程是:

  1. 设置新环境。
  2. 使用一个生产数据副本来进行测试。
  3. 关闭旧环境。
  4. 将生产数据复制到新环境。
  5. 将 DNS 更改为指向新环境。

尽管 “在云中”,但应用程序的性能可能还不如以前。注意以下几点:

  • 应用程序仍旧在一台服务器上运行。
  • 如果服务器崩溃,所有数据将丢失。
  • 与在物理服务器上相比,您对性能的控制能力减弱。
  • 机器和应用程序没有锁定。

在下一篇文章中,您将了解如何克服这些问题并开始为您的应用程序构建一个更健壮的环境。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Linux, Cloud computing, Open source
ArticleID=503631
ArticleTitle=将您的 Linux 应用程序迁移到 Amazon 云,第 1 部分: 初始迁移
publish-date=08022010