读书笔记《building-distributed-applications-in-gin》CD管道
Chapter 9: Implementing a CI/CD Pipeline
Technical requirements
要遵循本章中的内容,您将需要以下内容:
- A complete understanding of the previous chapter. This chapter is a follow-up of the previous one as it will be using the same source code. Hence, some snippets won't be explained to avoid repetition.
- Previous experience with CI/CD practices is highly recommended so that you can follow this chapter with ease.
本章的代码包托管在 GitHub 上,地址为 https: //github.com/PacktPublishing/Building-Distributed-Applications-in-Gin/tree/main/chapter09。
Exploring CI/CD practices
在前面的章节中,您学习了如何在 AWS 上设计、构建和部署 Gin Web 应用程序。目前,部署新更改可能是一个耗时的过程。在部署到 EC2 实例、Kubernetes 或 Platform as a Service (PaaS) 时,有 帮助推出新更改的手动步骤。
幸运的是,这些部署步骤中的许多都可以实现自动化,从而节省了开发时间,消除了人为错误的可能性,并缩短了发布周期。这就是为什么在本节中,您将学习如何接受 持续集成 (CI)、持续部署(CD)和持续交付以加快上市时间您的应用程序的 (TTM),以及确保通过每次迭代交付高质量的功能。但首先,这些做法是什么意思?
Continuous integration
持续集成(CI)是拥有集中代码存储库的过程(例如 GitHub、Bitbucket、GitLab 等)并在将所有更改和功能集成到远程存储库之前通过管道进行。经典管道在代码提交(或推送事件)发生时触发构建,运行预集成测试,构建工件(例如,Docker 映像、JAR、npm 包等),并将结果推送到用于版本控制的私有注册表:
如上图所示,CI 工作流程由以下阶段组成:Checkout、Test、构建和推送。
Continuous deployment
另一方面,持续部署(CD)是一个扩展CI 工作流程。通过 CI 管道所有阶段的每个更改都会自动发布到暂存或预生产环境中,QA 团队可以在其中运行验证和验收测试。
Continuous delivery
持续交付类似于 CD,但需要人工干预或业务验证,然后才能将新版本部署到生产环境。这种人工参与可能包括手动部署,这通常由 QA 工程师执行,或者像单击按钮一样简单。这与 CD 不同,在 CD 中,每个成功的构建都会发布到登台环境。
采用这三种做法有助于提高代码的质量和可测试性,还有助于降低将损坏的版本发布到生产环境的风险。
现在您了解了这三个组件是什么,在本章结束时,您将能够为我们的 Gin Web 应用程序构建一个端到端的部署流程,类似于下图所示的流程:
- Checkout: Pulls the latest changes from the project's GitHub repository.
- Test: Runs unit and quality tests within a Docker container.
- Build: Compiles and builds a Docker image from a Dockerfile.
- Push: Tags the image and stores it in a private registry.
- Deploy: Deploys and promotes the changes to an AWS environment (EC2, EKS, or ECS).
笔记
我们使用 CircleCI 作为 CI 服务器,但相同的工作流程可以通过其他 CI 解决方案实现,例如 Jenkins、Travis CI、GitHub Actions 等。
Building a CI workflow
我们为本书构建的应用程序在 GitHub 存储库中进行了版本控制。该存储库使用 GitFlow 模型作为分支策略,其中使用了三个主要分支。每个分支代表应用程序的运行时环境:
- Master branch: This branch corresponds to the code running in the production environment.
- Preprod branch: The staging environment – a mirror of the production environment.
- Develop branch: The sandbox or development environment.
要将应用程序从一种环境推广到另一种环境,您可以创建功能分支。您还可以为主要错误或问题创建修补程序分支。
笔记
要了解有关 GitFlow 工作流程和最佳实践的更多信息,请查看官方文档:https ://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow。
下图显示了您项目的 GitHub 存储库的样子:
您将 使用 CircleCI 来自动化 CI/CD 工作流程。如果您还没有 CircleCI 帐户,请在 https://circleci.com 上使用您的 GitHub 帐户免费注册 。无论 CI 服务器如何,CI/CD 的原理都是一样的:
注册后,需要配置 CircleCI 以运行应用程序测试并构建 Docker 映像。为此,您需要在模板文件中描述所有步骤并将其保存在代码的 GitHub 存储库中。这种方法称为管道即代码。
Pipeline as Code
当触发 CircleCI 构建时,它会在 中查找 .circleci/config.yml
文件。此文件包含要在 CI 服务器上执行的指令。
首先创建一个 .circleci
文件夹和一个 .config.yml
文件,其内容如下:
前面的 代码片段将在由 Golang v1.15.6 Docker 映像提供支持的环境中运行 工作流。大多数 CI/CD 步骤将使用 Docker 执行,这使得在本地运行构建变得轻而易举,并且如果我们将来想要迁移到不同的 CI 服务器(相对于供应商锁定),我们的选择仍然是开放的。要运行的第一个作业是测试阶段,它包括以下步骤:
test
作业将从此更改"_idIndexMarker770">项目的 GitHub 存储库使用 checkout
指令。然后,它将下载项目依赖项并缓存它们以供将来使用(以减少工作流持续时间),之后,它将运行一系列测试:
- Code linting: This checks if the code respects standard coding conventions.
- Unit tests: This executes the unit tests we wrote in previous chapters.
准备好 CircleCI 配置后,让我们在 CircleCI 上为 Gin 应用程序创建一个 项目。为此,请按照下列步骤操作:
- Jump to the CircleCI console and click on Set up Project, next to the project's repository:
- Click on the Use Existing Config button, since we already have a CircleCI configuration, and click on Start Building:
- A new pipeline will start; however, it will fail due to no
config.yml
file existing in the code repository. This error is shown in the following screenshot: - Push the CircleCI configuration to the GitHub repository on the develop branch by running the following commands:
将自动触发一个新的管道。输出将类似于以下内容:
- Click on the test job.
您应该看到
config.yml
文件中描述的步骤。所有测试都将通过,您将能够构建您的 Docker 映像:值得提到管道是自动触发的,因为在设置 CircleCI 项目时,会在项目的 GitHub 存储库中自动创建一个 webhook。这样,对于每个推送事件,都会向 CircleCI 服务器发送通知以触发相应的 CircleCI 管道:
- Add a
build
job to the CI/CD workflow: - The
build
job is responsible for building a Docker image based on ourDockerfile
, which is stored within the code repository. Then, it tags the built image and stores it in a remote Docker registry for versioning:笔记
如果您对 Dockerfile 感兴趣,可以在本书的 GitHub 存储库中找到它,地址为 https://github.com/PacktPublishing/Building-Distributed-Applications-in-Gin/blob/main/chapter10/Dockerfile。
为了标记图像,我们将使用语义版本控制 (https://semver.org )。版本的格式是三位数字,用点分隔:
当新的更改破坏 API(向后不兼容的更改)时,主版本会增加。发布新功能时,次要版本会增加,而补丁版本会随着错误修复而增加。
在 CircleCI 配置中,您使用
$CIRCLE_BUILD_NUM
环境 变量为通过以下方式构建的每个 Docker 映像创建唯一版本我们的 Gin 应用程序的开发周期。另一种选择是使用CIRCLE_SHA1
变量,它是触发 CI 构建的 Git 提交的 SHA1 哈希。 - Once the image has been tagged, store it in a private registry. In the previous example, you were using an Elastic Container Registry (ECR) as a private repository, but another solution such as DockerHub can be used as well.
- Push the changes to the develop branch with the following command:
将触发一个新的管道。 test
作业完成后,将执行 build
作业,如下图所示:
以下是 build
作业的步骤。测试应该在 Push image 步骤失败,因为由于缺少 AWS 权限,CircleCI 无法将图像推送到 ECR:
现在让我们看看如何配置 CI 和 CD 工作流程:
- To allow CircleCI to interact with your ECR repository, create a dedicated IAM user with proper IAM policies.
- Jump to the AWS Management Console (https://console.aws.amazon.com/) and navigate to the Identity and Access Management (IAM) console. Then, create a new IAM user for CircleCI. Check the Programmatic access box, as shown in the following screenshot:
- Attach the following IAM policy to the IAM user. This statement allows CircleCI to push a Docker image to the ECR repository. Make sure that you substitute
ID
as needed: - Once the IAM user has been created, create an access key from the Security credentials tab. Then, head back to the CircleCI dashboard and jump to Project Settings:
- Under the Environment Variables section, click on the Add Environment Variable button and add the following variables:
AWS_ACCESS_KEY_ID:指定与 CircleCI IAM 用户关联的 AWS 访问密钥。
AWS_SECRET_ACCESS_KEY:指定与 CircleCI IAM 用户关联的 AWS 秘密访问密钥。
AWS_DEFAULT_REGION:指定 ECR 存储库所在的 AWS 区域:
- Once the environment variables have been set up, update the CircleCI configuration by adding an instruction to authenticate with ECR, before executing the
docker push
commands. The new changes will look as follows: - Substitute the
USER
,ID
, andREGION
variables appropriately with your own values and, once again, push the changes to the remote repository, under the develop branch:笔记
而不是硬编码配置中的
USER
、ID
和REGION
值文件,您可以将它们的值作为环境变量从 CircleCI 项目设置中传递。将触发一个新的管道。这一次,
build
作业应该成功了,您应该会看到类似于以下内容的内容:现在,点击 Push image 步骤。您应该会看到确认图像已存储在ECR中的日志:
对于使用 CI 构建的应用程序的每个镜像,在 ECR 存储库中也会有一个对应的标签:
笔记
除了动态构建的版本之外,我们还存储了一个
develop
标签,它指向开发分支中最新构建的图像。 - Similar to the previous jobs, add a
deploy
job to the current workflow:deploy
作业将简单地使用我们在上一章中介绍的docker-compose.yml
文件将应用程序堆栈部署到EC2 实例。该文件如下所示(为简洁起见,已裁剪完整的 YAML 文件): - To deploy the new changes to the EC2 instance where the containers are running, you will have to SSH to the remote server and issue two
docker-compose
commands –pull
andup
: - Make sure that you substitute the
IP
variable with the IP or the DNS name of the EC2 instance where the sandbox environment is running. - To SSH to the EC2 instance, add the SSH key pair you used to deploy the EC2 instance in AWS to your CircleCI project settings. Under SSH Keys, click on Add SSH Key and paste the content of the SSH key pair:
- Commit and push the new CircleCI config to GitHub with the following commands:
如果您是运行弹性容器服务(ECS),您可以强制 ECS 使用以下 CircleCI 配置提取新图像:
笔记
确保您将 ECS 权限分配给 CircleCI IAM 用户以成功执行任务更新。
的主要变化是我们使用 CircleCI orbs 而不是 Docker 图像作为运行时环境。通过使用 orbs,我们可以使用预先构建的命令,这减少了配置文件中的代码行数。部署作业会将更新后的镜像部署到沙盒 ECS 集群。
如果您正在运行 Kubernetes,则可以使用以下 CircleCI 规范文件来更新映像:
配置好 CI 和 CD 工作流程后,您可以通过为 Gin RESTful API 构建新功能来测试它们。您可以通过执行以下步骤来做到这一点:
- Update the
main.go
file and expose a new endpoint on the/version
resource using the Gin router. The endpoint will display the running API version:HTTP 处理程序是不言自明的;它返回
API_VERSION
环境变量的值: - To inject the environment variable dynamically, you can use the Docker arguments feature, which allows you to pass values at build time. Update our
Dockerfile
and declareAPI_VERSION
as a build argument and environment variable: - Next, update the
Build image
step by injecting the$TAG
variable as a value for theAPI_VERSION
build argument: - Push the new changes to the develop branch with the following code:
一旦我们推送,构建就会开始运行。一旦 CI 管道完成并生成成功消息,
deploy
作业将运行并在 EC2 上部署应用程序: - To test out the new changes, navigate to the instance IP address and point your browser to the
/api/version
resource path:
这将返回 Gin RESTful API 的正在运行的 Docker 映像的版本。
值得一提的是,当前的 CircleCI 配置并不能保证作业总是以相同的顺序运行(测试 -> 构建 -> 部署)。要维护 CI/CD 顺序,请使用 requires
关键字,如下所示:
这样,您可以确保部署作业仅在测试和构建作业都成功的情况下执行:
惊人的!现在,我们为 Gin 应用程序提供了完整的 CI/CD 管道。
Maintaining multiple runtime environments
在实际场景中,您需要多个环境来避免在验证之前将损坏的功能或主要错误推送到沙盒或暂存环境(或更糟的是生产环境) .
您可以通过运行基于我们在前几章中创建的沙盒环境的新 EC2 实例来创建一个 EC2 实例来托管暂存环境:
- Select the sandbox instance and click on Actions from the action bar. Then, click on Launch more like this from the Image and template drop-down list:
此选项将使用所选实例的配置详细信息自动填充 Amazon EC2 启动向导。
- Update the
Name
tag value tostaging
and click on Launch to provision the instance: - Once the instance is up and running, update CircleCI so that it tags the Docker image based on the branch name where the pipeline is running. In addition to the
dynamic
tag we created via theCIRCLE_BUILD_NUM
environment variable, push afixed
tag (develop, preprod, or master) if the current branch is either develop, preprod, or master: - Next, update the
deploy
job so that you can SSH it to the right EC2 instance IP address based on the current Git branch name:笔记
应定义 IP 地址(
IP_PROD
、IP_STAGING
和IP_SANDBOX
)作为 CircleCI 项目设置中的环境变量。 - Finally, update the workflow so that it deploys the changes, but only if the current Git branch is a
develop
,preprod
, ormaster
branch: - Commit and store the changes in GitHub using the following commands:
将在开发分支上自动触发一个新管道,其中更改将部署到沙盒环境:
在沙盒环境中验证 新更改后,您应该准备好将代码提升到暂存环境。
要部署到暂存环境,请执行以下步骤:
- Create a pull request (PR) to merge the develop branch into the preprod branch, as follows:
请注意,PR 已准备好合并,因为所有检查都已通过:
- Click on the Merge pull request button. A new pipeline will be triggered on the preprod branch and three jobs – test, build, and deploy – will be executed one by one:
- At the end of the build stage, a new image from the preprod branch, as well as its CircleCI build number, will be stored in the ECR repository, as follows:
- Now, deploy the image to the staging environment using the
docker-compose up
command. Hit the IP address of the staging environment; you should see the version of the running Docker image:
伟大的!您现在拥有一个暂存环境,您可以在其中验证您的 API 功能,然后再将它们推广到生产环境。
到目前为止,您已经学习了如何通过推送事件来实现持续部署。但是,在生产环境中,您可能希望在将新版本发布到生产环境之前添加额外的验证。这就是持续交付实践发挥作用的地方。
Implementing continuous delivery
要将 Gin 应用程序部署到生产环境,您需要启动专用 EC2 实例或 EKS 集群。在部署到生产环境之前,您必须要求进行手动验证。
使用 CircleCI,您可以使用 pause_workflow
作业与用户交互并在恢复管道之前请求批准。为此,请按照下列步骤操作:
- Add the
pause_workflow
job before thedeploy
job and define arelease
job, as follows: - Push the changes to the develop branch. A new pipeline will be triggered and the changes will be deployed to your sandbox environment. Next, create a pull request and merge the develop and preprod branches. Now, raise a pull request to merge the preprod branch and the master branch:
- Once the PR has been merged, a new pipeline will be triggered on the master branch and both the test and build jobs will be executed:
- When the
pause_workflow
job is reached, the pipeline will be paused, as follows: - If you click on the pause_workflow box, a confirmation dialog will pop up, where you can allow the workflow to continue running:
- Once approved, the pipeline will resume, and the deploy stage will be executed. At the end of the CI/CD pipeline, the application will be deployed into a production environment:
惊人的!这样,您就实现了持续交付!
在结束之前,您可以通过添加 Slack 通知来改进工作流程,以便在新构建完成时提高开发团队的意识在 CircleCI 上触发。
Improving the feedback loop with Slack
您可以使用 Slack RESTful API 在 Slack 上发布 通知频道或使用带有预建 Slack 命令的 CircleCI Slack orb 来改进反馈循环。
为此,请按照下列步骤操作:
- Add the following code block to the
test
job: - Then, create a new Slack application on your Slack workspace by navigating to https://api.slack.com/apps and clicking on Build app from the page's header:
- Give the application a meaningful name and click on the Create App button. On the OAuth & Permissions page, add the following permissions under Bot Token Scopes:
- From the left navigation menu, click on OAuth & Permissions and copy the OAuth token:
- Go back to the CircleCI project settings and add the following environment variables:
SLACK_ACCESS_TOKEN:我们之前生成的 OAuth Token。
SLACK_DEFAULT_CHANNEL:您要发布 CircleCI 构建通知的 Slack 频道。
您应该看到以下内容:
- Push the new CircleCI config updates to GitHub. At this point, a new pipeline will be executed:
将在配置的 Slack 通道上发送 Slack 通知,其中包含项目名称和 Git 分支的名称:
您甚至可以进一步并根据管道的状态发送通知。例如,如果您想在管道失败时收到警报,请添加 以下代码(为简洁起见,已裁剪完整的 JSON):
您可以通过抛出与 0
不同的代码错误来模拟管道故障:
现在,将更改推送到开发分支。当管道到达 单元测试
步骤时,将抛出 错误,并且 < /a>管道将失败:
在 Slack 频道上,您应该会收到类似于以下屏幕截图所示的通知:
差不多就是这样。这个章节只是触及了可以用CI/CD管道完成的事情的表面。但是,它应该为您开始为您的 Gin 应用程序试验和构建自己的端到端工作流提供足够的基础。
Questions
- Build a CI/CD pipeline to automate the deployment process for the React web application we built in Chapter 5, Serving Static HTML in Gin.
- Add a Slack notification for when a successful production deployment is made.
Further reading
- Hands-On Serverless Applications with Go by Mohamed Labouardy, Packt publishing
- Implementing DevOps with AWS by Salle Ingle, Packt publishing