使用 Amazon CloudFormation 构建 CI/CD 管道以改进 IaC

本教程介绍了如何使用 Amazon CodeCatalyst 从头开始创建 CI/CD 管道,以便使用 Amazon CloudFormation 部署基础设施即代码 (IaC)。
发布时间:2023 年 7 月 24 日
DevOps
基础设施即代码
CI/CD
CloudFormation
CodeCatalyst
教程
亚马逊云科技
Olawale Olaleye
亚马逊云科技使用经验
200 - 中级
完成所需时间
30 分钟
所需费用
前提条件
示例代码

本教程中使用的示例代码来自 GitHub

上次更新时间
2023 年 3 月 22 日

十余年以来,基础设施即代码 (IaC) 极大地改变了我们构建基础设施的方式。如今,我们可以在 YAML/JSON 模板文件中定义云基础设施,并使用 Amazon CloudFormation 等服务在基础设施上执行 CRUD(创建、读取、更新和删除)操作。我们不必进入亚马逊云科技管理控制台来设置所有内容,也不必创建脚本并使用 CLI 运行。简而言之,基础设施即代码使基础设施设置变得更省时、更不容易出错。

但我们能做的不止于此。仅仅编写 CloudFormation 模板、手动更新堆栈并不能充分利用 IaC 的强大能力。定义 IaC 的真正目的在于使基础设施也经过应用程序在开发阶段所用的一整套 CI/CD 管道。如此我们就可以将版本控制、跟踪更改以及执行代码审查、测试和回滚的最佳实践原封不动地应用于基础设施代码。这将使我们的基础设施更具可重复性、可靠性和一致性,提高部署速度、减少错误并消除配置漂移。

本教程将展示如何使用 Amazon CodeCatalyst 为通过 CloudFormation 编写的基础设施即代码设置 CI/CD 管道。管道将利用拉取请求来提交、测试和审查所请求的任何基础设施更改。

前提条件

亚马逊云科技账户

在开始之前,请确保您拥有亚马逊云科技账户。您可以在此处注册创建新账户。

CodeCatalyst 账户

按照文档中的步骤设置 CodeCatalyst

IAM 角色

我们需要在亚马逊云科技账户中创建 CloudCatalyst 服务角色。我们将通过这些角色为 CodeCatalyst 提供权限。该操作仅执行一次。

只需部署一个 CloudFormation 堆栈即可。您可以在此处找到有关如何使用亚马逊云科技控制台部署此堆栈的详细说明。

  • 堆栈名称 CodeCatalyst-IAM-roles
  • 区域:任意(首选 us-west-2)
  • 下载此处提供的模板,然后在 CloudFormation 控制台上选择 Create new stack(创建新堆栈)-> Template(模板)-> Upload a template(上传模板)上传此模板。

这将在您的亚马逊云科技账户中创建 2 个新的 Amazon Identity and Access Management (IAM) 角色,分别是 main_branch_IAM_role 和 pr_branch_IAM_role。

请注意,main_branch_IAM_role 提供对 EC2 和 CloudFormation 服务中的亚马逊云科技资源的完全访问权限,本博客中的示例 CloudFormation 模板将会使用这些资源。请谨慎使用此角色,并在不需要时将其删除。

入门

设置 CodeCatalyst 空间、项目、存储库和环境

在创建 CI/CD 管道和工作流之前,先设置 CodeCatalyst。

空间

我们从设置 CodeCatalyst 空间开始。一个空间可代表您自己、您的公司、部门或小组。您的开发团队可以管理其中的项目。

点击 CodeCatalyst 仪表板上的 Create Space(创建空间),创建一个新空间,为其命名(这里使用 CloudFormation CodeCatalyst),再添加亚马逊云科技账户 ID 来关联计费信息。按照提示将您的亚马逊云科技账户与 CodeCatalyst 相关联。

请注意,012345678901 只是一个占位符,请将其替换为您的账户 ID。您可以在亚马逊云科技控制台的右上角查看账户 ID。在创建空间之前,请点击 Verify in the AWS console(在亚马逊云科技控制台中验证)链接并完成验证。界面显示绿色对勾后即可继续。

