AppSpec “钩子” 部分 - Amazon CodeDeploy
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

AppSpec “钩子” 部分

AppSpec 文件'hooks'部分中的内容因部署的计算平台而异。EC2/本地部署'hooks'部分包含将部署生命周期事件挂钩链接到一个或多个脚本的映射。有关 Lambda 或 Amazon ECS 部署的'hooks'部分指定了在部署生命周期事件期间运行的 Lambda 验证函数。如果某个事件的挂钩不存在,则不会对该事件执行任何操作。只有在部署过程中运行脚本或 Lambda 验证函数时,才需要此部分。

AppSpec 亚马逊 ECS 部署的 “挂钩” 部分

Amazon ECS 部署的生命周期事件挂钩列表

AmazonLambda 挂接是一个 Lambda 函数,在生命周期事件名称后的新行中使用字符串指定。对于每次部署,每个挂钩将执行一次。以下是生命周期事件的描述,您可以在 Amazon ECS 部署期间运行挂钩。

  • BeforeInstall-用于在创建替换任务集之前运行任务。一个目标组与原始任务集相关联。如果指定了可选的测试侦听器,则它与原始任务集相关联。此时,无法执行回滚。

  • AfterInstall-用于在创建替换任务集并且其中一个目标组与之关联后运行任务。如果指定了可选的测试侦听器,则它与原始任务集相关联。在此生命周期事件时挂钩函数的运行结果可能会触发回滚。

  • AfterAllowTestTraffic-用于在测试侦听器为替换任务集提供流量后运行任务集提供流量后运行任务。此时挂钩函数的运行结果可能会触发回滚。

  • BeforeAllowTraffic-用于在第二个目标组与替换任务集关联之后但在流量转移到替换任务集之前运行任务。在此生命周期事件时挂钩函数的运行结果可能会触发回滚。

  • AfterAllowTraffic— 用于在第二个目标组为替换任务集提供流量后运行任务集的流量。在此生命周期事件时挂钩函数的运行结果可能会触发回滚。

有关更多信息,请参阅 Amazon ECS 部署期间会发生什么教程:通过验证测试部署 Amazon ECS 服务

在 Amazon ECS 部署中运行挂钩顺序

在 Amazon ECS 部署中,事件挂钩按以下顺序运行:

注意

部署中的 “开始TestTrafficAllowTraffic、“安装” 和 “结束” 事件无法编写脚本,这就是它们在此图中以灰色显示的原因。

“钩子” 部分的结构

以下示例说明了 'hooks' 部分的结构。

使用 YAML:

Hooks: - BeforeInstall: "BeforeInstallHookFunctionName" - AfterInstall: "AfterInstallHookFunctionName" - AfterAllowTestTraffic: "AfterAllowTestTrafficHookFunctionName" - BeforeAllowTraffic: "BeforeAllowTrafficHookFunctionName" - AfterAllowTraffic: "AfterAllowTrafficHookFunctionName"

使用 JSON:

"Hooks": [ { "BeforeInstall": "BeforeInstallHookFunctionName" }, { "AfterInstall": "AfterInstallHookFunctionName" }, { "AfterAllowTestTraffic": "AfterAllowTestTrafficHookFunctionName" }, { "BeforeAllowTraffic": "BeforeAllowTrafficHookFunctionName" }, { "AfterAllowTraffic": "AfterAllowTrafficHookFunctionName" } ] }

示例 Lambda “挂钩” 函数

使用'hooks'部分指定 Lambda 函数,该函数 CodeDeploy 可以调用的用于验证 Amazon ECS 部署的 Lambda 函数。对于 BeforeInstallAfterInstallAfterAllowTestTrafficBeforeAllowTrafficAfterAllowTraffic 部署生命周期事件,您可以使用相同函数或不同函数。验证测试完成后,LambdaAfterAllowTraffic 函数会回调 CodeDeploy 并提供Succeeded或结果Failed

重要

如果 Lambda 验证函数 CodeDeploy 未在一小时内发出通知,则认为部署已失败。

