云中的 Python

作者: Adrian Klaver

使用 Python boto 库与 AWS 服务和资源交互的基本介绍。

本文探讨了使用 boto 库来操作 Amazon Web Services (AWS) 云中的资源。对于那些想知道的人,boto 的名字指的是亚马逊河中发现的一种淡水海豚。boto 由 Canonical 公司 Eucalyptus 团队的 Mitch Garnaat 维护。该库涵盖了 AWS 提供的许多服务,但并非全部(有关当前列表,请参见 boto 网站)。

但是,在开始介绍 boto 的使用和维护之前,请允许我稍微跑题一下。可能不用说,如果您想参与其中,则需要设置一个 AWS 账户。如果您已经拥有 Amazon 账户,则只需在 AWS 网站(请参阅“资源”)上注册 Amazon 即可设置您的 AWS 账户。否则,您需要先设置一个 Amazon 账户。作为 AWS 账户设置的一部分,您将获得一些凭据(稍后您将使用这些凭据)。请注意,如果您是 AWS 的新用户,请查看免费套餐优惠(请参阅“资源”)。这使您可以在很大程度上免费试用。对于本文,我尽量遵守优惠限制。

在 AWS 设置完成后,让我们继续安装 boto。在撰写本文时,当前版本为 2.0b4,这也是我在本文中使用的版本。boto 可从 Python Package Index (PyPi) 获得,您可以使用 easy_install boto 安装它。请记住,如果您希望它是系统范围的库,请以超级用户身份执行之前的操作。您也可以转到 PyPi 或 boto 站点并下载 tarball,然后执行 Python setup.py install。PyPi 站点仅提供最新版本;boto 站点提供各种版本。

现在,内务处理已完成,是时候开始使用了。如上所述,boto 允许您访问许多 AWS 服务——实际上,比我在这里可以涵盖的服务要多得多。本文涵盖 Amazon Machine Image (AMI)、Elastic Block Store (EBS)、Elastic Compute Cloud (EC2)、Simple Storage Service (S3) 和 Simple Notification Service (SNS)。其中 AMI 是虚拟机,EBS 是虚拟硬盘,EC2 是您在其中运行 AMI/EBS 组合的云,S3 是键/对象存储,SNS 是来自云的消息传递系统。在所有这些情况下,boto 都需要账户信息才能访问 AWS。您需要 AWS 访问密钥和 AWS 秘密访问密钥。它们是在您注册时创建的,但如果您没有记录它们,请不要担心。它们在您的 AWS 账户页面中作为安全凭证提供。

为了使事情更轻松、更安全,可以选择在连接字符串中包含信息。第一个选项是创建 AWS_ACCESS_KEY_ID 和 AWS_SECRET_ACCESS_KEY ENV 变量,并将它们设置为各自的密钥。另一个选项是在您的主目录中创建一个 .boto 文件,并使用 ini 样式设置密钥(清单 1)。

在进一步介绍之前,我应该指出 AWS 为其大多数服务提供了一个基于 Web 的管理工具。它被称为 AWS Management Console,您可以通过访问 AWS 站点并单击页面顶部的“账户”选项卡来访问它(在接下来的内容中,我将引用并使用此工具)。管理控制台对于确认 boto 代码实际上正在执行其应执行的操作也很方便。请记住,如有疑问,请单击控制台顶部的“刷新”按钮。

清单 1. boto 配置文件

#.boto file format

[Credentials]
aws_access_key_id = <some_access_key>
aws_secret_access_key = <some_secret_access_key>

接下来是 boto 和 AWS 之间交互的基本介绍。代码保持简单,既是为了节省空间,也是为了说明基本原理。首先,我需要创建自己的 AMI 才能使用。最简单的方法是抓取现有的公共镜像并将其设为私有。我使用 Canonical 维护的 Ubuntu 镜像供自己使用。查找可用镜像的最佳位置是 Alestic 站点(请参阅“资源”)。它有一个方便的表格,标签为“Ubuntu 和 Debian AMI for Amazon EC2”,带有 AWS 区域的选项卡。单击您想要的区域,然后选择合适的镜像。对于本文,我选择了美国东部 1 区的 Ubuntu 10.04 LTS 64 位 EBS AMI,其 AMI ID 为 ami-2ec83147(ID 可能因新镜像的构建而异,请参阅 EBS/S3 AMI 边栏)。单击镜像旁边的箭头会将我带到 AWS Management Console(登录后)以从该镜像启动实例。

为了利用免费套餐,我选择了微型实例。此时,我的账户上正在运行公共镜像的实例。要制作私有镜像,我可以使用管理控制台,方法是右键单击实例并选择“创建镜像”,但这有什么乐趣呢?让我们使用 boto 来代替(清单 2)。这很简单。导入 boto 便利函数 connect_ec2,并注意连接代码中缺少访问凭据。在这种情况下,它们位于我的主目录中的 .boto 文件中。然后,我使用 create_image() 创建并注册一个私有 AMI,使用从管理控制台启动的正在运行的实例 (i-c1315eaf),名称为 lj_test。create_image 函数返回 AMI ID——在本例中为 ami-7eb54d17。