(在撰写本文时,CodeCatalyst 仍处于公测阶段,仅支持一个区域。)

空间创建完成后,前往 AWS Accounts(亚马逊云科技账户)选项卡,点击您的账户 ID,然后点击 Manage roles from the AWS Management Console(亚马逊云科技管理控制台中的管理角色)。

系统将打开新的浏览器标签页,其标题是 Add IAM role to Amazon CodeCatalyst space(将 IAM 角色添加到 Amazon CodeCatalyst 空间)。在对话框中,选择 Add an existing role you have created in IAM(添加已在 IAM 中创建的角色),然后从下拉菜单中选择 main_branch_IAM_role。点击 Add role。请按照相同的步骤添加 pr_branch_IAM_role。

项目

接下来,我们在空间内创建一个新项目。一个空间可包含多个项目。

若要创建项目,请点击 Create Project(创建项目)按钮,选择 Start from scratch(从头开始),再为项目命名。这里使用的名称是 ThreeTierApp。

存储库

接下来,我们将创建一个新的代码库。在本例中,代码即 CloudFormation 模板和其他资源。点击左侧导航菜单中的 Code(代码),然后依次选择 Source repositories(源存储库)、Add repository(添加存储库)和 Create repository(创建存储库)。设置存储库的名称(本教程采用 3-tier-app),添加描述,并将 .gitignore 文件设为 none(无):

环境

最后,我们需要设置亚马逊云科技环境。CloudFormation 堆栈将在该环境中通过自动化工作流进行部署。该环境是一个非生产环境,示例 CloudFormation 模板将在其中进行部署。

在左侧导航面板中,选择 CI/CD 和 Environments(环境),然后点击 Create Environment(创建环境)。在 Environment details(环境详细信息)部分,输入以下内容:

  • Environment name(环境名称): PreProdEnv
  • Environment type(环境类型): Non-production
  • Description(说明): Pre-production environment to learn, test and experiment with CloudFormation
  • AWS account connection(亚马逊云科技账户连接)
    • Connection:选择将用于在工作流中部署此环境的亚马逊云科技账户 ID

搭建开发环境

为了使用 CloudFormation 实施基础设施即代码,我们需要一个开发环境。您可以选择使用下列 IDE(集成开发环境):

  • Amazon Cloud9
  • Visual Studio Code
  • JetBrains IDE
    • IntelliJ IDEA 旗舰版
    • GoLand
    • PyCharm 专业版

在本博客中,我们使用 AWS Cloud9 这一开发环境。

在左侧导航面板中,选择 Code(代码)和 Dev Environments(开发环境),然后点击 Create Dev Environment(创建开发环境)。在 Create dev environment and open with AWS Cloud9(创建开发环境并使用 Amazon Cloud9 打开)对话框中,选择以下选项:

  • Repository(存储库): Clone a repository
  • Repository(存储库):选择要克隆的存储库。选择我们之前创建好的存储库 3-tier-app1。
  • Branch(分支): Work in existing branch
  • Alias(别名): bootstrap

默认情况下,它将启动一台配置为 Small(2vCPU,4 GB RAM)的机器,这台机器有 16 GiB 存储空间,超时时间为 15 分钟。

点击 Create(创建)即可打开一个新的 Cloud9 开发环境。该过程需要一两分钟,所以在我们学习 CloudFormation 的强大功能之前先喝杯咖啡。

在欢迎界面上,您可以按需修改开发环境设置。

您将找到一个空的存储库 3-tier-app,它包含一个 readme.md、一个 devfile.yaml,以及一些隐藏文件夹。devfile.yaml 包含用于构建应用程序库和工具链的定义。在本教程中,您可以忽略它。

示例 CloudFormation 模板

您可以使用自己的 CloudFormation 模板,也可以直接使用一个示例模板。

在本博客中,我使用的是示例模板,其中部署了一个 VPC,具有 2 个子网和可公开访问的 Amazon EC2 实例,这些实例都位于 Auto Scaling 组中,受负载均衡器保护。您完全可以用和我一样的模板,我将对此模板进行更改并运行拉取请求工作流。

