fastec2 脚本:运行和监控长时间运行的任务

技术
作者

Jeremy Howard

发布日期

2019年2月15日

这是 fastec2 系列的第2部分。关于 fastec2 的介绍,请参阅 第1部分

Spot 实例(竞价实例)特别适合长时间运行的任务,因为它们可以节省大量费用,并且你可以在进行大量计算的期间仅使用更昂贵的实例类型。fastec2 包含一些功能,可以使这种用例更加方便。让我们看一个例子。我们将执行以下操作:

  1. 使用廉价的按需 监控实例 来收集结果(并可选地启动任务)。在本指南中,我们将其称为 od1(但你可以随意命名)
  2. 创建一个执行所需工作的脚本,并将其所需的任何配置文件放在特定文件夹中。该脚本需要编写为将结果保存到特定文件夹,以便它们得以保存
  3. 在一个全新的实例中测试脚本是否正常工作
  4. 在 fastec2 下运行脚本,这将使其在新实例的 tmux session 中启动,所需文件将被复制过去,并且任何生成的结果都将复制回 od1
  5. 在脚本运行时,可以通过连接到其正在运行的 tmux session 或查看正在复制回 od1 的结果来检查其进度
  6. 完成后,实例将自动终止,我们将在 od1 上查看结果。

让我们看看它是如何工作的以及如何使用的详细信息。在本文的后面,我们还将了解如何使用 fastec2 的 快照 功能,以便更轻松地连接到大型数据集。

设置监控实例和脚本

首先,创建一个完成所需任务的脚本。在 fastec2 下运行时,脚本将在一个名为 ~/fastec2 的目录中启动,这个目录还将包含脚本所需的任何额外文件(不在你的 AMI 中的文件),并且会监控文件变化,将变化的文件复制回你的按需实例(在本指南中是 od1)。这里有一个我们可以用于测试的示例(我们将其称为 myscript.sh):

#!/usr/bin/env bash
echo starting >> $FE2_DIR/myscript.log
sleep 60
echo done >> $FE2_DIR/myscript.log

运行时,环境变量 FE2_DIR 将被设置为你的脚本和文件所在的目录。记住给你的脚本执行权限。

$ chmod u+x myscript.sh

在新实例上测试时,只需设置 FE2_DIR 并创建该目录,然后查看你的脚本是否运行正常(最好给你的脚本添加一个参数,使其在测试时运行一个快速版本)。

$ export FE2_DIR=~/fastec2/spot2
$ mkdir -p $FE2_DIR
$ ./myscript.sh

使用 fastec2 运行脚本

你需要一台正在运行的计算机,用于收集长时间运行脚本的结果。你不希望为此使用 spot 实例,因为它可能随时被关闭,导致你丢失工作。但这可以是一个廉价的实例类型;如果你的 AWS 账户创建时间不到1年,则可以免费使用 t2.micro 实例。否则,t3.micro 是一个不错的选择——如果一直运行,它的费用大约是每月7美元(加上存储费用)。

要在 fastec2 下运行脚本,你需要提供以下信息:

  1. 要使用的实例名称(首先使用 launch 创建它)
  2. 你的脚本名称
  3. 连接到 监控实例 以复制结果的附加参数([--myip MYIP] [--user USER] [--keyfile KEYFILE])。如果未提供主机,则使用运行 fe2 的计算机的 IP 地址。

例如,此命令将在 spot2 上运行 myscript.sh 并将结果复制回 18.188.16.203

$ fe2 launch spot2 base 80 m5.large --spot
$ fe2 script myscript.sh spot2 18.188.162.203

运行上面的 fe2 script 命令后会发生以下情况:

  1. 如果监控实例上尚不存在,将创建一个名为 ~/fastec2/spot2 的目录(它始终是 ~/fastec2 的一个子目录,并与你连接的实例同名,在本例中为 spot2)。
  2. 你的脚本被复制到此目录。
  3. 此目录被复制到 目标实例(在本例中为 spot2)。
  4. 在目标实例上创建一个名为 ~/fastec2/current 的文件,其中包含此任务的名称(在本例中为“spot2”)。
  5. 在目标实例的后台运行 lsyncd,它将不断地将目标实例上 ~/fastec2/spot2 目录中的任何新增/更改文件复制到监控实例。
  6. ~/fastec2/spot2/myscript.sh 在 tmux session 中运行。

