亚马逊AWS官方博客

用无服务器应用模型部署无服务器应用 (二)使用无服务器应用模型的持续集成

作者:薛峰

上一篇文章中我们介绍了AWS 无服务器应用模型和SAM模板的基本功能和特性,并带领大家用一个实例体验了通过CloudFormation部署SAM模板。在这一篇中,我们仍然结合实例讲解,为大家继续介绍使用AWS CodeBuild 构建 Lambda函数以及使用AWS CodePipeline实现自动化持续集成。

部署配置AWS CodeBuild

如果我们的Lambda函数使用了依赖库时,我们可以通过AWS CodeBuild来把依赖库编译进Lambda函数的部署包里。

AWS CodeBuild  是一个完全托管的构建服务,可用于编写源代码、运行测试并生成可立即部署的软件包。CodeBuild基于AWS管理的容器,从而实现用户无需配置、管理和扩展自己的构建服务器。CodeBuild 可持续缩放和并行处理多个生成任务,因此构建任务不必在队列中等待。使用CodeBuild,我们只需要按构建时使用计算资源的分钟数付费,从而无需为预置的构建服务器的空闲时间付费。

除了常见的Java之类的程序源码的构建,CodeBuild还可用于Lambda函数部署前的构建。下面我们用一个例子来具体说明。

请先从以下git库下载源码。

https://github.com/xfsnow/serverless/tree/master/sam/codebuild

这个例子中的Lambda函数需要Node.js 依赖库 time,我们使用CodeBuild在构建时安装这个这个time库,把它加入到 Lambda 函数的包中。

index.js 文件中以下这行,表示需要依赖库 time。

var time = require('time');

buildspec.yml 中

install:

    commands:

      - npm install time

表示在构建的安装步骤把 time 库安装进来。

  build:

    commands:

      - aws cloudformation package --template-file codebuild.yaml --s3-bucket <bucket-name> --output-template-file output_codebuild.yaml

这段其实就是使用在上一章节我们介绍过的aws cloudformation package 打包。

上传源文件

把buildspec.yml文件中的 <bucket-name> 等变量值替换成你的具体的值。

在当前目录下除了 md 文件的其它文件打包成 codebuild.zip,然后把这个 zip 文件上传你自己的 S3桶中。

配置 CodeBuild 项目

打开 CodeBuild 控制台

点击 Create project。

在 Configure your project 页

Project name 输入 serverlessCodebuild

Source provider 选择 Amazon S3

Bucket 栏选择我们的刚才上传 zip 文件的 S3 桶名称

S3 object key 输入 codebuild.zip。

Environment image 保持选择 Use an image managed by AWS CodeBuild

Operating system 选择 Ubuntu

Runtime 选 Node.js

Version 选择 aws/codebuild/nodejs:4.3.2

Artifacts type 选 Amazon S3

Bucket name 还选择我们的刚才上传 zip 文件的 S3 桶名称

确认 Create a service role in your account 已选中

Role name 输入 serverlessCodebuild

点击右下角 Continue 按钮

在 Review 页点击右下方的 Save and build 按钮。

创建成功后前进到 Build projects 列表页,此时刚刚新建的项目应该是选中的状态。点击左上角 Start build 按钮。

在 Start new build 页,直接点击右下角 Start build 按钮。

在 Build 页可以查看构建进行的进度信息。注意看 Phase details 下面的输出内容。 构建成功完成以后,可以到我们的 S3 桶中查看结果,可以看到创建出一个 serverlessCodebuild 目录,里面就是构建的成果—— output_codebuild.yaml 文件。我们把它下载到本地,就可以用它再执行 CloudFormation 部署。

使用 CloudFormation 部署

执行以下命令

aws cloudformation deploy \

   --template-file output_codebuild.yaml \

   --stack-name serverlessCodebuild \

   --capabilities CAPABILITY_IAM

顺利地话,会看到逐渐输出的返回结果

Waiting for changeset to be created..


Waiting for stack create/update to complete