在实际生产中,您需要在单独的 CloudFormation 嵌套堆栈中完成网络基础设施部署和应用程序部署。利用嵌套堆栈,您无需每次都运行网络堆栈就能对应用程序堆栈进行常见更改,从而节省时间。同样,网络团队可以独立完成更改,而无需运行应用程序堆栈。此方法还将模板正文大小保持在 CloudFormation 配额范围内。由于使用 CodeCatalyst 部署的开销更小、操作更简单,并且我们不必担心长期操作,所以我们将在单个模板中部署所有内容。

使用以下命令将更改提交到 Git 存储库:

# go to the root folder of the repo and run following

$ cd 3-tier-app/
$ wget https://raw.githubusercontent.com/build-on-aws/ci-cd-iac-aws-cloudformation/main/cloudformation-templates/VPC_AutoScaling_With_Public_IPs.json

# check git status
$ git status

# add changed files, commit and push to the git repo
$ git add . -A
$ git commit -m "Uploading first CloudFormation template"
$ git push

输出:

$ git status
On branch main
Your branch is up to date with 'origin/main'.

Untracked files:
 (use "git add <file>..." to include in what will be committed)
 VPC_AutoScaling_With_Public_IPs.json

nothing added to commit but untracked files present (use "git add" to track)

$ git add .
$ git commit -m "Uploading first CloudFormation template"
[main eca3764] Uploading first CloudFormation template
 1 file changed, 560 insertions(+)
 create mode 100644 VPC_AutoScaling_With_Public_IPs.json

$ git push
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 2 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 4.59 KiB | 4.59 MiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
remote: Validating objects: 100%
To https://git.us-west-2.codecatalyst.aws/v1/CloudFormation-CodeCatalyst/ThreeTierApp/3-tier-app
 cbbfab7..eca3764 main -> main

您可以验证 CloudFormation 模板是否已在存储库中成功更新,方法是在 CodeCatalyst 控制台中点击左侧导航菜单中的 Code(代码),然后点击 Source repositories(源存储库)。

名为 VPC_AutoScaling_With_Public_IPs.json 的新文件此时应该已经添加到存储库中。

设置工作流以部署非生产环境

下一步是创建自动化工作流。我们的目的是当提交推送到主分支时触发自动操作。在本例中,我们只定义一个操作:部署更新后的 CloudFormation 模板和/或更新堆栈。

您可以选择以下 2 种方案来创建工作流:

  1. 利用可视化拖放方法,使用 CodeCatalyst 控制台创建工作流。为此,请前往 CI/CD -> Workflows(工作流)。
  2. 利用 YAML 文件,使用开发环境创建工作流。在本博客中,我们将使用此方法。

为了创建工作流,请在存储库中创建一个隐藏文件夹,向其中添加 main_branch.yaml 文件:

# go to the root folder of the repo and run following

mkdir -p .codecatalyst/workflows
touch .codecatalyst/workflows/main_branch.yaml

在 IDE 中打开 .codecatalyst/workflows/main_branch.yaml,并添加如下内容。请记住:

  • 将亚马逊云科技账户 ID 的占位符 123456789012 替换为您账户的值;如果您更改了 IAM 角色名称,还需要替换 main_branch_IAM_role
  • 如果您使用的是自己的 CloudFormation 模板,请替换 CloudFormation 文件名,它位于 template
  • 文件名是 main_branch.yaml
Name: Main_Branch_Workflow
SchemaVersion: "1.0"

# Optional - Set automatic triggers.
Triggers:
 - Type: Push
 Branches:
 - main

# Required - Define action configurations.
Actions:
 DeployAWSCloudFormationstack_7c:
 Identifier: aws/cfn-deploy@v1
 Configuration:
 parameter-overrides: SSHLocation=54.10.10.2/32,WebServerInstanceType=t2.micro
 capabilities: CAPABILITY_IAM,CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND
 template: VPC_AutoScaling_With_Public_IPs.json
 region: us-west-2
 name: PreProdEnvStack
 Timeout: 10
 Environment:
 Connections:
 - Role: main_branch_IAM_role
 Name: "123456789012"
 Name: PreProdEnv
 Inputs:
 Sources:
 - WorkflowSource

