如何使用 Gitlab-Ci 部署到使用 AWS CodeDeploy/CodePipeline/S3 的 EC2

How to deploy with Gitlab-Ci to EC2 using AWS CodeDeploy/CodePipeline/S3

我一直在使用 Gradle 开发基于 Scala 的 SlackBot 项目,并且一直在研究利用 Gitlab-CI 以部署到 AWS EC2 的方法。

我能够使用 Gitlab 完全构建和测试我的应用程序-CI。

如何使用 CodeDeploy 和 CodePipeline 执行从 Gitlab-CI 到 Amazon EC2 的部署?

要遵循的答案作为执行此操作的指南。

我创建了一组示例文件以配合下面提供的指南。 这些文件位于以下位置 link:https://gitlab.com/autronix/gitlabci-ec2-deployment-samples-guide/

范围

本指南假设以下内容

  • Gitlab EE 托管项目 - 可以在私有 CE/EE 实例上工作(未测试)
  • Gitlab 作为 GIT 版本库
  • Gitlab-CI 作为持续集成引擎
  • 现有 AWS 账户
  • AWS EC2 作为部署的目标生产或暂存系统
  • AWS EC2 实例 运行宁亚马逊 Linux AMI
  • AWS S3 作为部署文件的存储设施
  • AWS CodeDeploy 作为项目的部署引擎
  • AWS CodePipeline 作为部署管道

提供的 .gitlab-ci.yml 示例基于 Java/Scala + Gradle 项目。 该脚本作为通用示例提供,在通过此方法实施持续交付时需要根据您的特定需求进行调整。

该指南将假定用户具有有关 AWS 服务以及如何执行必要任务的基本知识。

注意:本示例中提供的指南使用 AWS 控制台执行任务。虽然这里执行的任务可能有等效的 CLI,但本指南不会涵盖这些内容。

动机

创建这些脚本和部署指南的动机来自于缺乏适当的教程来展示如何使用 Gitlab 和 AWS EC2 实施持续交付。 Gitlab 通过与 Digital Ocean 合作推出了他们免费提供的 CI 引擎,这使得用户存储库能够免费受益于高质量 CI。

使用 Gitlab 的主要优势之一是它们提供 built-in 持续集成容器,用于 运行 完成各个步骤并验证构建。 不幸的是,Gitblab 和 AWS 都提供了允许在通过构建后执行持续交付的集成。

本指南和脚本 (https://gitlab.com/autronix/gitlabci-ec2-deployment-samples-guide/) 提供了我为使用 Gitlab 和 AWS EC2 获得成功 CI 和 CD 所采取的步骤的简化版本,这可以提供帮助任何其他人都开始使用这种类型的实现。

在 AWS 上设置环境

确保持续交付过程成功的第一步是在 AWS 上设置必要的对象以使部署过程成功。

AWS IAM 用户

初始要求是设置一个 IAM 用户:

https://console.aws.amazon.com/iam/home#users

  1. 创建用户
  2. 附加以下权限:

    • CodePipelineFullAccess
    • AmazonEC2FullAccess
    • AmazonS3FullAccess
    • AWSCodeDeployFullAccess
    • 内联策略:

        {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Action": [
                "autoscaling:*",
                "codedeploy:*",
                "ec2:*",
                "elasticloadbalancing:*",
                "iam:AddRoleToInstanceProfile",
                "iam:CreateInstanceProfile",
                "iam:CreateRole",
                "iam:DeleteInstanceProfile",
                "iam:DeleteRole",
                "iam:DeleteRolePolicy",
                "iam:GetInstanceProfile",
                "iam:GetRole",
                "iam:GetRolePolicy",
                "iam:ListInstanceProfilesForRole",
                "iam:ListRolePolicies",
                "iam:ListRoles",
                "iam:PassRole",
                "iam:PutRolePolicy",
                "iam:RemoveRoleFromInstanceProfile",
                "s3:*"
              ],
              "Resource": "*"
            }
          ]
        }
      
  3. 生成安全凭证

注意:上面列出的政策范围非常广泛。您可以通过创建仅限制对某些资源的访问的自定义策略来调整您的要求。

注意:请将这些凭据保存在安全位置。您将在后面的步骤中需要它们。

AWS EC2 实例和角色

CodeDeploy 的实例角色

