vlambda博客
学习文章列表

读书笔记《building-distributed-applications-in-gin》CD管道

Chapter 9: Implementing a CI/CD Pipeline

本章将向您展示如何构建 CI/CD 工作流来自动部署 Gin 服务。我们还将讨论在构建基于 Gin 的 API 时采用 GitFlow 方法的重要性。

在本章中,我们将介绍以下主题:

  • Exploring CI/CD practices
  • Building a continuous integration workflow
  • Maintaining multiple runtime environments
  • Implementing continuous delivery

在本章结束时,您将能够自动化 Gin Web 应用程序的测试、构建和部署过程。

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 包等),并将结果推送到用于版本控制的私有注册表:

读书笔记《building-distributed-applications-in-gin》CD管道

图 9.1 – CI/CD 实践

如上图所示,CI 工作流程由以下阶段组成:Checkout、Test、构建和推送。

Continuous deployment

另一方面,持续部署(CD)是一个扩展CI 工作流程。通过 CI 管道所有阶段的每个更改都会自动发布到暂存或预生产环境中,QA 团队可以在其中运行验证和验收测试。

Continuous delivery

持续交付类似于 CD,但需要人工干预或业务验证,然后才能将新版本部署到生产环境。这种人工参与可能包括手动部署,这通常由 QA 工程师执行,或者像单击按钮一样简单。这与 CD 不同,在 CD 中,每个成功的构建都会发布到登台环境。

采用这三种做法有助于提高代码的质量和可测试性,还有助于降低将损坏的版本发布到生产环境的风险。

现在您了解了这三个组件是什么,在本章结束时,您将能够为我们的 Gin Web 应用程序构建一个端到端的部署流程,类似于下图所示的流程:

读书笔记《building-distributed-applications-in-gin》CD管道

图 9.2 – CI/CD 管道

前面的管道分为以下几个阶段:

  • 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 存储库的样子:

读书笔记《building-distributed-applications-in-gin》CD管道

图 9.3 – 项目的 GitHub 存储库

您将 使用 CircleCI 来自动化 CI/CD 工作流程。如果您还没有 CircleCI 帐户,请在 https://circleci.com 上使用您的 GitHub 帐户免费注册 。无论 CI 服务器如何,CI/CD 的原理都是一样的:

读书笔记《building-distributed-applications-in-gin》CD管道

图 9.4 – CircleCI 登陆页面

注册后,需要配置 CircleCI 以运行应用程序测试并构建 Docker 映像。为此,您需要在模板文件中描述所有步骤并将其保存在代码的 GitHub 存储库中。这种方法称为管道即代码。

Pipeline as Code

当触发 CircleCI 构建时,它会在 中查找 .circleci/config.yml 文件。此文件包含要在 CI 服务器上执行的指令。

首先创建一个 .circleci 文件夹和一个 .config.yml 文件,其内容如下:

version: 2.1
executors:
 environment:
   docker:
     - image: golang:1.15.6
   working_directory: 
jobs:
 test:
   executor: environment
   steps:
     - checkout
workflows:
 ci_cd:
   jobs:
     - test

前面的 代码片段将在由 Golang v1.15.6 Docker 映像提供支持的环境中运行 工作流。大多数 CI/CD 步骤将使用 Docker 执行,这使得在本地运行构建变得轻而易举,并且如果我们将来想要迁移到不同的 CI 服务器(相对于供应商锁定),我们的选择仍然是开放的。要运行的第一个作业是测试阶段,它包括以下步骤:

