为云简历挑战赛创建AWS + NextJS网站

Title card of the project with the text

我最近完成了 Forrest Brazeal 创建的云简历挑战。该挑战涉及通过完成一组称为“Chunks”的挑战,使用现代云技术构建简历网站。对于我的版本,我在 NextJS 中创建了一个静态简历网站,该网站托管在 S3 和 Cloudfront 上,并具有使用 Lambda 和 DynamoDB 实现的用户计数跟踪功能。我还应用了现代 DevOps 原则,通过使用 Terraform 将基础设施部署为代码,使用 GitHub Actions 创建 CI/CD 管道,并使用 Cypress 执行端到端测试。完成这项挑战让我感觉如沐春风。虽然我在大学期间参与过许多网络项目,但我并没有像完成这项挑战一样对软件开发获得如此多的见解和新视角。

第一部分:前端

Cloud Resume Challenge 分为四个部分,每个部分包含构建项目各个组件的一系列步骤。我从第一个部分开始,构建简历网站的前端,该网站由使用 NextJS 构建的网站组成。挑战只需要一个基本的 HTML/CSS 网站,但我选择使用 NextJS,因为根据过去处理过 Web 项目的经验,纯 HTML/CSS 网站在未来将比 NextJS 这样的生产级平台更难维护。我还决定使用这个框架,因为它在创建服务器端和静态网站方面都很灵活,我想为未来的项目积累使用这个框架的经验。我还选择使用 Terraform 比要求更早地将前端组件实现为基础设施即代码 (IaC)。这个决定使这个工具的学习过程更容易,因为它允许我在更简单的架构上编写 IaC 代码,当我以后必须将整个项目转换为 IaC 时,这将节省我的时间。

The resume website side-by-side with the source code written in Javascript

然后,我使用 S3 存储桶将网站部署到 AWS,并将网站缓存在 Cloudfront CDN 服务上。我还通过使用 AWS 证书管理器实施 HTTPS 来保护发送到网站的 Web 请求。到目前为止,这与我过去的项目没有太大区别,但随着我进入下一个阶段,我过去的经验将变得越来越没用。

第二部分:后端

第 2 和第 3 块的主要功能是访客计数。挑战需要一个持久计数器来显示浏览页面的访客数量,并在用户每次刷新页面时更新该数字。我开始在块 2 中研究此功能的后端,用 Python 编写一个 Lambda 函数,该函数每次访客查看网站时都会将用户计数作为统计记录存储并更新到 DynamoDB 数据库中。通过对公共 AWS API 网关服务进行 HTTP POST 调用来激活 Lambda 函数。

Diagram of the visitor count widget sending data to the AWS back end services

我还添加了一个计数器的额外功能,该计数器显示网站的独立访客数量。常规访客计数器的一个缺陷是,它会在刷新页面时进行计数,而用户可以通过多次刷新页面来增加计数。我创建了另一个计数器,通过缓存每个访问者的 IP 地址并仅当用户的 IP 地址未包含在缓存中时才将其计为独立访客,从而跟踪独立访客的​​数量。我还通过将访问者的 IP 地址作为哈希存储在数据库中来保持每个访问者的匿名性。这种额外的互动性可以让网站准确地记住访问者与网站的互动,从而让访问者感到更受欢迎。

Step-by-step diagram of how the unique visitor count widget stores identify the unique IP of each user

第三部分:整合两端

虽然访客计数的后端基础设施在上一个区块中已经完成,但我仍然需要确保网站从后端检索数据。我在区块 3 中的工作主要围绕制作显示网站上正确访客数量的计数器以及为前端和后端编写冒烟测试。我使用 Javascript 代码向 API 网关端点发出 HTTP POST 请求,让网站向 API 网关查询访客计数数据。

然而,当我必须为网站编写代码测试时,新的挑战开始出现。在我过去的大学项目中,质量并不像提交项目那么重要。只要完成得足够多并按时提交,即使项目很可能无法正常运行,该项目也会被视为“完成”。由于我专注于完成项目而不是功能,因此我从未考虑过为我的项目编写测试。我总是必须手动测试功能,这导致我实现的功能不完整且有问题,需要在将来进行更多修补。在最坏的情况下,由于使用手动测试,修补程序还会在代码中引入更多问题,这些问题需要在将来进行更多修补。在参与过许多质量不重要的项目后,我认为测试是在浪费时间,而时间可以更好地用于解决问题。

当第 3 部分要求我为 API 网关编写测试时,我的思维方式开始改变。挑战要求在 Cypress 中实施“冒烟测试”,即衡量网站全部功能的端到端测试。我不得不考虑我的代码可能出现什么问题,例如考虑 HTTP 请求如何包含格式错误的标头,或者当 Lambda 代码在未初始化数据库的情况下增加访问者计数时会发生什么。

