AppSpec 的 “挂钩” 部分 - AWS CodeDeploy

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

AppSpec 的 “挂钩” 部分

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

用于 Amazon ECS 部署的 AppSpec 的 “挂钩” 部分

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

网络 ACL 和安全组都允许 (因此可到达您的实例) 的发起 ping 的AWSLambda 挂钩是一个 Lambda 函数,该函数在生命周期事件名称之后的新行中使用字符串指定。对于每次部署,每个挂钩将执行一次。以下是在部署 Amazon ECS 期间可以运行挂钩的生命周期事件的描述。

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

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

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

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

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

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

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

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

注意

部署中的 StartInstallTestTrafficAllowTrafficEnd 事件无法编写脚本,这就是它们在此图中以灰色显示的原因。

“挂钩” 部分的结构

以下示例说明了 '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” 函数示例

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

重要

如果 Lambda 验证函数未在一个小时内通知 CodeDeploy,则部署将被视为已失败。

在调用 Lambda 挂钩函数之前,必须使用putLifecycleEventHookExecutionStatus命令。

下面是一个使用 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 的 “hook” 部分AWSLambda 部署

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

网络 ACL 和安全组都允许 (因此可到达您的实例) 的发起 ping 的AWSLambda 挂钩是一个 Lambda 函数,该函数在生命周期事件名称之后的新行中使用字符串指定。对于每次部署,每个挂钩将执行一次。以下是对可用于您的 AppSpec 文件中的挂钩的描述。

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

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

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

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

注意

部署中的 StartAllowTrafficEnd 事件无法脚本化,这就是为什么它们在此图中灰显。

“挂钩” 部分的结构

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

使用 YAML:

hooks: - BeforeAllowTraffic: BeforeAllowTrafficHookFunctionName - AfterAllowTraffic: AfterAllowTrafficHookFunctionName

使用 JSON:

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

Lambda “hooks” 函数示例

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

重要

如果 Lambda 验证函数未在一个小时内通知 CodeDeploy,则部署将被视为已失败。

在调用 Lambda 挂钩函数之前,必须使用putLifecycleEventHookExecutionStatus命令。

下面是一个使用 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'); } }); };

EC2/本地部署的AppSpec 的 “挂钩” 部分

生命周期事件挂钩列表

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

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

  • 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 Server Amazon EC2 实例上的文件夹。

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

  • 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 Server Amazon EC2 实例上的文件夹。

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

    要对在 DownloadBundle 部署生命周期事件期间失败的部署进行故障排除,请参阅 排查失败的问题 DownloadBundle 带有 UnknownError 的部署生命周期事件:不会打开以阅读

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

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

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

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

  • ValidateService— 这是最后一个部署生命周期事件。它用于验证部署已成功完成。

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

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

  • BlockTraffic-在此部署生命周期事件期间,阻止 Internet 流量访问当前正在处理流量的实例。此事件是为 CodeDeploy 代理预留的,不能用于运行脚本。

  • AfterBlockTraffic-在从负载均衡器取消注册实例之后,您可以使用此部署生命周期事件在这些实例上运行任务。

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

  • BeforeAllowTraffic-在将实例注册到负载均衡器之前,您可以使用此部署生命周期事件在这些实例上运行任务。

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

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

可用性生命周期事件

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

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

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

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

在部署中运行挂钩顺序

就地部署

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

注意

对于就地部署,与阻止并允许流量相关的六个挂钩仅当您在部署组中指定中的 Elastic Load Balancing Network Load Balancer 时适 Application Load Balancer。

注意

部署中的 StartDownloadBundleInstallEnd 事件无法脚本化,这就是为什么它们在此图中灰显。但是,您可以编辑'files'AppSpec 文件的部分,以指定在安装event.

蓝/绿部署

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

注意

部署中的 StartDownloadBundleInstallBlockTrafficAllowTrafficEnd 事件无法脚本化,这就是它们在此图中灰显的原因。不过,您可以编辑 AppSpec 文件的 “files” 部分,以指定在安装event.

“挂钩” 部分的结构

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

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

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

位置

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

timeout

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

注意

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

runas

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

挂钩的环境变量可用性

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

APPLICATION_NAME

CodeDeploy 中属于当前部署的应用程序的名称(例如,WordPress_App)。

DEPLOYMENT_ID

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

DEPLOYMENT_GROUP_NAME

CodeDeploy 中属于当前部署的部署组的名称(例如,WordPress_DepGroup)。

DEPLOYMENT_GROUP_ID

CodeDeploy 中属于当前部署的部署组的 ID(例如,b1a2189b-dd90-4ef5-8f40-4c1c5EXAMPLE)。

LIFECYCLE_EVENT

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

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

如果 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 的修订