在工作流中,我们提供了用于创建 CloudFormation 堆栈的参数值。如果您使用的是自己的模板,请确保修改 parameter-overrides 部分的相关内容和模板名称。

现在测试新工作流。

首先,我们需要暂存、提交更改并将其直接推送到主分支。这是必要操作,因为只有提交到存储库的工作流,CodeCatalyst 才会运行。

运行以下命令:

$ git add . -A
$ git commit -m "Adding main branch workflow"
$ git push

输出:

$ git add . -A
$ git commit -m "Adding main branch workflow"
[main 5677f67] Adding main branch workflow
 1 file changed, 28 insertions(+)
 create mode 100644 .codecatalyst/workflows/main_branch.yaml
$ git push
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to 2 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (5/5), 911 bytes | 455.00 KiB/s, done.
Total 5 (delta 0), reused 0 (delta 0), pack-reused 0
remote: Validating objects: 100%
To https://git.us-west-2.codecatalyst.aws/v1/CloudFormation-CodeCatalyst/ThreeTierApp/3-tier-app
 eca3764..5677f67 main -> main

在浏览器中,前往 CI/CD -> Workflows(工作流)页面。您应当会看到运行中的工作流:

点击 Recent runs(最近运行)将其展开,即可看到当前正在运行的作业的详细信息。点击作业 ID (Run-XXXXX) 可以查看构建的不同阶段:

CodeCatalyst 完成各阶段并部署 CloudFormation 堆栈需要一定的时间。堆栈部署时间取决于模板中定义的资源。这次部署是在 3 分 48 秒内完成的。

我们的 CloudFormation 堆栈已通过工作流部署完毕。可以在 Variables(变量)选项卡中查看 CloudFormation 的输出。

打开 WebSite(网站)链接,可以访问此模板部署的示例应用程序。

运行可能会因错误而失败。此时请您通读日志、了解问题并进行修正。如果您遇到内部错误,最好在亚马逊云科技管理控制台的 CloudFormation 仪表板中检查堆栈部署。如果 CloudFormation 堆栈已回滚,请手动删除堆栈,修复问题,然后再次运行工作流。您可以寻求故障排除文档、高级支持中心或 Amazon re:Post 的帮助。

使用拉取请求工作流更改代码

现在更改基础设施。我们要向 VPC 添加第三个子网,更新 LoadBalancer 和 AutoScaling 组,以使用这个新子网。

根据最佳实践,请不要直接更改主分支。我们应该始终创建一个单独的分支来进行更改,待审查人员批准后,这些更改会合并到主分支中。为满足特定组织或团队需求,您可以学习使用许多 Git 分支策略。对于 CodeCatalyst,您可以使用相同的策略。

在本博客中,我先做简单示范。每当需要进行更改时,我都会创建一个新分支(第 2 步),然后在新分支中更改基础设施(第 3 步)。然后,我会创建一个拉取请求 (PR),合并新分支与主分支。如图所示,每当打开 PR 时(第 4 步),CodeCatalyst 都会自动运行 PR 工作流来创建更改集(第 5 步)。您可以通过更改集来预览:将进行的堆栈更改对于当前正在运行的资源可能会造成什么样的影响。然后,您可以决定是否要执行更改。

审查人员批准更改并继续合并拉取请求(第 6 步)后,上述步骤中创建的 main_workflow 会自动合并代码,并将更改部署到我的非生产环境 PreProdEnv 中(第 7 步)。您可以采取与我不同的分支策略,也可以对生产环境部署进行更多测试。

首先,我们要编写一个 PR 工作流,让 CodeCatalyst 在新的拉取请求创建时先运行此工作流。在此 PR 工作流中,我们不会部署任何更改到 PreProdEnv。当 PR 被打开或修改时,我们将使用 super-linter 对其进行验证,然后创建一个 CloudFormation 更改集。

在隐藏目录 .codecatalyst/workflows/ 下创建一个新文件 pr_branch.yaml,并粘贴以下内容。

请记住:

  • 将亚马逊云科技账户 ID 的占位符 123456789012 替换为您账户的值;如果您更改了 IAM 角色名称,还需要替换 main_branch_IAM_role
  • 如果您使用的是自己的 CloudFormation 模板,请替换 CloudFormation 文件名,它位于 template
  • 文件名是 pr_branch.yaml
