Jenkins + AWS CodeDeploy + AutoScaling 持续集成

本文主要记录如何结合jenkins,codedeploy,s3, autoscaling等相关服务搭建一套可持续交付和应用部署的服务。

Aws AutoScaling部分

1、使用Auto Scaling的优点

1)、保持基础设置堆栈配置一致(例如软件nginx、php等安装配置一致)

2)、快速设置扩展(只需要设定Auto Scaling组内的所需实例数量即可完成实例的扩展)

3)、制定明确的扩展策略(比如根据CPU的利用率时增加或是缩减实例数量)

4)、控制实例资源成本(在Auto Scaling组内的实例通常都比较小,不然就失去了AutoScaling自动扩展的意义)

2、Auto Scaling组件说明

Auto Scaling组:EC2实例放在组中,用于扩展和管理的逻辑单元,在创建组时,可以指定其最小,最大和所需EC2的实例数量

(备注:auto Scaling 组是与启动配置相关联的)

Auto Scaling启动配置:EC2实例启动时的模板(指定实例类型,密钥对,安全组和磁盘空间大小)

3、创建启动配置步骤

1)、为EC2实例创建IAM角色

https://console.aws.amazon.com/iam/

2)、为Auto Scaling 创建启动配置(下图为已经设置好的启动配置模板)

3)、为EC2实例启动时添加必要的用户数据(主要为应用程序事先搭建好基础环境)

脚本如下:

#!/bin/bash

#run all command as root,system: ubuntu16.04

#enter /opt/patpat-devops folder

cd /opt/patpat-devops

#download aws codedeploy agent,and start

rm -rf codedeploy-agent

mkdir codedeploy-agent

cd codedeploy-agent

wget https://xxxx.com/latest/install

chmod +x ./install

./install auto

service codedeploy-agent start

service codedeploy-agent status

#backto patpat-devops folder

cd /opt/patpat-devops

#download nginx1.14, not need single start

wget https://xxxx.com/nginx/nginx1.14.tar

tar -xf nginx1.14.tar

mv nginx /usr/local/programs/

#replace /etc/logrotate.d/nginx

\cp -f /usr/local/programs/nginx/logrotate.d/nginx /etc/logrotate.d/nginx

#copy supervisor.d/nginx.conf to supervisor

\cp -f /usr/local/programs/nginx/supervisor.d/nginx.conf /usr/local/programs/supervisor/conf.d/

rm nginx1.14.tar

#download php7,not need single start

wget https://xxxx.com/php/php7.tar

tar -xf php7.tar

mv php7 /usr/local/programs/

#copy supervisor.d/php-fpm.conf to supervisor

\cp -f /usr/local/programs/php7/etc/supervisor.d/php-fpm.conf /usr/local/programs/supervisor/conf.d/

rm php7.tar

#start supervisor,nginx,php,zabbix start server

isExistApp=`pgrep supervisor`

if [ -n  $isExistApp ]; then

    echo "supervisor is activing, will reload"

    #restart server

    /usr/local/bin/supervisorctl reload 

else

    echo "supervisor is not active, will start server"

    #start server

   /usr/local/bin/supervisord -c /usr/local/programs/supervisor/supervisord.conf     

fi

#change nginx log permession

chmod -R 777 /usr/local/programs/nginx/logs

echo "Install finished!"

备注:具体在创建实例的时候在"配置详细信息"选项卡里面进行添加

4)、创建Auto Scaling 组 (下图为已经创建好的Auto Scaling组)

Auto Scaling结合ELB使用

此时aws auto scaling创建完成,随后Auto Scaling会根据给定的按需实例设置启动一台EC2实例

AWS Code Deploy部分

1、CodeDeploy部署的前提条件

需要在Auto Scaling启动配置中的EC2启动模板事先安装好CodeDeploy agent代理 Install or reinstall the aws CodeDeploy agent for Amazon Ubuntu Server


$ sudo apt-get install ruby

$ sudo apt-get install wget