jobs:
 test:
   executor: environment
   steps:
     - checkout
     - restore_cache:
         keys:
           - go-mod-v4-{{ checksum "go.sum" }}
     - run:
         name: Install Dependencies
         command: go mod download
     - save_cache:
         key: go-mod-v4-{{ checksum "go.sum" }}
         paths:
           - "/go/pkg/mod"
     - run:
         name: Code linting
         command: >
           go get -u golang.org/x/lint/golint
           golint ./...
     - run:
         name: Unit tests
         command: go test -v ./...

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 应用程序创建一个 项目。为此,请按照下列步骤操作:

  1. Jump to the CircleCI console and click on Set up Project, next to the project's repository:
    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.5 – 建立一个 CircleCI 项目

  2. Click on the Use Existing Config button, since we already have a CircleCI configuration, and click on Start Building:
    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.6 – CircleCI 配置

  3. 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:
    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.7 – 管道失败

  4. Push the CircleCI configuration to the GitHub repository on the develop branch by running the following commands:
    git add .
    git commit –m "added test stage"
    git push origin develop

    将自动触发一个新的管道。输出将类似于以下内容:

    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.8 – 管道已自动触发

  5. Click on the test job.

    您应该看到 config.yml 文件中描述的步骤。所有测试都将通过,您将能够构建您的 Docker 映像:

    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.9 – 运行自动化测试

    值得提到管道是自动触发的,因为在设置 CircleCI 项目时,会在项目的 GitHub 存储库中自动创建一个 webhook。这样,对于每个推送事件,都会向 CircleCI 服务器发送通知以触发相应的 CircleCI 管道:

    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.10 – GitHub Webhook

    让我们继续通过构建 Docker 映像来集成应用程序的下一步。

  6. Add a build job to the CI/CD workflow:
    workflows:
     ci_cd:
       jobs:
         - test
         - build
  7. The build job is responsible for building a Docker image based on our Dockerfile, which is stored within the code repository. Then, it tags the built image and stores it in a remote Docker registry for versioning:
    build:
        executor: environment
       steps:
         - checkout
         - setup_remote_docker:
            version: 19.03.13
         - run:
             name: Build image
             command: >
               TAG=0.1.$CIRCLE_BUILD_NUM
               docker build -t USER/recipes-api:$TAG .
         - run:
             name: Push image
             command: >
               docker tag USER/recipes-api:$TAG 
                   ID.dkr.ecr.REGION.amazonaws.com/USER/
                   recipes-api:$TAG
               docker tag USER/recipes-api:$TAG 
                   ID.dkr.ecr.REGION.amazonaws.com/USER/
                   recipes-api:develop
               docker push ID.dkr.ecr.REGION.amazonaws.com/
                   USER/recipes-api:$TAG
               docker push ID.dkr.ecr.REGION.amazonaws.com/
                   USER/recipes-api:develop

    笔记

    如果您对 Dockerfile 感兴趣,可以在本书的 GitHub 存储库中找到它,地址为 https://github.com/PacktPublishing/Building-Distributed-Applications-in-Gin/blob/main/chapter10/Dockerfile

    为了标记图像,我们将使用语义版本控制 (https://semver.org )。版本的格式是三位数字,用点分隔:

    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.11 – 语义版本控制

    当新的更改破坏 API(向后不兼容的更改)时,主版本会增加。发布新功能时,次要版本会增加,而补丁版本会随着错误修复而增加。

    在 CircleCI 配置中,您使用 $CIRCLE_BUILD_NUM 环境 变量为通过以下方式构建的每个 Docker 映像创建唯一版本我们的 Gin 应用程序的开发周期。另一种选择是使用 CIRCLE_SHA1 变量,它是触发 CI 构建的 Git 提交的 SHA1 哈希。

  8. 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.
  9. Push the changes to the develop branch with the following command:
    git add .
    git commit –m "added build stage"
    git push origin develop

将触发一个新的管道。 test 作业完成后,将执行 build 作业,如下图所示:

读书笔记《building-distributed-applications-in-gin》CD管道

图 9.12 – 运行“构建”作业

以下是 build 作业的步骤。测试应该在 Push image 步骤失败,因为由于缺少 AWS 权限,CircleCI 无法将图像推送到 ECR:

读书笔记《building-distributed-applications-in-gin》CD管道

图 9.13 – 推送图像步骤

现在让我们看看如何配置 CI 和 CD 工作流程:

  1. To allow CircleCI to interact with your ECR repository, create a dedicated IAM user with proper IAM policies.
  2. 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:
    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.14 – CircleCI IAM 用户

  3. 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:
    {
        "Version": "2008-10-17",
        "Statement": [
            {
                "Sid": "AllowPush",
                "Effect": "Allow",
                "Principal": {
                    "AWS": [
                        "arn:aws:iam::ID:circleci/
                                      push-pull-user-1"
                    ]
                },
                "Action": [
                    "ecr:PutImage",
                    "ecr:InitiateLayerUpload",
                    "ecr:UploadLayerPart",
                    "ecr:CompleteLayerUpload"
                ]
            }
        ]
    }
  4. 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:
    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.15 – CircleCI 环境变量

  5. 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 区域:

    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.16 – AWS 凭证作为环境变量

  6. 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:
        -run:
            name: Push image
            command: |
                TAG=0.1.$CIRCLE_BUILD_NUM
               docker tag USER/recipes-api:$TAG 
                   ID.dkr.ecr.REGION.amazonaws.com/USER/
                   recipes-api:$TAG
               docker tag USER/recipes-api:$TAG ID.dkr.ecr. 
                   REGION.amazonaws.com/USER/
                   recipes-api:develop
               aws ecr get-login-password --region REGION | 
                   docker login --username AWS --password-
                   stdin ID.dkr.ecr.REGION.amazonaws.com
               docker push ID.dkr.ecr.REGION.amazonaws.com
                   /USER/recipes-api:$TAG
        docker push ID.dkr.ecr.REGION.amazonaws.com
                   /USER/recipes-api:develop
  7. Substitute the USER, ID, and REGION variables appropriately with your own values and, once again, push the changes to the remote repository, under the develop branch:
    git add .
    git commit –m "authenticate with ecr"
    git push origin develop

    笔记

    而不是硬编码配置中的 USERIDREGION 值文件,您可以将它们的值作为环境变量从 CircleCI 项目设置中传递。

    将触发一个新的管道。这一次,build 作业应该成功了,您应该会看到类似于以下内容的内容:

    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.17 – 使用 CircleCI 构建和存储 Docker 镜像

    现在,点击 Push image 步骤。您应该会看到确认图像已存储在ECR中的日志:

    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.18 – Docker 标记和推送日志

    对于使用 CI 构建的应用程序的每个镜像,在 ECR 存储库中也会有一个对应的标签:

    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.19 – ECR 中的 Docker 映像

    笔记

    除了动态构建的版本之外,我们还存储了一个 develop 标签,它指向开发分支中最新构建的图像。

    随着测试和构建阶段的自动化,您可以走得更远,也可以自动化部署过程。

  8. Similar to the previous jobs, add a deploy job to the current workflow:
    workflows:
     ci_cd:
       jobs:
         - test
         - build
         - deploy

    deploy 作业将简单地使用我们在上一章中介绍的 docker-compose.yml 文件将应用程序堆栈部署到EC2 实例。该文件如下所示(为简洁起见,已裁剪完整的 YAML 文件):

    version: "3" 
    services:
      api:
        image: ID.dkr.ecr.REGION.amazonaws.com/USER/
               recipes-api:develop
        environment:
          - MONGO_URI=mongodb://admin:password@mongodb
                :27017/test?authSource=admin
                 &readPreference=primary&ssl=false
          - MONGO_DATABASE=demo
          - REDIS_URI=redis:6379
        external_links:
          - mongodb
          - redis
      redis:
        image: redis
      mongodb:
        image: mongo:4.4.3
        environment:
          - MONGO_INITDB_ROOT_USERNAME=admin
          - MONGO_INITDB_ROOT_PASSWORD=password
  9. 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 and up:
    deploy:
       executor: environment
       steps:
         - checkout
         - run:
             name: Deploy with Docker Compose
             command: |
               ssh -oStrictHostKeyChecking=no ec2-user@IP 
                   docker-compose pull && docker-compose up –d
  10. 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.
  11. 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:
    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.20 – 添加 SSH 密钥对

  12. Commit and push the new CircleCI config to GitHub with the following commands:
    git add .
    git commit –m "added deploy stage"
    git push origin develop

    会触发一个新的管道,测试、构建和部署作业将按顺序执行。在 deploy 作业结束时,新建的镜像将被部署到沙盒环境中:

读书笔记《building-distributed-applications-in-gin》CD管道

图 9.21 – 持续部署

如果您是运行弹性容器服务(ECS),您可以强制 ECS 使用以下 CircleCI 配置提取新图像:

version: 2.1
orbs:
 aws-ecs: circleci/[email protected]
workflows:
ci_cd:
   jobs:
    - test
    - build
    - aws-ecs/deploy-service-update:
       aws-region: AWS_DEFAULT_REGION
       family: 'demo'
       cluster-name: 'sandbox'
       container-image-name-updates: 
           'container=api,tag=0.1.${CIRCLE_BUILD_NUM}'

笔记

确保您将 ECS 权限分配给 CircleCI IAM 用户以成功执行任务更新。

的主要变化是我们使用 CircleCI orbs 而不是 Docker 图像作为运行时环境。通过使用 orbs,我们可以使用预先构建的命令,这减少了配置文件中的代码行数。部署作业会将更新后的镜像部署到沙盒 ECS 集群。

如果您正在运行 Kubernetes,则可以使用以下 CircleCI 规范文件来更新映像:

version: 2.1
orbs:
   aws-eks: circleci/[email protected]
   kubernetes: circleci/[email protected]
jobs:
 deploy:
   executor: aws-eks/python3
   steps:
     - checkout
     - aws-eks/update-kubeconfig-with-authenticator:
         cluster-name: sandbox
         install-kubectl: true
         aws-region: AWS_REGION
     - kubernetes/create-or-update-resource:
         resource-file-path: "deployment/
         api.deployment.yaml"
         get-rollout-status: true
         resource-name: deployment/api
     - kubernetes/create-or-update-resource:
         resource-file-path: "deployment/api.service.yaml"
        
workflows:
 ci_cd:
  jobs:
    - test
    - build
    - deploy

配置好 CI 和 CD 工作流程后,您可以通过为 Gin RESTful API 构建新功能来测试它们。您可以通过执行以下步骤来做到这一点:

  1. 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:
    router.GET("/version", VersionHandler)

    HTTP 处理程序是不言自明的;它返回 API_VERSION 环境变量的值:

    func VersionHandler(c *gin.Context) {
       c.JSON(http.StatusOK, gin.H{"version": os.Getenv(
           "API_VERSION")})
    }
  2. 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 declare API_VERSION as a build argument and environment variable:
    FROM golang:1.16
    WORKDIR /go/src/github.com/api
    COPY . .
    RUN go mod download
    RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .
    FROM alpine:latest 
    ARG API_VERSION
    ENV API_VERSION=$API_VERSION
    RUN apk --no-cache add ca-certificates
    WORKDIR /root/
    COPY --from=0 /go/src/github.com/api/app .
    CMD ["./app"]
  3. Next, update the Build image step by injecting the $TAG variable as a value for the API_VERSION build argument:
    run:
       name: Build image
        command: |
          TAG=0.1.$CIRCLE_BUILD_NUM
          docker build -t mlabouardy/
              recipes-api:$TAG --build-arg API_VERSION=${TAG} .
  4. Push the new changes to the develop branch with the following code:
    git add .
    git commit –m "inject api version"
    git push origin develop

    一旦我们推送,构建就会开始运行。一旦 CI 管道完成并生成成功消息,deploy 作业将运行并在 EC2 上部署应用程序:

    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.22 – 部署 Docker 堆栈

  5. To test out the new changes, navigate to the instance IP address and point your browser to the /api/version resource path:
读书笔记《building-distributed-applications-in-gin》CD管道

图 9.23 – API 运行版本

这将返回 Gin RESTful API 的正在运行的 Docker 映像的版本。

值得一提的是,当前的 CircleCI 配置并不能保证作业总是以相同的顺序运行(测试 -> 构建 -> 部署)。要维护 CI/CD 顺序,请使用 requires 关键字,如下所示:

workflows:
 ci_cd:
   jobs:
     - test
     - build:
       requires:
           - test
     - deploy:
       requires:
           - test
           - build

这样,您可以确保部署作业仅在测试和构建作业都成功的情况下执行:

读书笔记《building-distributed-applications-in-gin》CD管道

图 9.24 – CI/CD 工作流程

惊人的!现在,我们为 Gin 应用程序提供了完整的 CI/CD 管道。

Maintaining multiple runtime environments

在实际场景中,您需要多个环境来避免在验证之前将损坏的功能或主要错误推送到沙盒或暂存环境(或更糟的是生产环境) .

您可以通过运行基于我们在前几章中创建的沙盒环境的新 EC2 实例来创建一个 EC2 实例来托管暂存环境:

  1. 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:
    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.25 – 复制沙盒环境

    此选项将使用所选实例的配置详细信息自动填充 Amazon EC2 启动向导。

  2. Update the Name tag value to staging and click on Launch to provision the instance:
    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.26 – 在 EC2 实例中运行的暂存环境

  3. 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 the CIRCLE_BUILD_NUM environment variable, push a fixed tag (develop, preprod, or master) if the current branch is either develop, preprod, or master:
    run:
       name: Push image
       command: |
         TAG=0.1.$CIRCLE_BUILD_NUM
         aws ecr get-login-password --region REGION | docker 
             login --username AWS --password-stdin 
             ID.dkr.ecr.REGION.amazonaws.com
         docker tag USER/recipes-api:$TAG 
         ID.dkr.ecr.REGION.amazonaws.com/USER/recipes-api:$TAG
         docker push ID.dkr.ecr.REGION.amazonaws.com/
             USER/recipes-api:$TAG
         if [ "${CIRCLE_BRANCH}" == "master" ] || [ 
             "${CIRCLE_BRANCH}" == "preprod" ] || [ 
             "${CIRCLE_BRANCH}" == "develop" ];
        then
            docker tag USER/recipes-api:$TAG 
                ID.dkr.ecr.REGION.amazonaws.com/USER/
                recipes-api:${CIRCLE_BRANCH}
                 docker push ID.dkr.ecr.REGION.amazonaws.com/
                     USER/recipes-api:${CIRCLE_BRANCH}
          fi
  4. 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:
    run:
       name: Deploy with Docker Compose
       command: |
         if [ "${CIRCLE_BRANCH}" == "master" ]
         then
            ssh -oStrictHostKeyChecking=no ec2-user@IP_PROD 
                "docker-compose pull && docker-compose up -d"
        elif [ "${CIRCLE_BRANCH}" == "preprod" ]
         then
            ssh -oStrictHostKeyChecking=no             ec2-user@IP_STAGING 
                "docker-compose pull && docker-compose up -d"
         else
            ssh -oStrictHostKeyChecking=no             ec2-user@IP_SANDBOX 
                "docker-compose pull && docker-compose up -d"
         fi

    笔记

    应定义 IP 地址(IP_PRODIP_STAGINGIP_SANDBOX)作为 CircleCI 项目设置中的环境变量。

  5. Finally, update the workflow so that it deploys the changes, but only if the current Git branch is a develop, preprod, or master branch:
    workflows:
     ci_cd:
       jobs:
         - test
         - build:
             requires:
               - test
         - deploy:
             requires:
               - test
               - build
             filters:
               branches:
                 only:
                   - develop
                   - preprod
                   - master
  6. Commit and store the changes in GitHub using the following commands:
    git add .
    git commit –m "continuous deployment"
    git push origin develop

    将在开发分支上自动触发一个新管道,其中更改将部署到沙盒环境:

读书笔记《building-distributed-applications-in-gin》CD管道

图 9.27 – 部署到沙盒环境

在沙盒环境中验证 新更改后,您应该准备好将代码提升到暂存环境。

要部署到暂存环境,请执行以下步骤:

  1. Create a pull request (PR) to merge the develop branch into the preprod branch, as follows:
    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.28 – 创建拉取请求

    请注意,PR 已准备好合并,因为所有检查都已通过:

    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.29 – 成功的 Git 检查

  2. 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:
    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.30 – 部署到临时环境

  3. 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:
    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.31 – Preprod Docker 镜像

  4. 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:
读书笔记《building-distributed-applications-in-gin》CD管道

图 9.32 – Docker 镜像版本。

伟大的!您现在拥有一个暂存环境,您可以在其中验证您的 API 功能,然后再将它们推广到生产环境。

到目前为止,您已经学习了如何通过推送事件来实现持续部署。但是,在生产环境中,您可能希望在将新版本发布到生产环境之前添加额外的验证。这就是持续交付实践发挥作用的地方。

Implementing continuous delivery

要将 Gin 应用程序部署到生产环境,您需要启动专用 EC2 实例或 EKS 集群。在部署到生产环境之前,您必须要求进行手动验证。

使用 CircleCI,您可以使用 pause_workflow 作业与用户交互并在恢复管道之前请求批准。为此,请按照下列步骤操作:

  1. Add the pause_workflow job before the deploy job and define a release job, as follows:
    workflows:
     ci_cd:
       jobs:
         - test
         - build:
             requires:
               - test
         - deploy:
             requires:
               - test
               - build
             filters:
               branches:
                 only:
                   - develop
                   - preprod
         - pause_workflow:
             requires:
               - test
               - build
             type: approval
             filters:
               branches:
                 only:
                   - master
         - release:
             requires:
               - pause_workflow
             filters:
               branches:
                 only:
                   - master
  2. 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:
    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.33 – 合并到主分支的拉取请求

  3. 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:
    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.34 – 在主分支上运行 CI/CD 工作流

  4. When the pause_workflow job is reached, the pipeline will be paused, as follows:
    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.35 – 请求用户批准

  5. If you click on the pause_workflow box, a confirmation dialog will pop up, where you can allow the workflow to continue running:
    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.36 – 批准部署

  6. 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:
读书笔记《building-distributed-applications-in-gin》CD管道

图 9.37 – 将应用程序部署到生产环境

惊人的!这样,您就实现了持续交付!

在结束之前,您可以通过添加 Slack 通知来改进工作流程,以便在新构建完成时提高开发团队的意识在 CircleCI 上触发。

Improving the feedback loop with Slack

您可以使用 Slack RESTful API 在 Slack 上发布 通知频道或使用带有预建 Slack 命令的 CircleCI Slack orb 来改进反馈循环。

为此,请按照下列步骤操作:

  1. Add the following code block to the test job:
    - slack/notify:
             channel: "#ci"
             event: always
             custom: |
               {
                 "blocks": [
                   {
                     "type": "section",
                     "text": {
                       "type": "mrkdwn",
                       "text": "*Build has started*! 
                                 :crossed_fingers:"
                     }
                   },
                   {
                     "type": "divider"
                   },
                   {
                     "type": "section",
                     "fields": [
                       {
                         "type": "mrkdwn",
                         "text": "*Project*:\
                             n$CIRCLE_PROJECT_REPONAME"
                       },
                       {
                         "type": "mrkdwn",
                         "text": "*When*:\n$(date +'%m/%d/%Y 
                                   %T')"
                       },
                       {
                         "type": "mrkdwn",
                         "text": "*Branch*:\n$CIRCLE_BRANCH"
                       },
                       {
                         "type": "mrkdwn",
                         "text": "*Author*:                              \n$CIRCLE_USERNAME"
                       }
                     ],
                     "accessory": {
                       "type": "image",
                       "image_url": "https://media.giphy.com/
                        media/3orieTfp1MeFLiBQR2/giphy.gif",
                       "alt_text": "CircleCI logo"
                     }
                   },
                   {
                     "type": "actions",
                     "elements": [
                       {
                         "type": "button",
                         "text": {
                           "type": "plain_text",
                           "text": "View Workflow"
                         },
                         "url": "https://circleci.com/
                            workflow-run/${                                     CIRCLE_WORKFLOW_ID}"
                       }
                     ]
                   }
                 ]
               }
  2. 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:
    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.38 – 新的 Slack 应用程序

  3. 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:
    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.39 – Slack 机器人权限

  4. From the left navigation menu, click on OAuth & Permissions and copy the OAuth token:
    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.40 – Bot 用户 OAuth 令牌

  5. Go back to the CircleCI project settings and add the following environment variables:

    SLACK_ACCESS_TOKEN:我们之前生成的 OAuth Token。

    SLACK_DEFAULT_CHANNEL:您要发布 CircleCI 构建通知的 Slack 频道。

    您应该看到以下内容:

    读书笔记《building-distributed-applications-in-gin》CD管道

    图 9.41 – Slack 环境变量

  6. Push the new CircleCI config updates to GitHub. At this point, a new pipeline will be executed:
读书笔记《building-distributed-applications-in-gin》CD管道

图 9.42 – 管道启动时的 Slack 通知

将在配置的 Slack 通道上发送 Slack 通知,其中包含项目名称和 Git 分支的名称:

读书笔记《building-distributed-applications-in-gin》CD管道

图 9.43 – 发送 Slack 通知

您甚至可以进一步并根据管道的状态发送通知。例如,如果您想在管道失败时收到警报,请添加 以下代码(为简洁起见,已裁剪完整的 JSON):

- slack/notify:
     channel: "#ci"
     event: fail
     custom: |
       {
         "blocks": [
           {
             "type": "section",
             "text": {
                "type": "mrkdwn",
                "text": "*Tests failed, run for your 
                         life*! :fearful:"
              }
          ]
       }

您可以通过抛出与 0 不同的代码错误来模拟管道故障:

- run:
     name: Unit tests
     command: |
       go test -v ./...
       exit 1

现在,将更改推送到开发分支。当管道到达 单元测试 步骤时,将抛出 错误,并且 < /a>管道将失败:

读书笔记《building-distributed-applications-in-gin》CD管道

图 9.44 – 以编程方式抛出错误

在 Slack 频道上,您应该会收到类似于以下屏幕截图所示的通知:

读书笔记《building-distributed-applications-in-gin》CD管道

图 9.45 – 当管道失败时发送通知

差不多就是这样。这个章节只是触及了可以用CI/CD管道完成的事情的表面。但是,它应该为您开始为您的 Gin 应用程序试验和构建自己的端到端工作流提供足够的基础。

Summary

在本章中,您学习了如何从头开始设置 CI/CD 管道,以使用 CircleCI 自动执行 Gin 应用程序的部署过程。此外,使用 CircleCI 球体通过简化我们编写管道即代码配置的方式来提高生产力。

您还探索了如何使用 Docker 运行自动化测试,以及如何使用 GitFlow 和多个 AWS 环境实现持续部署。在此过程中,您设置了 Slack 通知,以便在构建失败或成功时收到警报。

本书的最后一章将介绍如何对生产中运行的 Gin 应用程序进行故障排除和调试。

Questions

  1. 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.
  2. 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