Name: PR_Branch_Workflow
SchemaVersion: "1.0"

# Optional - Set automatic triggers.
Triggers:
 - Type: PULLREQUEST
 Branches:
 - main
 Events:
 - OPEN
 - REVISION

# Required - Define action configurations.
Actions:
 Super-Linter_0d:
 # Identifies the action. Do not modify this value.
 Identifier: aws/github-actions-runner@v1

 # Specifies the source and/or artifacts to pass to the action as input.
 Inputs:
 # Optional
 Sources:
 - WorkflowSource # This specifies that the action requires this Workflow as a source

 # Defines the action's properties.
 Configuration:
 # Required - Steps are sequential instructions that run shell commands
 # Action URL: https://github.com/marketplace/actions/super-linter
 # Please visit the action URL to look for examples on the action usage.
 # Be aware that a new version of the action could be available on GitHub.
 Steps:
 - name: Lint Code Base
 uses: github/super-linter@v4
 env:
 VALIDATE_CLOUDFORMATION: "true"
 CreateChangeSet:
 Identifier: aws/cfn-deploy@v1
 DependsOn: 
 - Super-Linter_0d 
 Configuration:
 parameter-overrides: SSHLocation=54.10.10.2/32,WebServerInstanceType=t2.micro
 capabilities: CAPABILITY_IAM,CAPABILITY_NAMED_IAM,CAPABILITY_AUTO_EXPAND
 no-execute-changeset: "1"
 template: VPC_AutoScaling_With_Public_IPs.json
 region: us-west-2
 name: PreProdEnvStack
 Timeout: 10
 Environment:
 Connections:
 - Role: pr_branch_IAM_role
 Name: "123456789012"
 Name: PreProdEnv
 Inputs:
 Sources:
 - WorkflowSource

在上面的拉取请求工作流中,请注意以下定义:

  1. Super-Linter_0d 操作中定义了 VALIDATE_CLOUDFORMATION: "true" 环境变量。这样,我们就可以确保使用 cfn-lint github 操作来验证 CloudFormation 模板。cfn-lint 是一种开源工具,可以根据 Amazon CloudFormation 资源规范和其他检查步骤帮您验证 Amazon CloudFormation YAML/JSON 模板。这包括检查资源属性和最佳实践的有效值。

  2. 图示工作流的 CreateChangeSet 操作中有 no-execute-changeset: "1" 选项,用于指示要运行更改集还是审查更改集。默认值是 '0',表示运行更改集。我们不想让它执行更改,只想看看合并 PR 时会发生的变化,因此我们将其设置为 '1',表示不执行更改集。

  3. 在 CreateChangeSet 操作中,我们添加了一个新属性 DependsOn: - Super-Linter_0d。这会告知工作流首先运行 Super-Linter_0d 操作,如果成功则运行 CreateChangeSet 操作。

现在,使用以下命令暂存、提交更改并将其直接推送到主分支:

$ git add . -A
$ git commit -m "Adding PR branch workflow"
$ git push

输出:

$ git add . -A
$ git commit -m "Adding PR branch workflow"
[main e844b70] Adding PR branch workflow
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git push
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 2 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 451 bytes | 225.00 KiB/s, done.
Total 5 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Validating objects: 100%
To https://git.us-west-2.codecatalyst.aws/v1/CloudFormation-CodeCatalyst/ThreeTierApp/3-tier-app
 d410f15..e844b70 main -> main

然后,CodeCatalyst 将再创建一个工作流。点击 CodeCatalyst 控制台 的 CI/CD -> Workflow(工作流)即可确认这一点。可以看到 PR_Branch_Workflow 已创建,但尚未运行。

点击 PR_Branch_Workflow 可以看到工作流。正如上面的工作流 YAML 文件中所定义的那样,工作流将首先运行 Super-Linter_0d 操作,如果成功则运行下一个操作 CreateChangeSet。

现在回到开发环境,首先确保新的 test-pr-workflow 分支已创建,然后再更改 CloudFormation 模板。

输出:

$ git checkout -b test-pr-workflow
Switched to a new branch 'test-pr-workflow'

更改 CloudFormation 模板

  • 如果您使用的是自己的 CloudFormation 模板,请更改模板以创建更改集。

  • 对于本博客中使用的示例 CloudFormation 模板,您有 2 种操作方式可以选择:

    • 直接将其内容替换为这个已修改的模板。确保模板文件名和工作流中提到的文件名一致(VPC_AutoScaling_With_Public_IPs.json)。

      或者

    • 手动进行以下更改,将第三个子网及其资源添加到模板中:

      将以下 JSON 代码添加到 Resources(资源)部分下的示例 CloudFormation 模板中。

"PublicSubnet3" : {
 "Type" : "AWS::EC2::Subnet",
 "Properties" : {
 "VpcId" : { "Ref" : "VPC" },
 "CidrBlock" : { "Fn::FindInMap" : [ "SubnetConfig", "Public3", "CIDR" ]},
 "AvailabilityZone" : {"Fn::Select": [2, {"Fn::GetAZs": ""}]},
 "Tags" : [
 { "Key" : "Application", "Value" : { "Ref" : "AWS::StackId" } },
 { "Key" : "Network", "Value" : "Public" }
 ]
 }
 },
 "PublicSubnetRouteTableAssociation3" : {
 "Type" : "AWS::EC2::SubnetRouteTableAssociation",
 "Properties" : {
 "SubnetId" : { "Ref" : "PublicSubnet3" },
 "RouteTableId" : { "Ref" : "PublicRouteTable" }
 }
 },
 "PublicSubnetNetworkAclAssociation3" : {
 "Type" : "AWS::EC2::SubnetNetworkAclAssociation",
 "Properties" : {
 "SubnetId" : { "Ref" : "PublicSubnet3" },
 "NetworkAclId" : { "Ref" : "PublicNetworkAcl" }
 }
 },

在 Mappings、LoadBalancer 和 AutoScaling 资源中,添加 PublicSubnet3,如下所示:

"Mappings" : {
 "SubnetConfig" : {
 "VPC" : { "CIDR" : "10.0.0.0/16" },
 "Public1" : { "CIDR" : "10.0.0.0/24" },
 "Public2" : { "CIDR" : "10.0.1.0/24" },
 "Public3" : { "CIDR" : "10.0.2.0/24" } 
 },

"WebServerFleet" : {
 "Type" : "AWS::AutoScaling::AutoScalingGroup",
 "DependsOn" : "PublicRoute",
 "Properties" : {
 "VPCZoneIdentifier" : [{ "Ref" : "PublicSubnet1" }, { "Ref" : "PublicSubnet2" }, { "Ref" : "PublicSubnet3" }],

"PublicApplicationLoadBalancer" : {
 "Type" : "AWS::ElasticLoadBalancingV2::LoadBalancer",
 "Properties" : {
 "Subnets" : [ { "Ref" : "PublicSubnet1"}, { "Ref" : "PublicSubnet2" }, { "Ref" : "PublicSubnet3" } ],
 "SecurityGroups" : [ { "Ref" : "PublicLoadBalancerSecurityGroup" } ]
 }
 },

现在,使用以下命令保存修改后的文件并将其推送到 test-pr-workflow 分支:

$ git add .
$ git commit -m "Added third public subnet to VPC, RouteTable, NACL, LoadBalancer and ASG"
$ git push --set-upstream origin test-pr-workflow

输出:

$ git status
On branch test-pr-workflow
Changes not staged for commit:
 (use "git add <file>..." to update what will be committed)
 (use "git restore <file>..." to discard changes in working directory)
 modified: VPC_AutoScaling_With_Public_IPs.json

no changes added to commit (use "git add" and/or "git commit -a")

$ git add .
$ git commit -m "Added third public subnet to VPC, RouteTable, NACL, LoadBalancer and ASG"
[test-pr-workflow e1a1d0e] Added third public subnet to VPC, RouteTable, NACL, LoadBalancer and ASG
 1 file changed, 33 insertions(+), 4 deletions(-)

$ git push --set-upstream origin test-pr-workflow
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 2 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 467 bytes | 467.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Validating objects: 100%
To https://git.us-west-2.codecatalyst.aws/v1/CloudFormation-CodeCatalyst/ThreeTierApp/3-tier-app
 * [new branch] test-pr-workflow -> test-pr-workflow
branch 'test-pr-workflow' set up to track 'origin/test-pr-workflow'.

在 CodeCatalyst 控制台上,前往 Code(代码)-> Repository(存储库)。您可以看到 2 个分支:main 和 test-pr-workflow。

创建拉取请求并合并代码

现在,所有更改都在 test-pr-workflow 分支里了,您可以创建拉取请求,让其他人审查更改。

执行以下步骤创建拉取请求,以将测试分支中的更改与主分支进行比较:在 CodeCatalyst 控制台上,前往 Code(代码)-> Pull requests(拉取请求)。点击 Create pull request(创建拉取请求),输入以下详细信息:

  • Source repository(源存储库): 3-tier-app
  • Source branch(源分支): test-pr-workflow
  • Destination branch(目标分支): main
  • Pull request title(拉取请求标题): Merge new third subnet
  • Pull request description(拉取请求说明): New third subnet created and added to VPC, RouteTable, NACL, LoadBalancer, ASG

您可以添加审查人员,审查人员有权批准或拒绝合并。

请注意,我们的源分支是 test-pr-workflow,合并目标是 main 分支。创建此 PR 后,它将触发用于创建 CloudFormation 更改集的 PR_Branch_Workflow,并且不会进行部署。

若要查看 PR_Branch_Workflow 的当前运行,请登录 CodeCatalyst 控制台,前往 CI/CD -> Workflows(工作流)页面,然后选择 test-pr-workflow 分支。默认情况下,Workflows(工作流)页面始终显示 main 分支。必须切换分支才能查看其他分支中的当前工作流。

现在,您可能注意到了 PR_Branch_Workflow 的本次运行状态为 failed(失败)。

展开 Lint Code Base(Lint 代码库),您会发现以下内容:

[INFO] --------------------------------------------
[INFO] Gathering user validation information...
[INFO] - Validating ALL files in code base...
[INFO] ----------------------------------------------
[INFO] Linting [CLOUDFORMATION] files...
[INFO] ----------------------------------------------
[INFO] File:[/github/workspace/VPC_AutoScaling_With_Public_IPs.json]
[ERROR] Found errors in [cfn-lint] linter!
[ERROR] Error code: 4. Command output:
------
W7001 Mapping 'AWSInstanceType2NATArch' is defined but not used
/github/workspace/VPC_AutoScaling_With_Public_IPs.json:56:5
------
[INFO] ----------------------------------------------
[INFO] The script has completed
[INFO] ----------------------------------------------
[ERROR] ERRORS FOUND in CLOUDFORMATION:[1]
[FATAL] Exiting with errors found!

CloudFormation 模板确实通过 cfn-lint 进行了解析,并发现了一个错误。模板中有一个已定义但从未使用过的映射资源。我们应该在模板文件中删除它,并将更改推送到 test-pr-workflow。

因此,请返回 Amazon Cloud9 上的开发环境,在 CloudFormation 模板中删除以下数据块:

"AWSInstanceType2NATArch" : {
 "t1.micro" : { "Arch" : "NATHVM64" },
 "t2.nano" : { "Arch" : "NATHVM64" },
 "t2.micro" : { "Arch" : "NATHVM64" },
 "t2.small" : { "Arch" : "NATHVM64" },
 "t2.medium" : { "Arch" : "NATHVM64" },
 "t2.large" : { "Arch" : "NATHVM64" },
 "m4.large" : { "Arch" : "NATHVM64" },
 "m4.xlarge" : { "Arch" : "NATHVM64" },
 "c1.medium" : { "Arch" : "NATHVM64" }
 },

保存文件,暂存、提交更改,并将更改推送到 test-pr-workflow 分支。由于这是对分支的修订,因此它应该会自动触发工作流再次运行。

$ git add .
$ git commit -m "Removed unused AWSInstanceType2NATArch mapping"
$ git push --set-upstream origin test-pr-workflow

输出:

$ git add .
$ git commit -m "Removed unused AWSInstanceType2NATArch mapping"
[test-pr-workflow 64a27b5] Removed unused AWSInstanceType2NATArch mapping
 1 file changed, 1 insertion(+), 11 deletions(-)
$ git push --set-upstream origin test-pr-workflow
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 2 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 319 bytes | 159.00 KiB/s, done.
Total 3 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Validating objects: 100%
To https://git.us-west-2.codecatalyst.aws/v1/CloudFormation-CodeCatalyst/ThreeTierApp/3-tier-app
 1f8e97d..64a27b5 test-pr-workflow -> test-pr-workflow
branch 'test-pr-workflow' set up to track 'origin/test-pr-workflow'.

在浏览器中,前往 CI/CD -> Workflows(工作流)页面。请确保您选择的是 test-pr-workflow 分支。新运行现在应处于活动状态。

您可以确认新工作流已成功运行。

展开 Lint Code Base(Lint 代码库),可以看到以下文本,里面没有错误:

[INFO] --------------------------------------------
[INFO] Gathering user validation information...
[INFO] - Validating ALL files in code base...
[INFO] ----------------------------------------------
[INFO] Linting [CLOUDFORMATION] files...
[INFO] ----------------------------------------------
[INFO] File:[/github/workspace/VPC_AutoScaling_With_Public_IPs.json]
[INFO] - File:[VPC_AutoScaling_With_Public_IPs.json] was linted
[INFO] ----------------------------------------------
[INFO] The script has completed
[INFO] ----------------------------------------------
[NOTICE] All file(s) linted successfully with no errors detected

现在,工作流将继续执行下一个操作:CreateChangeSet。

操作成功后,您可以前往 CloudFormation 控制台的 Changeset(更改集)选项卡,并验证新拉取请求建议的更改。

审查人员将确认所有操作都已成功运行,更改集没有问题。在本例中,我自己就是审查人员,所以我将在浏览器中前往 Code(代码)-> Pull Requests(拉取请求),点击 Merge(合并)。

如果存在冲突,或者无法完成合并,则合并按钮将处于不可点击状态,并显示 Not mergeable(不可合并)标签。此时必须获得相关审批人员的批准,如有必要还需在本地解决冲突,然后再将这些更改推送到 test-pr-workflow,完成后才能合并。

此时,您可以采取 2 种合并策略:

  1. Fast forward merge(快进式合并):合并分支并将目标分支指针移动到源分支的顶端。这是 Git 中的默认合并策略。本博客采用这一选项。

  2. Squash and merge(压缩合并):将源分支中的所有提交合并到目标分支中的单个合并提交中。

合并此拉取请求后,您可以删除源分支。在本例中,源分支是 test-pr-workflow,我将删除这个分支,让我的分支结构简洁明了。

点击 Merge(合并)后,CodeCatalyst 会将 test-pr-workflow 的代码更改合并到 main 分支。这将触发 Main_Branch_Workflow 并将更新后的 CloudFormation 代码部署到 PreProdEnv。

您可以在 VPC 控制台上确认新创建的子网。

清理资源

我们已经完成了本教程:学习了如何创建工作流、如何拉取请求、如何使用操作——创建 ChangeSet、部署 CloudFormation 堆栈,以及先在模板上运行 cfn-lint 再更改基础设施。您可以邀请团队成员或创建问题,进一步探索 CodeCatalyst 的功能。如果您不想继续探索,请删除我们在本教程中创建的所有资源。清理亚马逊云科技账户中的 CloudFormation 堆栈。打开 Amazon CloudFormation 控制台,删除 PreProdEnvStack 和 CodeCatalyst-IAM-roles。

接下来删除我们在 CodeCatalyst 中创建的项目。在左侧导航栏中,前往 Project settings(项目设置),点击 Delete project(删除项目),然后按照说明删除项目。

最后删除 CodeCatalyst 空间。前往 CodeCatalyst 仪表板,点击 Space settings(空间设置)选项卡,然后点击 Delete space(删除空间)。

总结

恭喜您!您现在已经学会了如何使用 CloudFormation 和 CodeCatalyst 部署基础设施即代码,并且可以使用拉取请求工作流部署任何基础设施更改。