$ cd /home/ubuntu

$ wget https://bucket-name.s3.amazonaws.com/latest/install

$ chmod +x ./install

$ sudo ./install auto

$ sudo service codedeploy-agent status

$ sudo service codedeploy-agent start

$ sudo service codedeploy-agent status

备注:bucket-name 是包含适用于您所在区域的AWS CodeDeploy 资源工具包文件的 Amazon S3sds-s3-latest-bucket-name 存储桶的名称,对于美国东部(俄亥俄)区域,bucket-name 替换为 aws-codedeploy-us-east-2

2、Code Deploy组件

部署:部署一个包括应用程序和AppSpec文件的新修订;AppSpec指定如何将应用程序部署到部署组中的实例

应用程序:部署组和修订的集合;EC2/本地应用程序使用EC2/本地计算平台

修订版:修订版是可部署内容(如源代码、构建后项目、网页、可执行文件和部署脚本以及 AppSpec 文件)的特定版本,AWS CodeDeploy 代理程序可通过 GitHub 或 Amazon S3 存储桶访问修订版

部署组:部署组是用于在CodeDeploy部署中对EC2实例的AWS CodeDeploy实体;它是一组与您以之为目标进行部署的应用程序关联的实例;可以通过指定标签、Auto Scaling组名称或同时指定此二者,将实例添加到部署组中

备注:可以为一个应用程序定义多个部署组,如模拟和生产

部署配置:部署配置为部署组指定如何进行部署的行为,包括如何处理部署故障;可以使用部署配置向多实例部署组执行零停机部署;例如,如果您的应用程序需要部署组中至少有50% 的实例在运行中且提供流量,可以在您的部署配置中指定这一点,从而使部署不会导致停机;如果没有与部署或者部署组相关联的部署配置,则在默认情况下,AWS CodeDeploy将会一次部署到一个实例中

3、AWS CodeDeploy部署类型

就地部署

停止部署组中每个实例上的应用程序,安装最新的应用程序修订版,然后启动和验证应用程序的新版本;您可以使用负载均衡器,以便在部署期间取消注册每个实例,然后在部署完成后让其重新提供服务;只有使用EC2/本地计算平台的部署才能使用就地部署

对部署组中的实例依次执行脱机操作/更新应用/恢复联机的操作,完成滚动部署

蓝绿部署

创建一组新的替换实例,并安装新版本的应用程序。成功后,切换流量到这些新实例,删除旧实例,完成部署;AWS CodeDeploy 运行您在切换流量之前,对新版本应用程序进行测试;如果发现问题,您可以快速回滚到旧版本

EC2/本地计算平台上的蓝/绿部署:部署组中的实例(原始环境)将被不同的实例集(替代环境)所代替,步骤如下:

1)、系统将为替代环境配置实例

2)、替代实例上将安装最新的应用程序修订

3)、对于应用程序测试和系统验证等活动来说,等待时间可选

4)、替代环境中的实例在Elastic Load Balancing负载均衡器中进行注册,使得流量重新路由至这些实例;系统将撤销原始环境中的实例注册,进而终止或因其他使用情形而保持运行

备注:蓝/绿部署只能与Amazon EC2实例配合使用

4、就地部署概述

停止部署组中每个实例上的应用程序,安装最新的应用程序修订版,然后启动和验证应用程序的新版本。您可以使用负载均衡器,以便在部署期间取消注册每个实例,然后在部署完成后让其重新提供服务

1)、在本地开发计算机或类似环境上创建可部署的内容,然后添加application specification file (AppSpec file);AppSpec file对AWS CodeDeploy是唯一的;它定义了AWS CodeDeploy执行的部署操作;将可部署的内容和AppSpec file捆绑成一个存档文件,然后将其上传到Amazon S3存储桶或GitHub存储库;此存档文件称为应用程序修订(简称修订)