思考潜在问题并编写测试来检测这些问题让我意识到测试的好处。像 Cypress 这样的测试框架可确保每个测试一致且正确地运行,同时还提供了单击即可快速运行所有测试的功能。该框架减轻了繁重的工作并避免了手动测试的错误,让我有更多时间处理网站的功能。编写测试以确保网站正常运行变得与编写网站本身的代码一样重要。重点从仅仅“完成任务”转变为使用工具,使我能够创建高质量的工作,同时使工作变得容易。

A Cypress GUI showing a passing test run of the resume website

在此期间,我还完成了获得 AWS 认证的任务。最初的挑战要求我获得 AWS 认证云从业者证书,但我已经拥有该证书。为了进一步学习,我决定获得助理级 AWS 认证解决方案架构师证书。回想起来,获得此证书是一个不错的决定,因为我比从业者级证书更深入地了解了 AWS 服务的工作原理以及它们如何集成在一起。

AWS Certified Solutions Architect certificate addressed to Patima Poochai

第四部分:最后一段

在挑战的最后一段,我使用 Terraform 将剩余的后端基础设施迁移到 IaC。我还使用 GitHub Actions 创建了一个 CI/CD 管道来管理托管在 GitHub 存储库上的代码。当新代码提交到任一存储库时,GitHub Actions 会将代码部署到 AWS 并自动运行端到端测试。此工具还解决了我过去在项目中遇到的另一个常见问题,即每个项目总是有一个主要的痛点,当人们将损坏的代码提交到存储库时,需要很长时间才能解决问题。如果没有自动测试,就需要做大量工作来识别损坏的内容并追踪哪个提交导致了问题。甚至有时候,当我仍在排除初始问题时,人们会提交更多带有损坏代码的提交。如果我有这个 CI/CD 系统,可以自动检查每个提交的代码并识别当时带有损坏代码的提交,那么我就可以免于许多不眠之夜花在排除未知错误上。

A successful run of the Github Actions

我在这一块遇到的一个主要问题是排除 GitHub Actions 的 IAM 策略中的错误权限。GitHub Actions 管道需要一个具有访问必要服务的权限的 AWS 角色,以便使用 Terraform 部署基础设施,但不清楚 7 种不同的 AWS 服务需要哪些权限。起初,我想我可以尝试部署基础设施,阅读 Terraform 输出的错误,并手动将缺失的基础设施添加到 IAM 权限中。然而,这很耗时,因为每条错误消息只会显示一个缺失的权限,而缺失的权限可能有数百行。管道还需要大约 10 分钟才能尝试部署,然后显示部署期间发生的错误。我本可以像以前处理过去的项目一样继续部署基础设施并逐一添加权限,但考虑到这个项目对我的思维有多大的挑战,我想看看是否有更好的方法来解决这个问题。

An error message that describes the missing permissions needed to run Terraform deployment to AWS

起初,我尝试使用 AWS 内置的 API 调用日志记录工具捕获所需的权限。我尝试使用 Terraform 将网站部署到单独的测试帐户并记录所使用的权限。然后我可以使用 API 调用的名称来编写 IAM 权限策略。但是,这仍然不起作用,因为 API 调用的名称不是 IAM 策略中的有效权限名称,并且某些 IAM 权限完全缺失。挑战没有提供任何解决此问题的推荐方法,所以我不确定我是否能够找到解决这些问题的方法。

AWS Cloudtrail showing the logged API calls that was used by Terraform

但后来,我找到了一个名为“iamlive”的工具。它的工作原理是在本地计算机上创建一个 HTTP 代理,捕获 Terraform 通过代理进行的 API 调用,然后将它们转换为 IAM 策略格式的文本文件。起初,我不确定该工具是否能正常工作,因为我无法使用推荐的命令行参数设置代理。但是,通过花一些时间排除故障,确定我的设置需要哪些命令行参数,我能够让它捕获 IAM 权限。使用此工具,我能够通过使用捕获的权限编写 IAM 策略来完成此部分,这些策略允许 GitHub Actions 将 Terraform 基础设施部署到 AWS。

Live output of the permissions when running Terraform through iamlive's proxy

结论

通过接受这一挑战,我学到了很多有关云运营中使用的工具和现代 DevOps 原则的知识。我使用 Terraform 加快了基础设施部署过程,通过使用 Cypress 创建端到端测试消除了运行手动测试的辛苦,并使用 GitHub Actions 构建的 CI/CD 管道最大限度地减少了解决问题所花费的时间。我还了解到,只要愿意摆脱过去项目中养成的坏习惯,我就可以改善我的工作流程。

参见

点击此处查看简历网站

查看下面的项目代码:

  • 前端源代码
  • 后端源代码