在调用 Lambda 挂接函数之前,必须使用putLifecycleEventHookExecutionStatus命令将部署 ID 和生命周期事件挂接执行 ID 通知服务器。

以下是用 Node.js 编写的 Lambda 挂接函数示例。

'use strict'; const aws = require('aws-sdk'); const codedeploy = new aws.CodeDeploy({apiVersion: '2014-10-06'}); exports.handler = (event, context, callback) => { //Read the DeploymentId from the event payload. var deploymentId = event.DeploymentId; //Read the LifecycleEventHookExecutionId from the event payload var lifecycleEventHookExecutionId = event.LifecycleEventHookExecutionId; /* Enter validation tests here. */ // Prepare the validation test results with the deploymentId and // the lifecycleEventHookExecutionId for CodeDeploy. var params = { deploymentId: deploymentId, lifecycleEventHookExecutionId: lifecycleEventHookExecutionId, status: 'Succeeded' // status can be 'Succeeded' or 'Failed' }; // Pass CodeDeploy the prepared validation test results. codedeploy.putLifecycleEventHookExecutionStatus(params, function(err, data) { if (err) { // Validation failed. callback('Validation test failed'); } else { // Validation succeeded. callback(null, 'Validation test succeeded'); } }); };

AppSpec AmazonLambda 部署的 “挂钩” 部分

AmazonLambda 部署的生命周期事件挂钩列表

AmazonLambda 挂接是一个 Lambda 函数,在生命周期事件名称后的新行中使用字符串指定。对于每次部署,每个挂钩将执行一次。以下是可在您的 AppSpec 文件中使用的挂钩的描述。

  • BeforeAllowTraffic— 用于在流量转移到已部署的 Lambda 函数版本之前运行任务。

  • AfterAllowTraffic— 用于在所有流量转移到已部署的 Lambda 函数版本后运行任务。

在 Lambda 函数版本部署中挂钩的运行顺序

在无服务器 Lambda 函数版本部署中,事件挂钩按以下顺序运行:

注意

部署中的 Start AllowTraffic、En d 和 End 事件无法编写脚本,这就是它们在此图中以灰色显示的原因。

“钩子” 部分的结构

以下示例说明了“hooks”部分的结构。

使用 YAML:

hooks: - BeforeAllowTraffic: BeforeAllowTrafficHookFunctionName - AfterAllowTraffic: AfterAllowTrafficHookFunctionName

使用 JSON:

"hooks": [{ "BeforeAllowTraffic": "BeforeAllowTrafficHookFunctionName" }, { "AfterAllowTraffic": "AfterAllowTrafficHookFunctionName" }]

示例 Lambda “挂钩” 函数

使用 “钩指定 CodeDeploy 可以调用的用于验证 Lambda 部署的 Lambda 函数。对于 BeforeAllowTrafficAfterAllowTraffic 部署生命周期事件,您可以使用相同函数或不同函数。验证测试完成后,Lambda 验证函数会回调 CodeDeploy 并提供Succeeded或结果Failed

重要

如果 Lambda 验证函数 CodeDeploy 未在一小时内发出通知,则认为部署已失败。

在调用 Lambda 挂接函数之前,必须使用putLifecycleEventHookExecutionStatus命令将部署 ID 和生命周期事件挂接执行 ID 通知服务器。

以下是用 Node.js 编写的 Lambda 挂接函数示例。

'use strict'; const aws = require('aws-sdk'); const codedeploy = new aws.CodeDeploy({apiVersion: '2014-10-06'}); exports.handler = (event, context, callback) => { //Read the DeploymentId from the event payload. var deploymentId = event.DeploymentId; //Read the LifecycleEventHookExecutionId from the event payload var lifecycleEventHookExecutionId = event.LifecycleEventHookExecutionId; /* Enter validation tests here. */ // Prepare the validation test results with the deploymentId and // the lifecycleEventHookExecutionId for CodeDeploy. var params = { deploymentId: deploymentId, lifecycleEventHookExecutionId: lifecycleEventHookExecutionId, status: 'Succeeded' // status can be 'Succeeded' or 'Failed' }; // Pass CodeDeploy the prepared validation test results. codedeploy.putLifecycleEventHookExecutionStatus(params, function(err, data) { if (err) { // Validation failed. callback('Validation test failed'); } else { // Validation succeeded. callback(null, 'Validation test succeeded'); } }); };

AppSpec EC2/本地部署

生命周期事件挂钩列表

每次部署到实例时,EC2/本地部署挂接都会执行一次。在一个挂钩中,可以指定运行一个或多个脚本。生命周期事件的每个挂钩在单独的行中使用字符串指定。以下是可在您的 AppSpec 文件中使用的挂钩的描述。

有关哪些生命周期事件挂钩对哪些部署和回滚类型有效的信息,请参阅Lifecycle event hook availability

  • ApplicationStop— 此部署生命周期事件甚至在下载应用程序修订版之前发生。您可以为此事件指定脚本,以便从容地停止应用程序或在部署准备过程中删除当前已安装的软件包。用于此部署生命周期事件 AppSpec 的文件和脚本来自先前成功部署的应用程序版本。

    注意

    在将 AppSpec 文件部署到实例之前,该实例上不存在该文件。因此,ApplicationStop 挂钩在您首次部署到实例时不会运行。您可以在第二次部署到实例时使用 ApplicationStop 挂钩。

    要确定上次成功部署的应用程序修订版的位置, CodeDeploy 代理会查找deployment-group-id_last_successful_install文件中列出的位置。此文件位于:

    /opt/codedeploy-agent/deployment-root/deployment-instructionsAmazon Linux、Ubuntu 服务器和 RHEL Amazon EC2 实例上的文件夹。

    C:\ProgramData\Amazon\CodeDeploy\deployment-instructionsWindows 服务器的 Amazon EC2 实例上的文件夹。

    要对在 ApplicationStop 部署生命周期事件期间失败的部署进行故障排除,请参阅 对失败 ApplicationStop或 AfterBlockTraffic 部署生命周期事件进行故障排除 BeforeBlockTraffic

  • DownloadBundle— 在此部署生命周期事件中, CodeDeploy 代理将应用程序修订文件复制到临时位置:

    /opt/codedeploy-agent/deployment-root/deployment-group-id/deployment-id/deployment-archiveAmazon Linux、Ubuntu 服务器和 RHEL Amazon EC2 实例上的文件夹。

    C:\ProgramData\Amazon\CodeDeploy\deployment-group-id\deployment-id\deployment-archiveWindows 服务器的 Amazon EC2 实例上的文件夹。

    此事件是为 CodeDeploy 代理保留的,不能用于运行脚本。

    要对在 DownloadBundle 部署生命周期事件期间失败的部署进行故障排除,请参阅 使用 UnknownError:未打开以供阅读,对失败的 DownloadBundle 部署生命周期事件进行故障排除

  • BeforeInstall— 您可以将此部署生命周期事件用于预安装任务,例如解密文件和创建当前版本的备份。

  • Install— 在此部署生命周期事件中, CodeDeploy代理将修订文件从临时位置复制到最终目标文件夹。此事件是为 CodeDeploy 代理保留的,不能用于运行脚本。

  • AfterInstall— 您可以将此部署生命周期事件用于配置应用程序或更改文件权限等任务。

  • ApplicationStart— 您通常使用此部署生命周期事件来重新启动在此期间停止的服务ApplicationStop

  • ValidateService— 这是最后一个部署生命钩指示。它用于验证部署已成功完成。

  • BeforeBlockTraffic— 在实例从负载均衡器注销之前,您可以使用此部署生命周期事件在实例上运行任务。

    要对在 BeforeBlockTraffic 部署生命周期事件期间失败的部署进行故障排除,请参阅 对失败 ApplicationStop或 AfterBlockTraffic 部署生命周期事件进行故障排除 BeforeBlockTraffic

  • BlockTraffic— 在此部署生命周期事件期间,互联网流量被禁止访问当前为流量提供服务的实例。此事件是为 CodeDeploy 代理保留的,不能用于运行脚本。

  • AfterBlockTraffic— 从负载均衡器注销实例后,您可以使用此部署生命周期事件在实例上运行任务。

    要对在 AfterBlockTraffic 部署生命周期事件期间失败的部署进行故障排除,请参阅 对失败 ApplicationStop或 AfterBlockTraffic 部署生命周期事件进行故障排除 BeforeBlockTraffic

  • BeforeAllowTraffic— 您可以使用此部署生命周期事件在实例上运行任务,然后再将其注册到负载均衡器。

  • AllowTraffic— 在此部署生命周期事件期间,允许互联网流量在部署后访问实例。此事件是为 CodeDeploy 代理保留的,不能用于运行脚本。

  • AfterAllowTraffic— 在实例向负载均衡器注册后,您可以使用此部署生命周期事件在实例上运行任务。

Lifecycle event hook availability

下表列出了适用于每个部署和回滚方案的生命周期事件挂钩。

生命周期事件名称 就地部署¹ 蓝/绿部署:原始实例 蓝/绿部署:替换实例 蓝/绿部署回滚:原始实例 蓝/绿部署回滚:替换实例
ApplicationStop
DownloadBundle²
BeforeInstall
安装 ²
AfterInstall
ApplicationStart
ValidateService
BeforeBlockTraffic
BlockTraffic²
AfterBlockTraffic
BeforeAllowTraffic
AllowTraffic²
AfterAllowTraffic

¹ 也适用于就地部署的回调。

² 保留用于 CodeDeploy 操作。不能用于运行脚本。

部署中挂钩的运行顺序

就地部署

在就地部署中 (包括就地部署的回滚),事件挂钩按以下顺序运行:

注意

对于就地部署,只有当您在部署组中的 Elastic Load Balancing 中指定了Classic Load Balancer、Application Load Balancer 或Network Load Balancer 时,与阻塞和允许流量相关的六个挂钩才适用。

注意

部署中的 “开始”、“安装” 和 “结束” 事件无法编写脚本,这就是它们在此图中以灰色显示的原因。DownloadBundle但是,您可以编辑 AppSpec 文件'files'部分以指定安装事件期间安装的内容。

蓝/绿部署

在蓝/绿部署中,事件挂钩按以下顺序运行:

注意

部署中的 “开始BlockTrafficAllowTraffic、“安装” 和 “结束” 事件无法编写脚本,这就是它们在此图中以灰色显示的原因。DownloadBundle但是,您可以编辑文件的 “文件” 部分, AppSpec 以指定安装事件期间安装的内容。

“钩子” 部分的结构

'hooks' 部分具有以下结构:

hooks: deployment-lifecycle-event-name: - location: script-location timeout: timeout-in-seconds runas: user-name

可以在 hook 条目中的部署生命周期事件名称后包括以下元素:

location

必需。修订的脚本文件包的位置。您在hooks部分中指定的脚本位置相对于应用程序修订包的根目录。有关更多信息,请参阅计划 CodeDeploy 的修订

timeout

可选。在脚本被视为失败之前允许其执行的秒数。默认值为 3600 秒(1 小时)。

注意

3600 秒(1 小时)是允许每个部署生命周期事件脚本执行的最长时间。如果脚本超过此限制,则部署将停止,并且部署到实例将失败。确保在 timeout 中为每个部署生命周期事件的所有脚本指定的总秒数不超过此限制。

runas

可选。运行脚本时要模拟的用户。默认情况下,这是在实例上运行的 CodeDeploy 代理。 CodeDeploy 不存储密码,因此,如果 runas 用户需要密码,则无法模拟用户。此元素仅适用于亚马逊 Linux 和 Ubuntu 服务器实例。

挂钩的环境变量可用性

在每个部署生命周期事件期间,挂钩脚本可以访问以下环境变量:

APPLICATION_NAME

作为当前部署一部分 CodeDeploy 的应用程序的名称(例如,WordPress_App)。

DEPLOYMENT_ID

ID CodeDeploy 已分配给当前部署(例如d-AB1CDEF23)。

DEPLOYMENT_GROUP_NAME

作为当前部署一部分 CodeDeploy 的部署组的名称(例如,WordPress_DepGroup)。

DEPLOYMENT_GROUP_ID

作为当前部署一部分的部署组的 ID(例如,b1a2189b-dd90-4ef5-8f40-4c1c5EXAMPLE)。 CodeDeploy

LIFECYCLE_EVENT

当前部署生命周期事件的名称(例如 AfterInstall)。

这些是每个部署生命周期事件的本地环境变量。

根据部署包的来源,还有其他可用于挂接脚本的环境变量:

来自Amazon S3 的捆绑包

  • BUNDLE_

    从中下载部署包的 Amazon S3 存储桶的名称(例如,my-s3-bucket)。

  • 捆绑包_密钥

    Amazon S3 存储桶中已下载包裹的对象密钥(例如WordPress_App.zip)。

  • 捆绑包_版本

    捆绑包的对象版本(例如,3sL4kqtJlcpXroDTDmJ+rmSpXd3dIbrHY+MTRCxf3vjVBH40Nr8X8gdRQBpUMLUo)。只有在 Amazon S3 存储桶启用了对象版本控制时,才会设置此变量。

  • BUNDLE_ETAG

    捆绑包的对象标签(例如,b10a8db164e0754105b7a99be72e3fe5-4)。

捆绑来自 GitHub

  • 捆绑包_提交

    由 Git 生成的捆绑包的 SHA256 提交哈希(例如d2a84f4b8b650937ec8f73cd8be2c74add5a911ba64df27458ed8229da804a26)。

如果 DEPLOYMENT_GROUP_NAME 的值等于 Staging,则以下脚本会将 Apache HTTP 服务器上的侦听端口更改为 9090 而非 80。必须在 BeforeInstall 部署生命周期事件期间调用此脚本:

if [ "$DEPLOYMENT_GROUP_NAME" == "Staging" ] then sed -i -e 's/Listen 80/Listen 9090/g' /etc/httpd/conf/httpd.conf fi

如果 DEPLOYMENT_GROUP_NAME 环境变量的值等于 Staging,则以下脚本示例会将其错误日志中记录的消息的详细级别从警告更改为调试。必须在 BeforeInstall 部署生命周期事件期间调用此脚本:

if [ "$DEPLOYMENT_GROUP_NAME" == "Staging" ] then sed -i -e 's/LogLevel warn/LogLevel debug/g' /etc/httpd/conf/httpd.conf fi

以下脚本示例将指定网页中的文本替换为显示这些环境变量值的文本。必须在 AfterInstall 部署生命周期事件期间调用此脚本:

#!/usr/bin/python import os strToSearch="<h2>This application was deployed using CodeDeploy.</h2>" strToReplace="<h2>This page for "+os.environ['APPLICATION_NAME']+" application and "+os.environ['DEPLOYMENT_GROUP_NAME']+" deployment group with "+os.environ['DEPLOYMENT_GROUP_ID']+" deployment group ID was generated by a "+os.environ['LIFECYCLE_EVENT']+" script during "+os.environ['DEPLOYMENT_ID']+" deployment.</h2>" fp=open("/var/www/html/index.html","r") buffer=fp.read() fp.close() fp=open("/var/www/html/index.html","w") fp.write(buffer.replace(strToSearch,strToReplace)) fp.close()

钩子示例

以下是 hooks 条目的示例,该条目为 AfterInstall 生命周期事件指定两个挂钩:

hooks: AfterInstall: - location: Scripts/RunResourceTests.sh timeout: 180 - location: Scripts/PostDeploy.sh timeout: 180

Scripts/RunResourceTests.sh 脚本在部署过程的 AfterInstall 阶段运行。如果该脚本的运行时间超过 180 秒(3 分钟),则部署将失败。

您在“hooks”部分中指定的脚本的位置是应用程序修订包根目录的相对路径。在上述示例中,名为 RunResourceTests.sh 的文件位于名为 Scripts 的目录中。该 Scripts 目录位于包的根级别。有关更多信息,请参阅计划 CodeDeploy 的修订