2)、向AWS CodeDeploy提供有关您的部署的信息,例如,要从中提取修订的Amazon S3存储桶或GitHub,以及要将其内容部署到的一组Amazon EC2实例;AWS CodeDeploy将一组Amazon EC2实例称为一个部署组,部署组中包含单独标记的Amazon EC2实例和/或Amazon EC2 Auto Scaling组中的Amazon EC2实例

每次您成功上传要部署到部署组的新应用程序修订时,该捆绑包就会设置为部署组的目标修订;也就是说,当前设为部署目标的应用程序修订为目标修订,这也是将为自动部署提取的修订

3)、每个实例上的CodeDeploy-Agent将轮询 AWS CodeDeploy,以确定从指定的Amazon S3存储桶或GitHub存储库中提取的内容和提取时间

4)、每个实例上的CodeDeploy-Agent将从指定的Amazon S3存储桶或GitHub存储库中提取目标修订,并按照 AppSpec file中的说明向实例部署内容

AWS CodeDeploy将保留您的部署的记录,以便您可以获取部署状态、部署配置参数、实例运行状况

5、蓝/绿部署概述

在蓝/绿部署中将流量从一组实例(原始环境)重新路由到另一组实例(替换环境),相比就地部署提供了多种优势:

1)、可以提前在新实例上安装和测试应用程序,并通过直接将流量切换到新服务器来将应用程序部署到生产中

2)、可以更快、更可靠地切换回最近的应用程序版本,因为只要原始实例没有终止,就可以将流量路由回原始实例;而在就地部署中,必须通过重新部署上一个版本的应用程序来回滚版本

3)、如果您使用EC2/本地计算平台,则会为蓝/绿部署预置新实例,并且新实例反映最新的服务器配置;这将帮助您避免在长时间运行的实例上有时出现的问题类型

wiki:https://docs.aws.amazon.com/zh_cn/codedeploy/latest/userguide/welcome.html#welcome-deployment-overview-in-place

6、AppSpec 文件

appspec.yml是YAML格式、用于定于CodeDeploy服务在整个阶段所做的操作和文件拷贝路径和权限等。这个文档名称必须是appspec.yml,而且文档中的空格个数也有严格的要求,参考详细解析 .

如果没有AppSpec file,AWS CodeDeploy无法将应用程序修订中的源文件映射到其目标,也无法为您向EC2/本地计算平台中进行的部署运行脚本

AppSpec 文件是一种配置文件,用于指定待复制文件和待执行脚本;AppSpec文件使用 YAML 格式,它位于您的修订版的根目录下;AppSpec文件为AWS CodeDeploy 代理程序所用,由两个部分组成;文件部分指定了您的版次中待复制的源文件,以及每个实例的目标文件夹;挂接部分指定了在部署各阶段运行的脚本的位置(作为从修订包根下起始的相对路径);部署的各阶段被称为部署生命周期事件;下面是一个示例 AppSpec文件

appspec.yml示例:

version: 0.0                                      # 固定写法

os: linux

files:                                                 # You can specify one or more mappings in the files section.

  - source: /

    destination: /var/www/html/WordPress

hooks:                                              # The lifecycle hooks sections allows you to specify deployment scripts.

ApplicationStop:                             # Step 1: Stop Apache and MySQL if running.

    - location: helper_scripts/stop_server.sh

BeforeInstall:                                  # Step 2: Install Apache and MySQL.

# You can specify one or more scripts per deployment lifecycle event.

    - location: deploy_hooks/puppet-apply-apache.sh

    - location: deploy_hooks/puppet-apply-mysql.sh

AfterInstall:

    - location: deploy_hooks /change_permissions.sh              # Step 3: Set permissions.

      timeout: 30

      runas: root

    - location: helper_scripts/start_server.sh                             # Step 4: Start the server.

      timeout: 30

      runas: root

appspec.yml生产环境示例:

version: 0.0                                        # AppSpec file的版本;允许的唯一值为0.0

os: linux                                             # 指定部署到的实例的操作系统值(linux、windows)

