如何使用Gitlab-Ci和AWS CodeDeploy/CodePipeline/S3将代码部署到EC2?

47
我一直在使用Scala和Gradle构建一个SlackBot项目,并正在寻找利用Gitlab-CI部署到AWS EC2的方法。
我已经能够通过Gitlab-CI完全构建和测试我的应用程序。
如何使用CodeDeploy和CodePipeline从Gitlab-CI将应用程序部署到Amazon EC2?
请看下面的指南。
2个回答

165
I have created a set of sample files to go with the Guide provided below. These files are available at the following link: https://gitlab.com/autronix/gitlabci-ec2-deployment-samples-guide/

范围

本指南假定以下内容:

  • Gitlab EE 托管项目 - 可能适用于私人 CE/EE 实例(未经测试)
  • Gitlab 作为 GIT 版本库
  • Gitlab-CI 作为持续集成引擎
  • 现有的 AWS 账户
  • AWS EC2 作为目标生产或暂存系统进行部署
  • AWS EC2 实例运行 Amazon 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的主要优势之一是他们提供内置的持续集成容器,用于运行各个步骤并验证构建。 不幸的是,Gitlab和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. Create a user
  2. Attach the following permissions:

    • CodePipelineFullAccess
    • AmazonEC2FullAccess
    • AmazonS3FullAccess
    • AWSCodeDeployFullAccess
    • Inline Policy:

        {
          "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. Generate security credentials

注意:上述政策范围非常广泛。您可以通过创建自定义策略,仅限制访问某些资源来调整其符合您的要求。
注意:请将这些凭据保存在安全位置。您将在后续步骤中需要它们。
AWS EC2实例和角色
CodeDeploy实例角色

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

创建一个新角色,分配给你的EC2实例,以便访问S3,
1. 根据您的命名惯例设置名称(例如,MyDeploymentAppRole) 2. 选择Amazon EC2,以允许EC2实例运行其他AWS服务 3. 附加以下策略:
- AmazonEC2FullAccess - AmazonS3FullAccess - AWSCodeDeployRole 注意:上述策略范围非常广泛。您可以通过创建仅限于特定资源的自定义策略来调整您的要求。
启动实例

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

点击 启动实例 并按照以下步骤操作:

  • 选择 Amazon Linux AMI 2016.03.3 (HVM), SSD Volume Type
  • 选择所需的实例类型(默认为 t2.micro)
    • 下一步
  • 选择 IAM 角色MyDeploymentAppRole(基于上一部分创建的名称)
    • 下一步
  • 选择适当的存储
    • 下一步
  • 使用适当的名称标记您的实例(例如 MyApp-Production-Instance
    • 根据需要添加其他标签
    • 下一步
  • 根据需要配置安全组
    • 下一步
  • 审核并启动您的实例

您将有可能生成或使用 SSH 密钥。请选择适当的方法。

设置实例环境

安装 CodeDeploy Agent

登录到您新创建的 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. 选择 创建存储桶
    • 选择存储桶名称(例如:my-app-codepipeline-deployment
    • 选择区域
  2. 在存储桶的控制台中选择 属性
    • 展开 版本控制 菜单
    • 选择 启用版本控制

AWS CodeDeploy

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

现在基本元素已经设置好,我们准备在CodeDeploy中创建部署应用程序。
按照以下步骤创建CodeDeploy部署应用程序:
  1. 选择“创建新应用程序”
  2. 选择一个应用程序名称(例如“MyApp-Production”)
  3. 选择一个部署组名称(例如“MyApp-Production-Fleet”)
  4. 选择将受此部署影响的EC2实例 - “按标签搜索”
    • 在“键”下选择“Name”
    • 在“值”下选择“MyApp-Production-Instance”
  5. 在“服务角色”下,选择“MyDeploymentAppRole”
  6. 单击“创建应用程序”
注意:您可以将部署分配给任何适用于所需实例的相关标记。为简单起见,先前定义的实例仅使用了名称标记来选择实例。

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和CodePipeline将代码构建并部署到EC2实例。

Gitlab变量

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

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

  • 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脚本,这些脚本按阶段组织,这些阶段对应于您的持续集成步骤中的不同阶段。

有关详细信息和参考,请参阅以下两个链接:

你可以使用以下工具随时验证你的 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

这部分代表与之前任何持续集成阶段相关联的整个部署工作。
与部署相关的相关部分如下:
# 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包管理系统:pip。需要使用pip来安装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在收到部署文件后要遵循的行为。
本指南附带了一个示例文件以及在部署的各个阶段执行的示例脚本。
请参考CodeDeploy AppSpec规范,了解如何构建appspec.yml文件的详细信息: http://docs.aws.amazon.com/codedeploy/latest/userguide/app-spec-ref.html 生成部署Zip文件
为了使CodeDeploy正常工作,您必须创建一个正确生成的应用程序zip文件。
Zip文件必须包含:
- Zip根目录 - appspec.yml => CodeDeploy部署说明 - 部署阶段脚本 - 提供的示例将放置在zip文件中的scripts目录中,需要在应用程序目录的根目录(即my_app目录在zip中)添加my_app.sh脚本。 - 发布代码-在我们的示例中,它将位于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将启动部署过程。您可以根据项目要求调整这些规则。

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

  • 构建作业 - 编译源代码
  • 测试作业 - 运行单元测试
  • 部署作业 - 编译源代码,生成分发压缩包,上传到Amazon S3

一旦分发压缩包被上传到Amazon S3,以下步骤将会发生:

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

成功部署的截图:

Gitlab Deploy Job

CodePipeline Deploy

CodeDeploy hook script log

参考资料


2
非常好的答案和详细的解释! - Darren Reid

5
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行。有三个选项可用OVERWRITE是我需要的选项,我无法通过CodePipeline设置此标志,因此我选择了cli选项。
我还稍微更改了上传.zip的部分。我不是自己创建.zip,而是使用aws deploy push命令,在s3存储桶上为我创建.zip。
真的没有其他需要修改的地方。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接