AppSpec 的“hooks”部分 - AWS CodeDeploy
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

AppSpec 的“hooks”部分

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

用于 Amazon ECS 部署的 AppSpec 的“hooks”部分

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

AWS Lambda 挂钩是一个 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 可调用以验证 Lambda 部署的 Lambda 函数。对于 BeforeInstallAfterInstallAllowTestTrafficBeforeAllowTrafficAllowTestTraffic 部署生命周期事件,您可以使用相同函数或不同函数。在完成验证测试后,Lambda AfterAllowTraffic 函数将回调 CodeDeploy,并交付 SucceededFailed 结果。

重要

如果 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 AWS CodeDeploy. var params = { deploymentId: deploymentId, lifecycleEventHookExecutionId: lifecycleEventHookExecutionId, status: 'Succeeded' // status can be 'Succeeded' or 'Failed' }; // Pass AWS 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'); } }); };

用于 AWS Lambda 部署的 AppSpec 的“hooks”部分

用于 AWS Lambda 部署的生命周期事件挂钩的列表

AWS Lambda 挂钩是一个 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,并交付 SucceededFailed 结果。

重要

如果 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 AWS CodeDeploy. var params = { deploymentId: deploymentId, lifecycleEventHookExecutionId: lifecycleEventHookExecutionId, status: 'Succeeded' // status can be 'Succeeded' or 'Failed' }; // Pass AWS 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 的“hooks”部分

生命周期事件挂钩的列表

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

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

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

    注意

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

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

    Amazon Linux、Ubuntu Server 和 RHEL Amazon EC2 实例上的 /opt/codedeploy-agent/deployment-root/deployment-instructions 文件夹。

    Windows Server Amazon EC2 实例上的 C:\ProgramData\Amazon\CodeDeploy\deployment-instructions 文件夹。

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

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

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

    Windows Server Amazon EC2 实例上的 C:\ProgramData\Amazon\CodeDeploy\deployment-group-id\deployment-id\deployment-archive 文件夹。

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

    要对在 DownloadBundle 部署生命周期事件期间失败的部署进行故障排除,请参阅 排查失败的 DownloadBundle 部署生命周期事件的问题,错误为“UnknownError: not opened for reading”

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

生命周期事件挂钩可用性

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

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

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

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

挂钩在部署中的运行顺序

就地部署

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

注意

对于就地部署,与阻止及允许流量相关的六个挂钩仅当您在部署组中指定 Elastic Load Balancing 中的 传统负载均衡器、应用程序负载均衡器 或 Network Load Balancer 时适用。

注意

部署中的 StartDownloadBundleInstallEnd 事件无法脚本化,这就是为什么它们在此图中灰显。不过,您可以编辑 AppSpec file 的 'files' 部分,以指定在 Install 事件期间安装的内容。

蓝/绿部署

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

注意

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

“挂钩”部分的结构

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

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

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

位置

必需。修订的脚本文件包的位置。

timeout

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

注意

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

runas

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

挂钩的环境变量可用性

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

APPLICATION_NAME

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

DEPLOYMENT_ID

CodeDeploy 已分配给当前部署的 ID(例如,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 的修订