带有远程(AWS S3)目标的Makefile

4
我希望创建一个makefile,其中目标和依赖项不是本地文件,而是存储在AWS/S3桶中。
考虑以下示例,它将简单地将"data_raw"文件复制到"obj1",然后再复制到"obj2"(在运行此操作之前,您需要将“bucket”编辑为您拥有的某个桶,并创建一些“data_raw”文件):
# local, works fine
bucket = /tmp/test/
cp = cp

# remote, does not work
bucket = s3://bucket/test/
cp = s3cmd cp

all : $(bucket)obj2

$(bucket)obj2 : $(bucket)obj1
    $(cp) $(bucket)obj1 $(bucket)obj2

$(bucket)obj1 :
    $(cp) $(bucket)raw_data $(bucket)obj1

这个错误是:
makefile:9: *** target pattern contains no `%'.  Stop.

这是为了:

all : $(bucket)obj2

我怀疑make完全不理解远程URI(“s3://xxx”)。
我能找到的所有示例/文档似乎都隐含地将目标和依赖项与本地文件相关联。广泛的谷歌搜索只产生了一些看似未完成的有关为s3创建ant任务的想法(http://code.google.com/p/awstasks/)。
这是在Python中运行几个复杂的MapReduce作业的背景下。
我宁愿使用GNU make,但肯定会考虑其他选择。
我总是可以创建一些轻量级的本地镜像来代替远程目标,但肯定有更好的方法吧?
提前感谢!
尼克

Make在使用那里的文件来构建这里的文件方面表现最佳。但是这个makefile看起来并不太糟糕;你是想减少复杂性吗?你能从桶内运行Make吗? - Beta
这里的困难可能在于Make不接受远程URI作为目标或依赖项。我是否漏掉了一些愚蠢的东西(转义?)?Make应该能够处理哪种类型的URI?我想它主要需要测试存在性并获取日期,这是S3应该支持的吧? - Nic Mabon
我不知道 AWS/S3,但你能否使用几个本地文件作为代理,仅用touch指示真实文件已被修改,并使用synch目标将它们与主要文件同步更新? - Beta
是的,那是我在问题的最后一行建议的一个途径。它感觉更像是一个变通方法而不是真正的解决方案。你对Make及其许多等效工具有多深入的了解?你知道有没有一种本地支持远程资源的工具?例如,是否可能提供一些脚本来重载存在和新鲜度的测试? - Nic Mabon
3个回答

2
一种可行的解决方法是在本地挂载 S3 存储桶。
在 Linux 上,可以使用 fuse/s3fs。这也可能适用于 MacOS,但安装起来似乎非常麻烦。我转而使用商业软件transmit(点击“作为磁盘挂载”)。有了它,上述示例对我来说是可用的:
bucket = /Volumes/s3.amazonaws.com/bucket/test/
cp = cp

在这个示例中,我们使用“cp”,因为“s3cmd cp”拒绝本地uri。在一个(我的)真实示例中,该命令将被一些Python MapReduce脚本替换,需要实际的S3输入/输出URI。
为了保持整洁,可能应该有一个前缀变量("/Volumes/s3.amazonaws.com/")用于本地挂载文件(以测试存在性/最新性),并且一个前缀变量("s3://")用于构建命令来指向实际数据(数据将通过MapReduce由EC2实例进行处理,我们绝对不想下载所有东西到本地)。
请记住,S3只是最终一致性。还要确保为了测试存在性和最新性,不会将整个文件下载到本地(在这种情况下应该使用一些虚假文件)。
希望这有所帮助。
如果有更直接的方法(无需本地挂载),我很感兴趣。
Nic

0

我喜欢你的想法。但是,如果这个功能被集成到makefile和make中,我会感到惊讶;正如你所指出的,“Linux”的做法是找到一种将S3挂载为文件系统的方法。

然而,如果你需要“类似make”的工具,我建议使用Ruby宇宙中的rake。虽然我已经有一段时间没有用它了,但我记得它允许你编写自定义扩展,以便你的源和目标不必在本地文件系统上。

如果Ruby在我通常工作的那些系统(相当裸露的EC2和ECS系统,没有管理员权限)上更为普及,我会把所有我的make文件都切换到rake文件。


0

Make使用文件系统来确定它需要从哪些先决条件构建哪些目标。

除非将S3上的文件和目录挂载到文件系统上(例如使用类似已提及的s3fs FUSE的工具),否则无法将其用作目标或先决条件。

您可以将其作为Makefile的一部分挂载,类似于以下方式:

BUCKET      = bucket-name
BUCKET_DIR  = /

s3:
    mkdir --parents $@
    findmnt $@ || s3fs $(BUCKET):$(BUCKET_DIR) $@

s3/foo: foo | bin
    cp $< $@

这将创建挂载点s3,如果不存在的话。
如果尚未挂载,请使用s3fs在该目录上进行挂载。
现在,您应该能够使用S3上的对象运行Make。
注意:在这种情况下,$<$@只是Make中的花哨变量,分别表示foos3/foo,因此它将运行cp foo s3/foo
请注意,可能还有其他关于远程存储一致性的考虑事项,可能会出现与时间等相关的问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接