EBS 与 S3 AMI

以下是关于 EBS 支持的 AMI 和 S3 支持的 AMI 之间差异的一些说明。当 AWS 首次启动时,S3 AMI 是规则。它们将镜像根设备存储为 AWS S3 存储服务中的一系列数据块。S3 支持的 AMI 也称为实例存储 AMI。后来,EBS 支持的 AMI 可用。这些将根设备存储为 EBS 卷。这有一些实际考虑因素,例如以下内容

  • S3 的最大根设备大小为 10GiB,EBS 的最大根设备大小为 1TiB。

  • EBS 的启动时间更快,因为根设备不必先组装。

  • 停止:EBS AMI 实例除了终止外,还能够停止,这大致相当于暂停状态。S3 支持的实例只能终止。

有关更详细的比较,请参阅本文“资源”中列出的 URL。

安全

安全性,与往常一样,在讨论 Internet 上的服务器时是一个重要问题。标准程序适用于 EC2 实例,也适用于常规服务器。有关这些内容,请参阅 Mick Bauer 在先前 LJ 期刊中撰写的 Paranoid Penguin 专栏,以及任何数量的安全参考资料。

但是,有一个与 AMI 相关的特殊情况值得一提。如本文所示,可以获取公开可用的 AMI 镜像并将其制作为您自己的私有镜像。这带来了一些特殊问题;请参阅“资源”部分中的“安全 URL”。在创建生产实例之前,最好阅读该信息并牢记在心。对于另一方面,请查阅 Alestic 博客(请参阅“资源”),了解如何创建安全的 AMI 以与他人共享,而不会泄露您的私人信息。

清单 2. 使用 boto

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time
from boto import connect_ec2, connect_sns

# Create private image
con = connect_ec2()
con.create_image("i-c1315eaf", "lj_test")

# Launch/run instance(s)
reserv = con.run_instances("ami-7eb54d17",
    min_count=2, max_count=5, key_name='laptop',
    instance_type="t1.micro",
    placement="us-east-1d",
    disable_api_termination=True)

# Disable termination protection
con.modify_instance_attribute("i-132e457d",
    "disableApiTermination", False)

# Find running instances
res_list = con.get_all_instances(
    filters={"image-id": "ami-7eb54d17",
        "instance-state-name": "running"})

# Find instance information
for reservation in res_list:
    inst_list = reservation.instances
    for instance in inst_list:
        instance.id, instance.state
# See Figure 1 for output.


# Create a tag
con.create_tags(["i-391c2657"],
    {"Name": "lj_instance"})
con.create_tags(["vol-a9590ac2"],
    {"Name": "lj_volume"})


# Get volume
vol = con.get_all_volumes(
    filters={"tag:Name": "lj_volume"})[0]

# Create snapshot
snap = vol.create_snapshot(vol.tags["Name"]\
    + "Snap")

# Monitor snapshot creation and notify on completion
def check_snapshot(snap):
    while snap.status != "completed":
        print "Sleeping"
        time.sleep(30)
        snap.update()
    g_time = time.gmtime()
    msg_str = "Snapshot " + snap.id + "\n"
    msg_str += "of volume " + snap.volume_id + "\n"
    msg_str += "started at time "
    msg_str += snap.start_time + "\n"
    msg_str += "completed at "
    msg_str += time.asctime(g_time)
    ARN = "arn:aws:sns:us-east-1:213825411462:Lj"
    sns_con = connect_sns()
    sns_con.publish(ARN, msg_str, "Snapshot done")
    print msg_str

下一步是通过启动其一个或多个实例来使用该镜像。为此,请参阅清单 2 中带有 con.run_instances() 的行。先前创建的 AMI 用作实例的模板。

min_countmax_count 参数需要一些解释。AWS 默认限制每个区域每个账户可以运行 20 个实例(可以通过填写请求表来增加此限制)。这就是 min/max 计数发挥作用的地方。如果我已经在一个区域中运行了 18 个实例,并且我将 min_count 设置为 2,将 max_count 设置为 5,则将启动两个新实例。

密钥名称是由 Amazon 生成的 SSH 密钥对,用于 SSH 访问实例。

instance_type 设置为 EC2 微型实例,并且通过 placement 参数将其安排在 us-east-1d 可用区中运行。让我们简要介绍一下 AWS 可用区。可用区相对于您的账户。换句话说,我的 us-east-1d 可能不代表与您的 us-east-1d 相同的物理可用区。

最后一个参数 disable_api_termination=True 是一种锁定机制。它可以防止使用 API 终止调用来终止实例。具有此保护功能的实例必须首先将该参数更改为 False,然后发出终止命令才能消失。请参阅 modify_instance_attribute() 行,了解如何撤消正在运行的实例上的终止保护。

假设成功启动,run_instances() 将返回一个 boto 预留类,该类表示 AWS 创建的预留。然后可以使用此类查找正在运行的实例,假设它已被捕获并立即迭代。更通用的方法是使用 get_all_instances() 函数返回与给定条件匹配的预留类列表。在清单 2 中,我使用 filter 参数将我的实例搜索限制为从上面创建的 AMI 创建的实例,并且这些实例实际上正在运行。