https://console.aws.amazon.com/iam/home#roles

创建一个将分配给您的 EC2 实例以访问 S3 的新角色,

  1. 根据您的命名约定设置名称(即。MyDeploymentAppRole
  2. Select Amazon EC2 以便允许 EC2 实例 运行 其他 AWS 服务
  3. 附上以下政策:
    • AmazonEC2FullAccess
    • AmazonS3FullAccess
    • AWSCodeDeployRole

注意:上面列出的政策范围非常广泛。您可以通过创建仅限制对某些资源的访问的自定义策略来调整您的要求。

启动实例

https://console.aws.amazon.com/ec2/v2/home

单击 Launch Instance 并按照以下步骤操作:

  • SelectAmazon Linux AMI 2016.03.3 (HVM), SSD Volume Type
  • Select 所需的实例类型(默认为t2.micro)
    • 下一个
  • SelectIAM Role变为MyDeploymentAppRole(根据上一节创建的名称)
    • 下一个
  • Select适当的存储
    • 下一个
  • 用适当的名称标记您的实例(即 MyApp-Production-Instance
    • 根据需要添加其他标签
    • 下一个
  • 根据需要配置安全组
    • 下一个
  • 检查并启动您的实例

您将有机会生成 o使用 SSH 密钥。请select适当的适用方法。

设置实例环境

安装 CodeDeploy 代理

登录到您新创建的 EC2 实例并按照说明操作:

CodeDeploy 重要路径:

  • CodeDeploy 部署基目录:/opt/codedeploy-agent/deployment-root/
  • CodeDeploy 日志文件:/var/log/aws/codedeploy-agent/codedeploy-agent.log

提示:运行 tail -f /var/log/aws/codedeploy-agent/codedeploy-agent.log实时跟踪部署。

安装项目先决条件 如果您的项目有任何 运行 的先决条件,请确保在 运行 部署之前安装这些先决条件,否则您的启动脚本可能会失败。

AWS S3 存储库

https://console.aws.amazon.com/s3/home

在此步骤中,您需要创建一个 S3 存储桶来保存您的部署文件。

只需按照以下步骤操作:

  1. 选择Create Bucket
    • Select 存储桶名称(即 my-app-codepipeline-deployment
    • Select一个地区
  2. 在您的存储桶的控制台中 select Properties
    • 展开 Versioning 菜单
    • 选择Enable Versioning

AWS CodeDeploy

https://console.aws.amazon.com/codedeploy/home#/applications

既然设置了基本元素,我们就可以在 CodeDeploy 中创建 Deployment 应用程序了

要创建 CodeDeploy 部署应用程序,请执行以下步骤:

  1. SelectCreate New Application
  2. 选择一个应用程序名称(即 MyApp-Production
  3. 选择部署组名称(即 MyApp-Production-Fleet
  4. Select 将受此部署影响的 EC2 实例 - Search by Tags
    • KeySelectName
    • ValueSelectMyApp-Production-Instance
  5. Service Role,SelectMyDeploymentAppRole
  6. 点击Create Application

注意:您可以将部署分配给应用于部署目标实例的任何相关标签。为简单起见,仅使用名称标签来选择先前定义的实例。

AWS CodePipeline

https://console.aws.amazon.com/codepipeline/home#/dashboard

下一步是继续创建 CodePipeline,它负责执行 S3 存储桶和 CodeDeploy 进程之间的连接。

要创建 CodePipeline,请执行以下步骤:

  1. 点击Create Pipeline
  2. 为您的管道命名(即 MyAppDeploymentPipeline
    • 下一个
  3. Source Provider 设置为 Amazon S3
    • Amazon S3 location 设置为您的存储桶地址和目标部署文件(即 s3://my-app-codepipeline-deployment/myapp.zip
    • 下一个
  4. Build Provider 设置为 None - 这已由 Gitlab-CI 处理,稍后将介绍
    • 下一个
  5. Deployment Provider 设置为 AWS CodeDeploy
    • Application Name 设置为您的 CodeDeploy 应用程序的名称(即 MyApp-Production
    • Deployment Group 设置为您的 CodeDeploy 部署组的名称(即 MyApp-Production-Fleet
    • 下一个
  6. 创建或选择管道服务角色
    • 下一个
  7. 查看并点击 Create Pipeline

在Gitlab上搭建环境

现在 AWS 环境已准备好接收应用程序部署,我们可以继续设置 CI 环境和设置,以确保使用 S3、CodeDeploy 构建代码并将其部署到 EC2 实例和 CodePipeline。

Gitlab 变量

为了部署工作,我们需要在项目存储库中设置一些环境变量。

在您的 Gitlab 项目中,导航到项目的 Variables 区域并设置以下变量:

  • AWS_DEFAULT_REGION => 您的 AWS 区域
  • AWS_SECRET_ACCESS_KEY => 您的 AWS 用户凭据密钥(在您为用户生成凭据时获得)
  • AWS_ACCESS_KEY_ID => 您的 AWS 用户凭证密钥 ID(在您为用户生成凭证时获得)
  • AWS_S3_LOCATION => 部署 zip 文件的位置(即 s3://my-app-codepipeline-deployment/my_app.zip

这些变量将可由 Gitlab-CI 容器执行的脚本访问。

启动脚本

已提供一个简单的启动脚本 (https://gitlab.com/autronix/gitlabci-ec2-deployment-samples-guide/blob/master/deploy/extras/my_app.sh) 以允许部署执行以下任务:

  • 启动应用程序并创建 PID 文件
  • 通过PID文件查看应用状态
  • 停止应用程序

您可能会在 deploy/extras/my_app.sh

下找到此脚本

正在创建 gitlab-ci.yml

gitlab-ci.yml 文件负责执行与给定提交关联的持续集成任务。 它充当一组简化的 shell 脚本,这些脚本按阶段组织,对应于不同的持续集成步骤中的阶段。

更多的细节和参考,请参考以下两个link:

您可以随时使用以下工具验证 gitlab-ci.yml 文件的语法:https://gitlab.com/ci/lint

出于部署的目的,我们将仅介绍本指南提供的示例的最后一部分:

deploy-job:
  # Script to run for deploying application to AWS
  script:
    - apt-get --quiet install --yes python-pip # AWS CLI requires python-pip, python is installed by default
    - pip install -U pip  # pip update
    - pip install awscli  # AWS CLI installation
    - $G build -x test -x distTar # # Build the project with Gradle
    - $G distZip  # creates distribution zip for deployment
    - aws s3 cp $BUNDLE_SRC $AWS_S3_LOCATION # Uploads the zipfile to S3 and expects the AWS Code Pipeline/Code Deploy to pick up
  # requires previous CI stages to succeed in order to execute
  when: on_success
  stage: deploy
  environment: production
  cache:
    key: "$CI_BUILD_NAME/$CI_BUILD_REF_NAME"
    untracked: true
    paths:
        - build/
  # Applies only to tags matching the regex: ie: v1.0.0-My-App-Release
  only:
    - /^v\d+\.\d+\.\d+-.*$/
  except:
    - branches
    - triggers

这部分表示与之前的部署相关的整个作业,如果有的话,C.I。阶段。

与部署相关的部分是这样的:

# Script to run for deploying application to AWS
script:
  - apt-get --quiet install --yes python-pip # AWS CLI requires python-pip, python is installed by default
  - pip install -U pip  # pip update
  - pip install awscli  # AWS CLI installation
  - $G build -x test -x distTar # # Build the project with Gradle
  - $G distZip  # creates distribution zip for deployment
  - aws s3 cp $BUNDLE_SRC $AWS_S3_LOCATION # Uploads the zipfile to S3 and expects the AWS Code Pipeline/Code Deploy to pick up

第一步涉及安装 python 包管理系统:pippip 需要安装 AWS CLI,这是将部署文件上传到 AWS S3 所必需的

在本例中,我们使用Gradle(由环境变量$G定义); Gradle 提供了一个自动压缩部署文件的模块。根据您部署的项目类型,此方法生成分发 zip 文件的方法会有所不同 my_app.zip.

aws s3 cp $BUNDLE_SRC $AWS_S3_LOCATION 命令将分发 zip 文件上传到我们之前定义的 Amazon S3 位置。然后,CodePipeline 会自动检测、处理此文件并将其发送到 CodeDeploy。 最后,CodeDeploy 通过 appspec.yml 文件指定的 CodeDeploy 代理执行必要的任务。

正在创建appspec.yml

appspec.yml 定义了 CodeDeploy 在收到部署文件后要遵循的行为。

随本指南一起提供了示例文件以及要在部署的各个阶段执行的示例脚本。

有关如何构建 appspec.yml 文件的更多信息,请参阅 CodeDeploy AppSpec 规范:http://docs.aws.amazon.com/codedeploy/latest/userguide/app-spec-ref.html

正在生成部署 ZipFile

为了使 CodeDeploy 正常工作,您必须为您的应用程序创建一个正确生成的 zip 文件。

压缩文件必须包含:

  • 压缩根
    • appspec.yml => CodeDeploy部署说明
    • 部署阶段脚本
    • 提供的示例将放置在 zip 文件的 scripts 目录中,需要在应用程序目录的根目录中添加 my_app.sh 脚本(即 my_app 压缩包中的目录)
    • 分发代码 - 在我们的示例中,它将位于 my_app 目录下

Gradle 和 Maven 等工具能够通过对 zip 生成过程进行某些更改来生成分发 zip 文件。 如果您不使用此类工具,您可能需要指示 Gitlab-CI 以不同的方式生成此 zip 文件;此方法超出本指南的范围。

正在将您的应用程序部署到 EC2

本指南的最后一步实际上是执行成功的部署。

持续集成的阶段由 gitlab-ci.yml 中设置的规则定义。本指南提供的示例将为匹配以下正则表达式的任何引用启动部署:/^v\d+\.\d+\.\d+-.*$/.

在这种情况下,通过 git 将标签 v1.0.0-My-App-Alpha-Release 推送到您的远程 Gitlab 将启动部署过程。您可以根据您的项目要求调整这些规则。

所提供的 gitlab-ci.yml 示例将在检测标签 v1.0.0-My-App-Alpha-Release 时执行以下作业:

  • 构建作业 - 编译源代码
  • 测试作业 - 运行 单元测试
  • deploy-job - 编译源代码,生成分发 zip,将 zip 上传到 Amazon S3

分发 zip 上传到 Amazon S3 后,将发生以下步骤:

  • CodePipeline 检测到 S3 zip 文件修订中的更改
  • CodePipeline 验证文件
  • CodePipeline 发送 CodeDeploy 包已准备就绪的信号
  • CodeDeploy 执行部署步骤
    • 开始 - 部署初始化
    • 应用程序停止 - 为挂钩执行定义的脚本
    • DownloadBundle - 通过 CodePipeline
    • 从 S3 存储库获取捆绑文件
    • BeforeInstall - 为挂钩执行定义的脚本
    • 安装 - 将内容复制到 appspec.yml
    • files 部分定义的部署位置
    • AfterInstall - 为挂钩执行定义的脚本
    • ApplicationStart - 为挂钩执行定义的脚本
    • ValidateService - 为钩子执行定义的脚本
    • 结束 - 向 CodePipeline 发出部署已成功完成的信号

部署成功截图:

参考参考资料

autronix 的回答很棒,尽管在我的例子中,由于以下错误我不得不放弃 CodePipeline 部分:The deployment failed because a specified file already exists at this location : /path/to/file。这是因为我在该位置已经有了文件,因为我使用的是现有实例,服务器 运行 已经在上面。

这是我的解决方法:

.gitlab-ci.yml 中,这是我更改的内容:

deploy:
  stage: deploy
  script:
    - curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" # Downloading and installing awscli
    - unzip awscliv2.zip
    - ./aws/install
    - aws deploy push --application-name App-Name --s3-location s3://app-deployment/app.zip # Adding revision to s3 bucket
    - aws deploy create-deployment --application-name App-Name --s3-location bucket=app-deployment,key=app.zip,bundleType=zip --deployment-group-name App-Name-Fleet --deployment-config-name CodeDeployDefault.OneAtATime --file-exists-behavior OVERWRITE # Ordering the deployment of the new revision
  when: on_success
  only:
    refs:
      - dev

重要的部分是带有标志 --file-exists-behavioraws deploy create-deployment 行。有 three options availableOVERWRITE 是我需要的,但我无法使用 CodePipeline 设置此标志,所以我选择了 cli 选项。

我还对 .zip 的上传部分进行了一些更改。我没有自己创建 .zip,而是使用 aws deploy push 命令,它将在 s3 存储桶上为我创建一个 .zip。

真的没有别的可以修改了