files:                                                   # 定义文件映射关系

  - source: /                                        # 表示本版本包的全部文件和目录(相对路径,从修订的根目录开始)

    destination: /var/www/alpha-website_desktop/       # 被部署服务器的完整路径

hooks:                                               # 定义CodeDeploy各阶段执行的操作

  BeforeInstall:                                  # CodeDeploy部署之前

    - location: codedeploy-scripts/install_dependencies    # 运行的软件包依赖脚本

      timeout: 300                               # 安装超时时间

      runas: root                                 # 以什么用户进行软件安装

  AfterInstall:                                    # CodeDeploy部署之后

    - location: codedeploy-scripts/change_applications_configure

    - location: codedeploy-scripts/change_permissions

      timeout: 300

      runas: root

  ApplicationStart:                           # 应用启动

    - location: codedeploy-scripts/start_server

      timeout: 300

      runas: root

  ApplicationStop:                           # 应用停止

    - location: codedeploy-scripts/stop_server

      timeout: 300

      runas: root

appspec.yml部署生命周期:

部署生命周期说明

部署会经过一组预定义阶段,称为部署生命周期事件。部署生命周期事件可让您将代码作为部署的一部分运行

下表以执行顺序列出了目前支持的各种不同的部署生命周期事件,以及您可能想使用它们的时间示例

In-place deployments(就地部署)

Blue/green deployments(蓝绿部署生命周期)

蓝绿部署流量切换过程

CodeDeploy部署方式:

CodeDeploy与AutoScaling集成原理 https://aws.amazon.com/cn/blogs/devops/under-the-hood-aws-codedeploy-and-auto-scaling-integration/

使用Auto Scaling配置CodeDeploy

使用Auto Scaling配置CodeDeploy非常简单。只需转到AWS CodeDeploy控制台,然后在部署组配置中指定Auto Scaling组名称

此外,还需要:

1、在Auto Scaling实例上安装CodeDeploy代理。您可以将代理程序作为基本AMI的一部分进行烘焙,也可以在启动期间使用用户数据来安装代理程序

2、确保CodeDeploy用于与Auto Scaling交互的服务角色具有正确的权限

Auto Scaling Lifecycle Hook

事件中的Auto Scaling和CodeDeploy之间的通信基于Auto Scaling生命周期挂钩;建议不要尝试手动设置或修改这些挂钩,因为CodeDeploy可以为您执行此操作;Auto Scaling生命周期挂钩告诉Auto Scaling在实例即将更改为某些Auto Scaling生命周期状态时发送通知;CodeDeploy仅侦听有关已启动且即将放入InService的实例的通知;此状态发生在EC2实例完成引导之后,但在它被放置到您已配置的任何Elastic Load Balancing负载平衡器之后;Auto Scaling在继续处理实例之前等待CodeDeploy的成功响应

挂钩是Auto Scaling组配置的一部分;您可以使用describe-lifecycle-hooks CLI命令查看Auto Scaling组上安装的挂钩列表;创建或修改部署组以包含Auto Scaling组时,CodeDeploy将执行以下操作:

1)、使用传入的CodeDeploy服务角色与部署组一起使用以获取Auto Scaling组的权限

2)、在Auto Scaling组中安装生命周期挂钩,用于实例启动,将通知发送到CodeDeploy拥有的队列

3)、将已安装的挂钩的记录添加到部署组

从部署组中删除Auto Scaling组或删除部署组时,CodeDeploy将执行以下操作:

1)、使用部署组的服务角色来访问Auto Scaling组

2)、获取部署组中记录的挂钩,并将其从Auto Scaling挂钩中删除

3)、如果正在修改(未删除)部署组,请从部署组中删除该挂钩的记录

如果创建钩子有问题,CodeDeploy将尝试回滚更改;如果删除钩子有问题,CodeDeploy将在API响应中返回不成功的钩子删除并继续

以下是Auto Scaling scale-in事件期间发生的事件序列:

1、Auto Scaling要求EC2提供新实例

2、EC2使用Auto Scaling提供的配置旋转新实例