Successfully created/updated stack - serverlessCodebuild

这时到 CloudFormation 的控制台已经创建出一个 serverlessCodebuild ,整个过程大约持续 1 到 2 分钟。

然后到 API Gateway 控制台,可以看到创建出的 serverlessCodebuild 的 API,点击其 Stages 下的 Prod 链接,可以看到形如下面的调用 URL: Invoke URL: https://xxxxxxxxx.execute-api.my-region.amazonaws.com/Prod

点击它,打开一个新窗口,显示

“The time in Los Angeles is Mon Aug 07 2017 03:32:42 GMT-0700 (PDT)”
表示已经部署成功。

部署配置AWS CodePipeline

每次都要手工执行aws cloudformation deploy命令来部署仍然有些繁琐,而且手工部署难免会有人工的失误。下面我们使用AWS CodePipeline来最终实现完全自动化的部署。

AWS CodePipeline 是一个托管的持续集成与持续交付服务,可以实现快速而可靠的应用程序和基础设施更新。每次更改代码时,CodePipeline 都会根据我们定义的发布流程模型构建、测试和部署代码,就像管道一样逐个步骤的执行流程中的每一步操作,还支持可选的人工审核步骤。和CodeBuild一样, CodePipeline也是只按实际使用量付费,同样无需为预置的资源空闲付费。

我们下面这个例子,Lambda函数还是使用了time依赖库,仍然使用CodeBuild安装依赖库、CloudFormation进行部署,这次我们配置CodePipeline来完成构建和部署的全部流程,实现持续集成。

总的操作流程主要是以下几步:

  1. 在 github 上创建一个库存放源文件。
  2. 创建一个 CodeBuild 项目,用于构建无服务器应用。
  3. 创建一个 IAM 角色,用于 CloudFormation 部署无服务器应用。
  4. 创建一个 CodePipeline 项目,把上述若干步骤和资源组建成管道。

在 github 上创建一个库存放源文件

请在你自己的github新建一个存储库,名为 serverlessCodepipepline。

从以下git库下载源码。

https://github.com/xfsnow/serverless/blob/master/sam/codepipeline

放在我们自已的 serverlessCodepipepline 库的根目录下。

把 buildspec.yml 中的 <bucket> 更新成自己的桶名称,再 commit 到 git 库中。

配置 CodeBuild 项目

  • 打开 CodeBuild 控制台,点击 Create project。

在 Configure your project 页

Project name 输入 serverlessCodepipeline

Source provider 选择 Github

Repository 选择 Use a repository in my account

Repository URL 输入我们自己的库的路径,比如 https://github.com/xfsnow/serverlessCodepipepline

  • Environment image 保持选择 Use an image managed by AWS CodeBuild

Operating system 选择 Ubuntu

Runtime 选 Node.js

Version 选择 aws/codebuild/nodejs:4.3.2

Build specification 保持选中 Use the buildspec.yml in the source code root directory

Artifacts type 选 Amazon S3

Bucket name 还选择我们在 buildspec.yml 中指定的 S3 桶名称

确认 Create a service role in your account 已选中

Role name 输入 serverlessCodebuild,点击右下角 Continue 按钮。

  • 在 Review 页点击右下方的 Save and build 按钮。

创建成功后前进到 Build projects 列表页,此时刚刚新建的项目应该是选中的状态。点击左上角 Start build 按钮。

在 Start new build 页,直接点击右下角 Start build 按钮。

  • 在 Build 页可以查看构建进行的进度信息。注意看 Phase details 下面的输出内容。

构建成功完成以后,可以到我们的 S3 桶中查看结果,可以看到创建出一个 serverlessCodepipeline 目录,里面就是构建的成果—— output-codepipeline.yaml 文件。

我们可以把它下载到本地看一下,后续我们继续配置 CodePipeline 就是用它来做无服务器资源的部署。

配置 IAM 角色

