本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
AppSpec “挂钩” 部分
AppSpec 文件'hooks'
部分的内容因部署的计算平台而异。EC2/本地部署'hooks'
部分包含将部署生命周期事件挂钩链接到一个或多个脚本的映射。Lambda 或 Amazon 部署'hooks'
部分指定了在ECS部署生命周期事件期间要运行的 Lambda 验证函数。如果某个事件的挂钩不存在,则不会对该事件执行任何操作。仅当您将在部署过程中运行脚本或 Lambda 验证函数时,才需要此部分。
AppSpec Amazon ECS 部署的 “挂钩” 部分
Amazon ECS 部署的生命周期事件挂钩列表
AWS Lambda 挂钩是一个 Lambda 函数,在生命周期事件名称后的新行中使用字符串指定。对于每次部署,每个挂钩将执行一次。以下是生命周期事件的描述,您可以在这些事件中在 Amazon ECS 部署期间运行挂钩。
-
BeforeInstall
– 用于在创建替换任务集之前运行任务。一个目标组与原始任务集相关联。如果指定了可选的测试侦听器,则它与原始任务集相关联。此时,无法执行回滚。 -
AfterInstall
– 用于在创建替换任务集并且其中一个目标组与之关联后运行任务。如果指定了可选的测试侦听器,则它与原始任务集相关联。在此生命周期事件时挂钩函数的运行结果可能会触发回滚。 -
AfterAllowTestTraffic
– 用于在测试侦听器为替换任务集提供流量后运行任务。此时挂钩函数的运行结果可能会触发回滚。 -
BeforeAllowTraffic
– 用于在第二个目标组与替换任务集关联之后但在流量转移到替换任务集之前运行任务。在此生命周期事件时挂钩函数的运行结果可能会触发回滚。 -
AfterAllowTraffic
– 用于在第二个目标组为替换任务集提供流量后运行任务。在此生命周期事件时挂钩函数的运行结果可能会触发回滚。
有关更多信息,请参阅Amazon ECS 部署期间会发生什么 和教程:通过验证测试部署 Amazon ECS 服务。
在 Amazon ECS 部署中运行挂钩顺序。
在 Amazon ECS 部署中,事件挂钩按以下顺序运行:
注意
部署中的 “开始” TestTrafficAllowTraffic、“安装” 和 “结束” 事件无法编写脚本,这就是它们在此图中以灰色显示的原因。
“hooks”部分的结构
以下示例说明了 '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'
部分指定一个 Lambda 函数,该函数 CodeDeploy 可以调用该函数来验证亚马逊ECS部署。您可以对BeforeInstall
、、AfterInstall
AfterAllowTestTraffic
、BeforeAllowTraffic
和AfterAllowTraffic
部署生命周期事件使用相同或不同的函数。验证测试完成后,Lambda AfterAllowTraffic
函数会回调 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 AWS Lambda 部署的 “挂钩” 部分
AWS Lambda 部署的生命周期事件挂钩列表
AWS Lambda 挂钩是一个 Lambda 函数,在生命周期事件名称后的新行中使用字符串指定。对于每次部署,每个挂钩将执行一次。以下是可在您的 AppSpec 文件中使用的挂钩的描述。
-
BeforeAllowTraffic— 用于在流量转移到已部署的 Lambda 函数版本之前运行任务。
-
AfterAllowTraffic— 用于在所有流量转移到已部署的 Lambda 函数版本后运行任务。
挂钩在 Lambda 函数版本部署中的运行顺序
在无服务器 Lambda 函数版本部署中,事件挂钩按以下顺序运行:
注意
部署中的 “开始” AllowTraffic、“结束” 事件无法编写脚本,这就是它们在此图中以灰色显示的原因。
“hooks”部分的结构
以下示例说明了“hooks”部分的结构。
使用YAML:
hooks: - BeforeAllowTraffic:
BeforeAllowTrafficHookFunctionName
- AfterAllowTraffic:AfterAllowTrafficHookFunctionName
使用JSON:
"hooks": [{ "BeforeAllowTraffic": "
BeforeAllowTrafficHookFunctionName
" }, { "AfterAllowTraffic": "AfterAllowTrafficHookFunctionName
" }]
Lambda“hooks”函数示例
使用 “挂钩” 部分指定一个 Lambda 函数,该函数 CodeDeploy 可以调用该函数来验证 Lambda 部署。您可以对BeforeAllowTraffic
和AfterAllowTraffic
部署生命周期事件使用相同或不同的函数。验证测试完成后,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 文件中使用的挂钩的描述。
有关哪些生命周期事件挂钩对哪些部署和回滚类型有效的信息,请参阅生命周期事件挂钩可用性。
-
ApplicationStop
– 此部署生命周期事件发生在下载应用程序修订之前。您可以为此事件指定脚本,以便从容地停止应用程序或在部署准备过程中删除当前已安装的软件包。用于此部署生命周期事件 AppSpec 的文件和脚本来自先前成功部署的应用程序修订版。注意
在部署到实例之前, AppSpec 文件不存在于该实例。因此,
ApplicationStop
挂钩在您首次部署到实例时不会运行。您可以在第二次部署到实例时使用ApplicationStop
挂钩。要确定上次成功部署的应用程序修订版的位置, CodeDeploy 代理会查找
文件中列出的位置。此文件位于:deployment-group-id
_last_successful_install/opt/codedeploy-agent/deployment-root/deployment-instructions
亚马逊 Linux、Ubuntu 服务器和RHEL亚马逊EC2实例上的文件夹。C:\ProgramData\Amazon\CodeDeploy\deployment-instructions
Windows 服务器亚马逊EC2实例上的文件夹。要对在
ApplicationStop
部署生命周期事件期间失败的部署进行故障排除,请参阅 对失败 ApplicationStop BeforeBlockTraffic、或 AfterBlockTraffic 部署生命周期事件进行故障排除。 -
DownloadBundle
— 在此部署生命周期事件中, CodeDeploy 代理会将应用程序修订文件复制到临时位置:/opt/codedeploy-agent/deployment-root/
亚马逊 Linux、Ubuntu 服务器和RHEL亚马逊EC2实例上的文件夹。deployment-group-id
/deployment-id
/deployment-archiveC:\ProgramData\Amazon\CodeDeploy\
Windows 服务器亚马逊EC2实例上的文件夹。deployment-group-id
\deployment-id
\deployment-archive此事件是为 CodeDeploy 代理保留的,不能用于运行脚本。
要对在
DownloadBundle
部署生命周期事件期间失败的部署进行故障排除,请参阅 使用以下命令对失败的 DownloadBundle 部署生命周期事件进行故障排除 UnknownError:未打开供读取。 -
BeforeInstall
– 您可以使用此部署生命周期事件执行预安装任务,例如解密文件和创建当前版本的备份。 -
Install
— 在此部署生命周期事件中, CodeDeploy代理将修订文件从临时位置复制到最终目标文件夹。此事件是为 CodeDeploy 代理保留的,不能用于运行脚本。 -
AfterInstall
– 您可以使用此部署生命周期事件执行配置应用程序或更改文件权限等任务。 -
ApplicationStart
– 此部署生命周期事件通常用于重新启动在ApplicationStop
期间停止的服务。 -
ValidateService
– 这是最后一个部署生命周期事件。它用于验证部署已成功完成。 -
BeforeBlockTraffic
– 在从负载均衡器取消注册实例之前,您可以使用此部署生命周期事件在这些实例上运行任务。要对在
BeforeBlockTraffic
部署生命周期事件期间失败的部署进行故障排除,请参阅 对失败 ApplicationStop BeforeBlockTraffic、或 AfterBlockTraffic 部署生命周期事件进行故障排除。 -
BlockTraffic
– 在此部署生命周期事件期间,阻止互联网流量访问当前正在处理流量的实例。此事件是为 CodeDeploy 代理保留的,不能用于运行脚本。 -
AfterBlockTraffic
– 在从相应的负载均衡器取消注册实例之后,您可以使用此部署生命周期事件在这些实例上运行任务。要对在
AfterBlockTraffic
部署生命周期事件期间失败的部署进行故障排除,请参阅 对失败 ApplicationStop BeforeBlockTraffic、或 AfterBlockTraffic 部署生命周期事件进行故障排除。 -
BeforeAllowTraffic
– 在将实例注册到负载均衡器之前,您可以使用此部署生命周期事件在这些实例上运行任务。 -
AllowTraffic
– 在此部署生命周期事件期间,允许互联网流量在部署后访问实例。此事件是为 CodeDeploy 代理保留的,不能用于运行脚本。 -
AfterAllowTraffic
– 在将实例注册到负载均衡器之后,您可以使用此部署生命周期事件在这些实例上运行任务。
生命周期事件挂钩可用性
下表列出了适用于每个部署和回滚方案的生命周期事件挂钩。
生命周期事件名称 | Auto Scaling 启动部署¹ | Auto Scaling 终止部署¹ | 就地部署² | 蓝/绿部署:原始实例 | 蓝/绿部署:替换实例 | 蓝/绿部署回滚:原始实例 | 蓝/绿部署回滚:替换实例 |
---|---|---|---|---|---|---|---|
ApplicationStop | ✓ | ✓ | ✓ | ✓ | |||
DownloadBundle³ | ✓ | ✓ | ✓ | ||||
BeforeInstall | ✓ | ✓ | ✓ | ||||
Install³ | ✓ | ✓ | ✓ | ||||
AfterInstall | ✓ | ✓ | ✓ | ||||
ApplicationStart | ✓ | ✓ | ✓ | ||||
ValidateService | ✓ | ✓ | ✓ | ||||
BeforeBlockTraffic | ✓ | ✓ | ✓ | ✓ | |||
BlockTraffic³ | ✓ | ✓ | ✓ | ✓ | |||
AfterBlockTraffic | ✓ | ✓ | ✓ | ✓ | |||
BeforeAllowTraffic | ✓ | ✓ | ✓ | ✓ | |||
AllowTraffic³ | ✓ | ✓ | ✓ | ✓ | |||
AfterAllowTraffic | ✓ | ✓ | ✓ | ✓ | |||
¹ 有关 Amazon A EC2 uto Scaling 部署的信息,请参阅Amazon EC2 Auto Scaling 是如何使用的 CodeDeploy。 ² 也适用于就地部署的回滚。 ³ 预留用于 CodeDeploy 操作。不能用于运行脚本。 |
挂钩在部署中的运行顺序
Auto Scaling 启动部署
在 Auto Scaling 启动部署期间,按以下顺序 CodeDeploy 运行事件挂钩。
有关 Auto Scaling 启动部署的更多信息,请参阅 Amazon EC2 Auto Scaling 是如何使用的 CodeDeploy。
注意
部署中的 “开始” AllowTraffic、“安装” 和 “结束” 事件无法编写脚本,这就是它们在此图中以灰色显示的原因。DownloadBundle但是,您可以编辑 AppSpec 文件'files'
部分以指定在安装事件期间安装的内容。
Auto Scaling 终止部署
在 Auto Scaling 终止部署期间,按以下顺序 CodeDeploy 运行事件挂钩。
有关 Auto Scaling 终止部署的更多信息,请参阅 在 Auto Scaling 横向缩减事件期间启用终止部署。
注意
部署中的 “开始” BlockTraffic、“结束” 事件无法编写脚本,这就是它们在此图中以灰色显示的原因。
就地部署
在就地部署中(包括就地部署的回滚),事件挂钩按以下顺序运行:
注意
对于就地部署,与阻止和允许流量相关的六个挂钩仅当您在部署组中指定 Elastic Load Balancing 中的经典负载均衡器、应用程序负载均衡器或网络负载均衡器时适用。
注意
部署中的 “开始”、“安装” 和 “结束” 事件无法编写脚本,这就是它们在此图中以灰色显示的原因。DownloadBundle但是,您可以编辑 AppSpec 文件'files'
部分以指定在安装事件期间安装的内容。
蓝/绿部署
在蓝/绿部署中,事件挂钩按以下顺序运行:
注意
部署中的 “开始”、“安装” BlockTrafficAllowTraffic、“、” 和 “结束” 事件无法编写脚本,这就是它们在此图中以灰色显示的原因。DownloadBundle但是,您可以编辑文件的 “文件” 部分, AppSpec 以指定在安装事件期间安装的内容。
“hooks”部分的结构
'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 用户需要密码,则无法模拟该用户。此元素仅适用于 Amazon Linux 和 Ubuntu Server 实例。
在挂钩脚本中引用文件
如果您要按中所述将脚本连接到 CodeDeploy 生命周期事件AppSpec “挂钩” 部分,并且想要在脚本中引用文件(例如helper.sh
),则需要helper.sh
使用以下命令进行指定:
使用绝对路径
要使用文件的绝对路径来引用文件,可以执行以下任一操作:
-
在 AppSpec 文件
files
部分的destination
属性中指定绝对路径。然后,在挂钩脚本中指定相同的绝对路径。有关更多信息,请参阅 AppSpec “文件” 部分(仅EC2限本地部署)。 -
在挂钩脚本中指定一个动态绝对路径。有关更多信息,请参阅部署存档位置。
部署存档位置
在DownloadBundle生命周期事件期间, CodeDeploy 代理会将要部署的修订提取到以下格式的目录中:
root-directory
/deployment-group-id
/deployment-id
/deployment-archive
这些区域有:root-directory
路径的一部分始终设置为下表所示的默认路径,或者由:root_dir
配置设置控制。有关配置设置的更多信息,请参阅CodeDeploy 代理配置参考。
代理平台 | 默认根目录 |
---|---|
Linux – 所有 rpm 发行版 |
/opt/codedeploy-agent/deployment-root
|
Ubuntu Server – 所有 deb 发行版 |
/opt/codedeploy-agent/deployment-root
|
Windows Server |
%ProgramData%\Amazon\CodeDeploy
|
从挂钩脚本中,您可以使用根目录路径以及 DEPLOYMENT_ID
和 DEPLOYMENT_GROUP_ID
环境变量访问当前的部署存档。有关您能使用的变量的更多信息,请参阅挂钩的环境变量可用性。
下面的示例介绍了如何在 Linux 上访问位于修订根目录下的 data.json
文件:
#!/bin/bash rootDirectory="/opt/codedeploy-agent/deployment-root" # note: this will be different if you # customize the :root_dir configuration dataFile="$rootDirectory/$DEPLOYMENT_GROUP_ID/$DEPLOYMENT_ID/deployment-archive/data.json" data=$(cat dataFile)
再举一个例子,介绍了如何在 Windows 上使用 Powershell 访问位于修订根目录下的 data.json
文件:
$rootDirectory="$env:ProgramData\Amazon\CodeDeploy" # note: this will be different if you # customize the :root_dir configuration $dataFile="$rootDirectory\$env:DEPLOYMENT_GROUP_ID\$env:DEPLOYMENT_ID\deployment-archive\data.json" $data=(Get-Content $dataFile)
使用相对路径
要使用文件的相对路径来引用文件,你需要知道 CodeDeploy 代理的工作目录。文件路径是相对于该目录的。
下表显示了 CodeDeploy 代理的每个支持平台的工作目录。
代理平台 | 流程管理方法 | 生命周期事件脚本的工作目录 |
---|---|---|
Linux – 所有 rpm 发行版 | systemd(默认) |
/
|
init.d – 了解更多 |
/opt/codedeploy-agent
|
|
Ubuntu Server – 所有 debian 发行版 | all |
/opt/codedeploy-agent
|
Windows Server | 不适用 |
C:\Windows\System32
|
挂钩的环境变量可用性
在每个部署生命周期事件期间,挂钩脚本可以访问以下环境变量:
- 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_BUCKET
从中下载部署包的 Amazon S3 存储桶的名称(例如
my-s3-bucket
)。 -
BUNDLE_KEY
Amazon S3 存储桶中下载的捆绑包的对象键(例如
WordPress_App.zip
)。 -
BUNDLE_VERSION
捆绑包的对象版本(例如
3sL4kqtJlcpXroDTDmJ+rmSpXd3dIbrHY+MTRCxf3vjVBH40Nr8X8gdRQBpUMLUo
)。只有在 Amazon S3 存储桶启用了对象版本控制时,才会设置此变量。 -
BUNDLE_ETAG
捆绑包的对象 etag(例如,
b10a8db164e0754105b7a99be72e3fe5-4
)。
捆绑包来自 GitHub
-
BUNDLE_COMMIT
Git 生成的捆绑包的SHA256提交哈希值(例如
d2a84f4b8b650937ec8f73cd8be2c74add5a911ba64df27458ed8229da804a26
)。
如果 DEPLOYMENTGROUP_ 的值等于,则以下脚本将 Apache HTTP 服务器上的侦听端口更改为 9090 而不NAME是 80。Staging
必须在 BeforeInstall
部署生命周期事件期间调用此脚本:
if [ "$DEPLOYMENT_GROUP_NAME" == "Staging" ] then sed -i -e 's/Listen 80/Listen 9090/g' /etc/httpd/conf/httpd.conf fi
如果 DEPLOYMENTGROUP_ 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。