3、Auto Scaling查看新实例,将其置于Pending:Wait状态,并将通知发送到Code Deploy

4、CodeDeploy从Auto Scaling接收实例启动通知

5、CodeDeploy验证实例和部署组的配置

1)、如果通知看起来正确,但部署组不再包含Auto Scaling组(或者我们可以确定先前已删除部署组),则CodeDeploy将不会部署任何内容,并通过实例启动将Auto Scaling告知CONTINUE;Auto Scaling将尊重实例启动时的任何其他约束; 如果出现其他问题,此步骤不会强制Auto Scaling继续

2)、如果CodeDeploy无法处理消息(例如,如果存储的服务角色未授予适当的权限),则CodeDeploy将使挂钩超时;CodeDeploy的默认超时为10分钟

6、CodeDeploy为实例创建新部署以部署部署组的目标修订;(目标修订版是部署组的最后一个成功部署的修订版;它由CodeDeploy维护);您需要至少部署到部署组一次,以便CodeDeploy识别目标修订版;您可以使用get-deployment-group CLI命令或CodeDeploy控制台获取部署组的目标修订

1)、部署正在运行时,它会将心跳发送到Auto Scaling,让它知道该实例仍在处理中

2)、如果部署出现问题,CodeDeploy将立即告知Auto Scaling ABANDON实例启动。Auto Scaling终止实例并使用新实例重新启动该过程

最佳实践 1)、设置或修改Auto Scaling生命周期挂钩 -不要手动设置或修改Auto Scaling挂钩,因为配置错误可能会破坏CodeDeploy集成(备注:在CodeDeploy中配置添加AutoScaling组,生命周期挂钩就已经建立)

2)、注意部署失败 - 当部署到新实例失败时,CodeDeploy会将实例标记为终止;Auto Scaling将终止实例,启动新实例,并通知CodeDeploy以启动部署;当你有暂时的错误时,这很好。但是,缺点是如果您的目标修订版存在问题(例如,如果部署脚本中存在错误),则启动和终止实例的此循环可以进入循环;我们建议您密切监视部署并设置Auto Scaling 通知,以跟踪Auto Scaling启动和终止的EC2实例

3)、Auto Scaling部署疑难解答-对涉及Auto Scaling组的部署进行故障排除可能具有挑战性;如果部署失败,我们建议您取消Auto Scaling组与部署组的关联,以防止Auto Scaling不断启动和终止EC2实例。接下来,将使用相同基本AMI启动的标记EC2实例添加到部署组,将目标修订部署到该EC2实例,并使用该实例对脚本进行故障排除。如果您有信心,请将部署组与Auto Scaling组关联,将黄金版本部署到Auto Scaling组,扩展新的EC2实例(通过调整Min,Max和Desired()),并验证部署是否成功

4)、订购启动脚本的执行 - CodeDeploy代理在启动时立即查找并执行部署;部署执行和启动脚本(如用户数据,cfn-init等)之间没有排序;我们建议您将启动脚本作为启动脚本的一部分(也可能是最后一步)安装,以便您可以确定在实例安装了不属于CodeDeploy部署的依赖项之前,不会执行部署;如果您希望将代理程序烘焙到基本AMI中,我们建议您将代理程序服务保持在停止状态,并使用启动脚本启动代理程序服务

5)、将多个部署组与同一Auto Scaling组关联 - 通常,应避免将多个部署组与同一Auto Scaling组关联;当Auto Scaling使用与多个部署组关联的多个挂钩扩展实例时,它会同时发送所有挂钩的通知;因此,将创建多个CodeDeploy部署;这有几个缺点。这些部署是并行执行的,因此您将无法依赖它们之间的任何顺序;如果任何部署失败,Auto Scaling将立即终止实例;当实例关闭时,正在运行的其他部署将开始失败,但它们可能需要一个小时才能完成;Host Agent一次只处理一个部署命令,因此您还需要考虑两个限制;第一,其中一个部署可能会因为时间过长而失败;例如,如果部署中的步骤需要五分钟以上才能完成,则可能会发生这种情况;其次,部署之间没有先发制人,因此无法在一个部署与另一个部署之间强制执行步骤排序;因此,我们建议您最小化与Auto Scaling组关联的部署组的数量,并将部署合并到单个部署中