那么,在哪里可以找到可用的过滤器呢?boto 文档没有列出过滤器,而是将您指向源,即每个资源的 AWS 开发人员文档(请参阅“资源”)。深入研究该文档,您可以找到 API 参考,其中详细说明了各种操作的选项。对于此特定情况,信息位于 EC2 API(请参阅“资源”)下的“操作/DescribeImages”中。boto 函数名称和 AWS API 名称之间并非完全一一对应,但它们足够接近,可以弄清楚。

运行该函数后,我现在有一个预留列表。使用此列表,我迭代列表中的预留类,这将产生一个包含实例类的实例列表。然后,依次迭代此列表,并提取各种实例属性(图 1)。

图 1. EC2 实例信息

创建了 AMI 并使用该镜像启动了实例之后,现在怎么办?如何备份实例中包含的信息?AWS 具有一项功能,可以通过该功能创建 EBS 卷的快照。这样做的好处是快照本质上是增量的。在第一天拍摄快照,它代表该卷在该时间点的状态。在第二天拍摄快照,它仅代表两天之间的差异。此外,快照虽然代表 EBS 卷,但存储为 S3 数据。这样做的好处是,尽管 EBS 的每月费用是基于卷的大小(无论是否使用空间),但 S3 的费用是基于实际使用的空间。因此,如果您有一个 40GB 的 EBS 卷,则每月收费 40GB。假设仅使用了一半,则快照将产生每月大约 20GB 的费用。快照的最后一个功能是,可以从中创建一个 EBS 卷,而该卷又可以用于创建新的 AMI。这使得相对容易地返回到过去的某个时间点。

为了使快照过程更容易,我将在实例上创建一个标签,该实例具有我要快照的 EBS 卷,以及卷本身。AWS 支持在其许多资源上使用用户定义的标签。create_tags() 函数是一个通用函数,它将标签应用于请求的资源。第一个参数是资源 ID 列表;第二个参数是一个字典,其中标签名称是键,标签值是字典值。了解实例的 Name 标签后,我使用带有过滤器的 get_all_volumes() 来检索卷类。然后,我使用卷类创建快照,并将快照的 Description 设置为卷 Name 标签加上字符串 Snap。虽然 create_snapshot() 将很快返回快照 ID,但快照可能需要一段时间才能完成处理。这就是 SNS 服务派上用场的地方。

SNS 确实如此,是一种发送通知的简单方法。通知可以以电子邮件、JSON 格式的电子邮件、HTTP/HTTPS 或 AWS Simple Queue Service (SQS) 的形式发送。我在这里不深入介绍 SQS;只需知道它是一种从 AWS 发送消息的更强大且功能更丰富的方式。

第一步是设置通知主题。最简单的方法是使用 AWS 管理控制台中的 SNS 选项卡。主题只是特定通知的标识符。创建主题后,可以将订阅绑定到该主题。订阅在确认之前不会生效。对于发送到电子邮件的订阅(我在这里使用的),会发送一封确认电子邮件,其中包含确认链接。确认订阅后,即可使用。

正如我之前提到的,我演示了使用快照创建过程监控完成时的通知(清单 2)。函数 check_snapshot() 接受 create_snapshot 返回的快照类,并定期检查其进度。请注意 snap.update()。AWS API 是基于 Web 的,并且不维护持久连接。除非快照立即返回“completed”状态,否则 while 循环将无限期运行,而没有 update() 方法来刷新状态。

快照完成后,将使用快照属性构造消息。然后将消息发布到 SNS 主题,这将触发订阅运行,并且应该很快出现一封电子邮件。显示的 ARN 代表 Amazon Resource Name。它是在设置 SNS 主题时创建的,代表主题的系统地址。请注意,SNS 的简单部分在于没有传递确认。如果 AWS API 无法执行其部分(发送消息),它将抛出错误,但不涵盖接收错误。这就是 SNS 的发送选项之一是 SQS 的原因。SQS 将保留消息并在一定时间段内或直到收到收到确认和删除请求(以先到者为准)才重新发送消息。

这就是您所拥有的——使用 Python boto 库与 AWS 服务和资源交互的基本介绍。不用说,这仅仅是冰山一角。有关更多信息和保持最新状态,我推荐 Alestic 站点的博客,以获取一般 AWS 信息,以及 Mitch Garnaat 的博客,以获取 boto 和 AWS 信息。

资源

boto 网站:http://code.google.com/p/boto

什么是 boto?http://www.acsonline.org/factpack/Boto.htm

boto 文档:http://boto.cloudhackers.com

boto 博客:http://www.elastician.com

AWS 网站:http://aws.amazon.com

使用公共 AMI:http://aws.amazon.com/articles/0155828273219400

创建安全 AMI:http://alestic.com/2011/06/ec2-ami-security

EBS 与 S3:http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/Concepts_BootFromEBS.html

AWS 免费套餐:http://aws.amazon.com/free

AWS 开发人员文档:http://aws.amazon.com/documentation

EC2 API:http://docs.amazonwebservices.com/AWSEC2/latest/APIReference

Alestic:http://alestic.com

加载 Disqus 评论