登录 AWS 管理控制台。点击左侧导航链接中的 Roles,点击 Create new role 按钮。

  • 在 Select role type 页选择 AWS Service Role,找到 AWS Cloudformation Role 点击其右边的 Select 按钮。
  • 在 Attach Policy 页,选择 AWSLambdaExecute。点击 Next Step 按钮。
  • 在 Set role name and review 页, Role name 输入 cloudformation-lambda-execution,然后点击 Create role 按钮。
  • 打开刚才创建的角色,在 Permissions 选项卡下,点击 Inline Policies 展开之,然后选择 click here 链接。

选择 Custom Policy,然后选择 Select。

在 Policy Name 中,输入 cloudformation-deploy-lambda ,然后将以下内容中的 region account_id 替换成你自己的值,粘贴到 Policy Document 字段中:

{

    "Statement": [

        {

            "Action": [

                "s3:GetObject",

                "s3:GetObjectVersion",

                "s3:GetBucketVersioning"

            ],

            "Resource": "*",

            "Effect": "Allow"

        },

        {

            "Action": [

                "s3:PutObject"

            ],

            "Resource": [

                "arn:aws:s3:::codepipeline*"

            ],

            "Effect": "Allow"

        },

        {

            "Action": [

                "lambda:*"

            ],

            "Resource": [

                "arn:aws:lambda:region:account-id:function:*"

            ],

            "Effect": "Allow"

        },

        {

            "Action": [

                "apigateway:*"

            ],

            "Resource": [

                "arn:aws:apigateway:region::*"

            ],

            "Effect": "Allow"

        },

        {

            "Action": [

                "iam:GetRole",

                "iam:CreateRole",

                "iam:DeleteRole"

            ],

            "Resource": [

                "arn:aws:iam::account-id:role/*"

            ],

            "Effect": "Allow"

        },

        {

            "Action": [

                "iam:AttachRolePolicy",

                "iam:DetachRolePolicy"

            ],

            "Resource": [

                "arn:aws:iam::account-id:role/*"

            ],

            "Effect": "Allow"

        },

        {

            "Action": [

                "iam:PassRole"

            ],

            "Resource": [

                "*"

            ],

            "Effect": "Allow"

        },

        {

            "Action": [

                "cloudformation:CreateChangeSet"

            ],

            "Resource": [

                "arn:aws:cloudformation:region:aws:transform/Serverless-2016-10-31"

            ],

            "Effect": "Allow"

        }

    ],

    "Version": "2012-10-17"

}    

点击 Validate Policy,然后点击 Apply Policy。

配置 CodePipeline 项目
打开 CodePipeline 控制台,点击 Create project。

  • 在 Step 1: Name 页

Project name 输入 serverlessCodepipeline,点击“Next Step” 按钮。

  • 在 Step 2: Source 页

Source provider 选择 Github,然后点击 Connect to GitHub 按钮,关联 GitHub 账号。按提示完成关联操作。

回到 AWS 页面后,Repository 选择前述我们自己创建的存储库。

Branch 选择 master ,点击“Next Step” 按钮。

  • 在 Step 3: Build 页

Build provider 选择 AWS CodeBuild

Configure your project 保持选中 Select an existing build project。

Project name 在下拉列表中选择我们前面创建的 serverlessCodepipeline 项目。

  •  在 Step 4: Deploy 页

Deployment provider 选择 AWS CloudFormation。

Action mode 选择 Create or replace a change set。

Stack name 输入 serverlessCodepipeline。

Change set name 输入 serverlessCodepipelineChangeSet。

Template file 输入 buildspec.yml 中指定的构建结果文件名 output-codepipeline.yaml。

Capabilities 选择 CAPABILITY_IAM。

Role name 选择我们前面创建的 IAM 角色 cloudformation-lambda-execution。 点击 Next Step 按钮。

  • 在 Step 5: Service Role 页