Jenkins+Git+CodeDeploy持续集成

参考官方教程: https://aws.amazon.com/cn/blogs/china/aws-devops-jenkins-and-codedeploy/

需要Jenkins安装codedeploy插件,插件截图:

Jenkins关于项目配置目录规则

project-configure/

├── geodata

│   └── geoip.mmdb

├── xxxx                                                                               # 公司名称

│   ├── alpha                                                                           # alpha环境

│   │   ├── xxxx-alpha-website_api                                    # 具体的项目名称

│   │   │   ├── codedeploy                                                      # CodeDeploy目录存放codedeploy必须的appspec.yml和脚本文件夹

│   │   │   │   ├── appspec.yml                                               # 用于定义CodeDeploy服务在整个阶段做的操作和文件拷贝路径和权限等

│   │   │   │   └── codedeploy-scripts                                   # CodeDeploy中脚本执行所在文件夹

│   │   │   │       ├── change_applications_configure          # CodeDeploy部署完成后,配置文件拷贝,服务重启操作

│   │   │   │       ├── change_permissions                            # codedeploy部署完成后,相关目录权限变更等设置

│   │   │   │       ├── install_dependencies                           # codedeploy部署前系统软件包依赖关系安装

│   │   │   │       ├── start_server                                           # 启动服务脚本

│   │   │   │       └── stop_server                                           # 停止服务脚本

│   │   │   ├── project-conf.d                                                # 项目中的.env配置文件目录

│   │   │   └── server-applications                                       # 软件(nginx,php)应用程序配置文件存放文件夹

│   │   │       └── nginx

│   │   │           └── conf.d

│   │   │               └── xxxx-alpha-website_api.conf            

│   ├── production                                                                # 线上生产环境

│   │   ├── xxxx-api

│   │   │   ├── codedeploy

│   │   │   │   ├── appspec.yml

│   │   │   │   └── codedeploy-scripts

│   │   │   │       ├── change_applications_configure

│   │   │   │       ├── change_permissions

│   │   │   │       ├── install_dependencies

│   │   │   │       ├── start_server

│   │   │   │       └── stop_server

│   │   │   ├── project-conf.d

│   │   │   └── server-applications

│   │   │       └── aws-kinesis-agent

│   │   │           └── agent.json

│   └── test                                                                           # 测试环境

└── README                                                                       # CodeDeploy目录说明

相关目录说明:

目录层级:

平台/环境/项目

目前只有patpat和ace平台,环境有production、test、alpha

项目目录包含项目配置,codedeploy配置,服务器端配置,每个项目配置下面分别有下面三个目录:

codedeploy/

project-conf.d/

server-applications/

说明:

  1. codedeploy目录存放codedeploy必须的appspec.yml和scripts脚本文件

  2. project-conf.d目录存放项目参数配置文件,例如.env

  3. server-applications目录存放目标服务器上的nginx,php,kinesis-agent等应用程序配置,需要结合上面的codedeploy使用

务必严格按照此格式配置,每次修改配置后需要重新在jenkins上构建发布!

AWS codedeploy采取蓝绿部署,无状态部署,所以每次修改配置后需要重新构建启动新机器

构建截图

Jenkins与codedeploy结合部署文件上传至指定的S3存储桶

发布流程

Jenkins主要实现将构建好的部署包上传至s3存储桶,事先在EC2实例上的CodeDeploy-Agent在轮询过程中发现s3存储桶上有新的修订版(jenkins部署上传到S3的压缩包)时,获取存储桶的新的修订版并解压,CodeDeploy根据新的修订版里的appspec.yml对EC2实例进行自动部署,这样保证每次在同一个CodeDeploy组内的实例获取的都是最新的部署包.