如果你希望脚本完成后实例终止,请记住在脚本末尾包含 systemctl poweroff(对于 Ubuntu)或类似的命令。

创建数据卷

上述过程的一个问题是,如果你有大量不同的大型数据集需要处理,你要么需要将所有数据集复制到你要使用的每个 AMI 中(这既昂贵,又意味着每次添加数据集时都需要重新创建该 AMI),要么为每个数据集创建一个新的 AMI(这意味着当你更改配置或添加应用程序时,必须更改所有 AMI)。

一种更简单的方法是将数据集放到一个单独的 (即 AWS 磁盘)上。fastec2 可以轻松创建一个卷(格式化为 ext4,这是 Linux 上最常见的文件系统类型)。为此,最简单的方法是使用 fastec2 REPL(关于 REPL 的介绍,请参阅本系列的 第1部分的最后一节),因为我们需要一个可以连接到实例来挂载和格式化新卷的 ssh 对象。例如,要使用实例 od1 创建卷(假设它已在运行):

$ fe2 i
IPython 6.1.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: inst = e.get_instance('od1')

In [2]: ssh = e.ssh(inst)

In [3]: vol = e.create_volume(ssh, 20)

In [4]: vol
Out[4]: od1 (vol-0bf4a7b9a02d6f942 in-use): 20GB

In [5]: print(ssh.run('ls -l /mnt/fe2_disk'))
total 20
-rw-rw-r-- 1 ubuntu ubuntu     2 Feb 20 14:36 chk
drwx------ 2 ubuntu root   16384 Feb 20 14:36 lost+found

如你所见,新磁盘已挂载到请求的实例上的 /mnt/fe2_disk 目录下,并且新卷已获得与其创建实例相同的名称(od1)。你现在可以连接到你的实例并将数据集复制到此目录中,完成后,卸载卷(在你的 ssh session 中运行 sudo umount /mnt/fe2_disk),然后你可以使用 fastec2 分离该卷。如果你的上一个 REPL session 不再打开,你需要先获取你的卷对象,然后才能分离它。

In [1]: vol = e.get_volume('od1')

In [2]: vol
Out[2]: od1 (vol-0bf4a7b9a02d6f942 in-use): 20GB

In [3]: e.detach_volume(vol)

In [4]: vol
Out[4]: od1 (vol-0bf4a7b9a02d6f942 available): 20GB

将来,你可以通过 repl 重新挂载你的卷。

In [5]: e.mount_volume(ssh, vol)

使用快照

卷的一个显著缺点是,你一次只能将一个卷附加到一个实例。这意味着你不能使用卷来启动连接到同一数据集的多个任务。相反,为此目的你应该创建一个 快照。快照是卷的一个模板;从此快照创建的任何卷都将拥有与原始卷相同的数据。但是请注意,快照不会更新卷中添加的任何额外信息——快照中最初包含的数据保持不变。

从卷创建快照(假设你已经有一个卷对象 vol,如上所述,并且已将其从实例分离):

In [7]: snap = e.create_snapshot(vol, name="snap1")

现在你可以使用此快照创建一个卷,它会自动附加到你的实例。

In [8]: vol = e.create_volume(ssh, name="vol1", snapshot="snap1")

总结

现在我们已经集齐了所有拼图块。在以后的文章中,我们将讨论使用所有这些组件通过 fastec2 运行任务的最佳实践——但这里是流程的快速总结:

  1. 启动一个实例,并配置所需的软件和设置。
  2. 如果需要,为数据集创建一个卷,并从中创建快照。
  3. 停止该实例,并从中创建一个 AMI(可选地,完成后可以终止该实例)。
  4. 使用廉价的实例类型启动一个 监控实例
  5. 为你的长时间运行任务启动一个 spot 实例。
  6. 从你的快照创建一个卷,并附加到你的 spot 实例。
  7. 在该实例上运行你的长时间运行任务,并传入你的监控实例的 IP 地址。
  8. 确保你的长时间运行任务完成后关闭实例,以避免在完成后继续支付实例费用。(你此时可能也想删除从快照创建的卷。)

要运行更多任务,你只需重复最后4个步骤。你可以使用本指南中显示的 API 调用自动化该过程。