点击 Create Role 按钮,在弹出的 IAM AWS CodePipeline is requesting permission to use resources in your account 页面,直接点击右下角 Allow 按钮,返回后点击 Next Step 按钮。

  • 在 Step 6: Review 页面,直接点击右下角 点击右下角的 Create Pipeline 按钮。最后来到 serverlessCodepipeline 项目详情页。
  • 增加测试部署阶段 在 serverlessCodepipeline 详情页点击 Edit 按钮。

在 Staging 阶段下面点击 +Stage 链接。

在 Stage name 栏输入 Beta,然后点击其下面的 +Action 按钮。

在 Action category 中,选择Deploy。

在 Action name 中,输入 executeChangeSet。

在 Deployment provider 中,选择 AWS CloudFormation。

在 Action mode: 中,选择 execute a changeset。前一步我们已经创建了 ChangeSet,将 SAM 模板转换为完整的 AWS CloudFormation 格式,现在我们要使用 deployChangeSet 部署 AWS CloudFormation 模板了。

在 Stack name:中,输入 serverlessCodepipeline。

在 Change set name:中,输入 serverlessCodepipelineChangeSet。

选择 Add Action。

回到页面顶部点击 Save pipeline changes。

选择 Save and continue。

查看结果

我们在 serverlessCodepipeline 项目详情页稍等10秒左右,Pipeline 会自动开始第一次部署。可以随时查看到各个步骤的执行情况,比如:

Source
GitHub
Succeeded 2 min ago
d24ff81
最后等到 Beta 步骤也完成,这时到 CloudFormation 的控制台查看已经创建出一个 serverlessCodepipeline ,整个过程大约持续 3到5 分钟。

然后到 API Gateway 控制台,可以看到创建出的 serverlessCodepipeline 的 API,点击其 Stages 下的 Prod 链接,可以看到形如下面的调用 URL: Invoke URL: https://xxxxxxxxx.execute-api.my-region.amazonaws.com/Prod

复制此 URL,打开一个新窗口,粘贴进地址栏,然后在后面再输入 /time,组成形如

https://xxxxxxxxx.execute-api.my-region.amazonaws.com/Prod/time

的链接再访问之,显示

“The time in Los Angeles is Mon Aug 07 2017 03:31:39 GMT-0700 (PDT)”
表示已经部署成功。

然后我们模拟代码更新,把你自己的 github 存储库中的 README.md 文件编辑一下,然后 git commit 到 github 上去。 然后再回到 serverlessCodepipeline 详情页,稍等一会我们会看到从 Source 开始整个管道会再次执行一遍。

执行到每一步时,我们都可以点击 Detail 链接到相关服务的详情页查看具体进度。比如 CloudFormation 会创建出一个新的 serverlessCodepipelineChangeSet 来执行变更。

最后到 API Gateway 的 serverlessCodepipeline API,选择一个 Stage ,再点选 Deployment History 可以看到 Deployment date时间更新了。

小结

今天我们继续结合实例,为大家讲解了使用AWS CodeBuild 构建 Lambda函数以及使用AWS CodePipeline实现自动化持续集成。这些也是基于AWS 无服务器应用模型和SAM模板,再与其它AWS运维的服务集成,共同实现无服务器应用的自动化运维。

相关资源链接

Serverless Application Model (SAM):
https://github.com/awslabs/serverless-application-model

无服务器服务官网:

AWS Lambda: https://aws.amazon.com/lambda

Amazon API Gateway: https://aws.amazon.com/api-gateway

运维相关的服务:

CloudFormation: https://aws.amazon.com/cloudformation

CodeBuild: https://aws.amaz.com/codebuild

CodePipeline: https://aws.amazon.com/codepipeline

 

作者介绍:

薛峰,亚马逊AWS解决方案架构师,AWS的云计算方案架构的咨询和设计,同时致力于AWS云服务在国内和全球的应用和推广,在大规模并发应用架构、移动应用以及无服务器架构等方面有丰富的实践经验。在加入AWS之前曾长期从事互联网应用开发,先后在新浪、唯品会等公司担任架构师、技术总监等职位。对跨平台多终端的互联网应用架构和方案有深入的研究。