埃里克·普劳泽特在 Unsplash 上拍摄的照片
几个月前,我决定辞职去旅行。接下来是一个夏天的冒险,然后,一瞬间,我发现自己回到了细雨蒙蒙的伦敦,准备考虑重新进入就业市场。自然地,我想知道我是否能收集一些数据来帮助引导我的思考。
在的上一篇文章中,我探索了如何使用 Reed API 以编程方式搜索相关的工作列表。但是如果我想让我的搜索保持新鲜呢?在本文中,我们将使用 AWS 来安排我们的代码每天获取和存储这些工作列表。
你可能已经注意到这篇文章的标题有点骗人。使用 API 并不是真正的 web 抓取,但是如果它是一个选项,它会可靠得多。然而,从根本上来说,这篇文章是关于建立一个可伸缩的机制来重复调用互联网,所以它可以很容易地应用于 web 抓取。
免责声明:本文仅用于教育目的。我们不鼓励任何人抓取网站,尤其是那些可能有条款和条件反对此类行为的网站。
要在家里复制这一点,你需要一个 AWS 帐户,掌握 python,Reed 的 API 密匙(你可以在这里注册),以及安装 Docker Desktop 的能力。AWS 对完成的解决方案每天收取我 12 美分。
需求非常简单——我有一些从 API 获取工作列表的代码,我希望这些代码每天都运行。鉴于我不想让我的笔记本电脑全天候运行,我需要使用 AWS(或其他云计算服务)。
为了最大限度地降低成本和工作量,我需要一个无服务器或托管的解决方案。AWS Lambda 是一种非常简单的方法,但是每个 Lambda 最多只能运行 15 分钟,不幸的是,这对我来说太短了。我的代码运行需要 20 分钟,即使不需要,我也想要一个可伸缩的解决方案。如果我决定大幅度扩大我的求职范围,这种方法同样有效。设计一个依赖我的代码的系统从来都不是一个好主意,永远不会变得更慢。
我可以设计一些混乱的方式来触发连续的 lambdas,直到全部工作完成,但是当理想情况下,我想要一些灵活的东西时,我会创建一个非常具体的解决方案。
输入 AWS 批次 。这项出色的服务允许您运行和安排批处理作业,而无需担心基础设施。我们只需要定义工作和我们想要的资源,剩下的就交给 AWS 了。
本文大部分是技术教程,所以如果你对具体细节不感兴趣,可以去 我的下一个故事 ,那里我会分析数据来了解工作薪水、技能、趋势等等!
AWS Batch 不会像 Lambda 那样执行简单的 python 脚本。AWS 批处理通过执行 Docker 映像来工作。
如果你不熟悉 Docker,基本上有三点需要理解:
- 一个 Docker 容器类似于一个轻量级虚拟机。它本质上是一个独立的系统,包含我们运行给定应用程序所需的一切。例如,我们的容器将需要包含 python 的安装。
- 一个 Docker 图像是一个可以用来创建容器的模板。它是一个多层文件,包含创建该容器所需的一切。容器是一个图像的可运行实例,虽然图像是不可变的,但是它可以产生几个独立的容器。
- 一个 Dockerfile 是一个文本文件,它包含一组简单的指令,用于定义 Docker 映像的创建。
首先,安装 Docker 桌面。
在上一篇文章中,我们有两个脚本:一个用于搜索 jobs 数据库并返回清单的基本细节(reed_summary_fetcher.py
),另一个用于遍历这些清单以获取它们的完整细节(reed_details_fetcher.py
)。提醒一下,这是第一个脚本:
这是第二个:
我们需要为每个脚本创建不同的 Docker 映像,所以首先,在您的笔记本电脑上为每个脚本创建一个本地文件夹。每个本地文件夹都有三个组成部分:脚本、python 包的 requirements.txt 文件和 Docker 文件(按照惯例,它总是被简单地命名为 Dockerfile ,没有扩展名)。以下是第一个脚本的 docker 文件:
这套简单的说明将告诉 Docker 如何制作图像:
- 从包含所有 python 设置的现有公共映像开始
- 创建一个名为
app
的新目录,将本地工作目录中的所有文件添加到映像中,并将app
定义为工作目录 - 安装我们需要的任何 python 包
- 运行 python 脚本
您的 requirements.txt 文件只需要以下 python 包:requests、boto3 和 datetime。
除了要运行的 python 文件的名称之外,第二个 python 脚本的 Dockerfile(获取清单细节)是相同的。
要测试这是否有效,请打开一个终端并运行:
docker build -t <image name> .
如果成功,当你输入docker images
时,你应该能看到你的图像。你可以通过输入docker rmi <image name or ID>
来删除它。
AWS Batch 无法使用您笔记本电脑上的 Docker 映像。我们需要将您的图像放入亚马逊的图像存储 ECR。由于没有办法将图像拖放到 AWS 中,我们必须使用命令行界面。
如果你以前没有用过这个,你首先需要在你的本地机器上安装客户端。接下来,您需要导航到 AWS 中的 IAM 部分来生成一个密钥对(除非您已经有了一个)。这个密钥对对于验证您的本地机器和您的 AWS 帐户之间的连接是必需的。出于安全原因,最好为 IAM 角色而不是根用户生成访问密钥。最后,您可以配置您的 AWS CLI,方法是在本地机器上的终端中键入aws configure
,并在出现提示时提供您的密钥对和区域。你可以在这里得到更详细的说明。
您只需配置一次 AWS CLI 之后,它将能够自动认证。
导航到 AWS 中的 ECR 控制台,并选择“创建新存储库”。一个存储库可以包含多个映像,但是通常的最佳实践是一个存储库包含一个映像(或者同一映像的所有不同开发版本)。因此,我们将需要一个存储库用于第一个脚本(我称之为 mine reed-summary )和一个存储库用于第二个脚本(我称之为 mine reed-details )。你可以只输入一个名字,其他的都是默认的。
如果你点击进入你的新存储库,有一个方便的按钮,上面写着“查看推送命令”。点击这个按钮可以获得您需要在本地终端上运行的命令集。这些命令执行以下操作:
- 验证与 AWS 的连接
- 在当地建立你的形象
- 用您的 ECR 存储库标记您的映像(加上一个常规标记来表示这是映像的最新版本)
- 将您的映像推送到您的存储库
如果因为任何原因,这些命令看不到,你可以在这里得到它们,你也可以从 ECR 存储库主页得到存储库 URI。
记住要做两次——我们有两个 python 脚本,每个脚本都需要放入自己的映像中,存储在自己的 ECR 存储库中。
我们已经有了我们的图像——创建小 python 框来运行我们的脚本的模板——现在我们只需要 AWS 运行它们的方法。
我们的基本设置如下图所示:Eventbridge 触发器将告诉 Batch 运行一个作业;Batch 将从 ECR 中获取我们的图像,并将其作为一个容器运行;该容器将运行我们的 python 代码,python 代码将从 Reed API 获取数据并保存到 s3。
作者图表
这听起来很简单,但是在它的内部,AWS Batch 有以下组件:
- 一个计算环境定义了你的工作将在其上运行的基础设施
- 作业定义通过陈述相关的 docker 映像和其他配置来定义作业——您想要执行的任务
- 作业是作业定义的运行实例
- 作业队列将作业传递到相关的计算环境中执行
是时候再次动手了!
任何令人兴奋的 AWS 服务的无聊序言——所有的设置都是为了确保我们的各种组件可以安全地相互通信。文档非常好,所以我们将快速浏览一下。
- AWS Batch 需要知道将计算资源放在哪里,所以创建一个 VPC(指令在这里或在这里)。确保它有一个公共子网。
- 您需要一个安全组来为您的计算环境把关入站和出站流量。在你的新 VPC 里创造一个。默认情况下,向导应该向所有 IP 建议一个通用出站规则,而不建议入站规则;这对我们来说很好。(在现实世界中,如果我们的 Reed API 端点坚持一组静态的 IP 地址,我们将进一步完善这条规则。)
在我们的用例中有三个不同的 IAM 角色。
- 服务角色管理 AWS 批处理调用其他 AWS 服务所需的权限。例如,Batch 需要使用其他 AWS 服务来管理每个作业的计算资源。该角色将在我们设置计算环境时自动创建。
- 执行角色管理 ECS 代理调用其他 AWS 服务所需的权限。例如,从 ECR 中提取图像。按照此处的说明设置该角色ecstaxecutionrole。
- 任务角色授予正在运行的容器更多的权限。在现实世界的场景中,我们有许多作业都运行不同的映像用于不同的目的,每个作业可能有不同的作业角色,同时共享相同的最小执行角色。
我们需要我们的容器能够向 S3 写对象,所以我们需要创建一个作业角色。转到 IAM 控制台中的创建角色向导,选择“AWS 服务任务”作为可信实体,选择弹性容器服务作为用例,选择 AmazonS3FullAccess 和ecstaxecutionrole作为您的策略。我把这个角色命名为 s3-put-iam 。
在 AWS 控制台中搜索批处理,转到计算环境,然后点击创建。
这里的几乎所有内容都可以保持默认,包括 AWS 提供的创建服务角色。使用 Fargate 选项可以最大程度地简化无服务器操作。
在网络部分,选择我们的新 VPC 及其公共子网(我们的计算资源将需要访问互联网以获取我们的数据),以及我们的新安全组。
从侧边栏进入工作定义控制台,点击创建。我们没有做任何繁重的工作,所以单节点选项对我们有好处。选择 Fargate 平台类型,并选择我们之前创建的ecstakexecutionrole。我们还需要启用公共 IP,这样我们就可以享受出站互联网访问。
再往下,提供簧片-总结图像的位置(URI)。提供我们的S3-put-iam**角色作为作业角色,并提供环境变量配置中的 Reed API 键作为API_KEY
(因为这是 python 代码所期望的)。
您需要设置其中两个作业定义——一个用于钢筘汇总图像,一个用于钢筘详细信息图像。
从侧边栏进入作业队列控制台,点击创建。您只需要命名您的作业队列并选择计算环境。
您可以为作业队列和作业定义设置优先级,让 AWS 知道哪些作业优先,但是因为我们每天只运行两个连续的作业,所以可以忽略这一点。
您可以在批次中的作业部分提交一个新作业,点击提交新作业,选择作业定义和作业队列(其他保持默认)。这是检查一切是否正常的好方法——AWS Batch仪表板概述了提交到每个队列的作业,而作业部分显示正在运行或最近运行的作业。您可以通过单击这些作业来查找作业日志,以便解决任何问题。如果您需要更改作业定义,Batch 允许您进行版本修订,这是跟踪更改的好方法。
有点违背直觉,为了让这些作业按计划运行,我们需要脱离 Batch,进入 AWS Eventbridge 。该服务允许我们为其他服务创建触发器。
在 Eventbridge 中创建规则非常简单。出于我们的目的,我们需要两个规则,每个工作(图像)一个。为了简单起见,我使用一个 cron 表达式来每天运行一次每个作业,开始时间间隔为一小时(以确保第一个作业已经完成)。例如,10 2 ** ? *
将作业安排在每天早上 02:10。在实际场景中,我们会给第一个作业一个基于时间的触发器,并设置第二个作业在第一个作业成功完成后运行。
做一件极其简单的事情——每天运行两个小 python 脚本——可能感觉需要相当大的努力。而且……的确如此。如果不是 AWS Lambda 的超时限制,我们也不会为 Batch 费心,这篇文章也会短很多。
但是一旦我们设置好批处理,我们就有了一个非常可扩展的解决方案。我可以将数以千计的作业按优先级排序。如果我的工作变得更加繁重,我可以扩展我的计算环境。如果有必要,我甚至可以管理自己的资源,选择 AWS 提供的任何类型的计算机,包括 GPU,如果我的任务需要它们的话。
在我的 AWS 批处理作业每天运行五个月后,我分析了产生的数据,以了解英国数据部门的职称、工资和技能。前往我的下一篇文章了解更多信息!