如何通过AWS CDK在流水线执行ECS命令并调试首次执行无效问题
ECS执行Drush命令调试方案及问题排查
问题背景
我们通过AWS CDK搭建流水线,利用Lambda执行ECS命令部署Drupal 8网站,CDK中配置了约5条此类部署命令。Lambda代码如下:
'use strict'; const AWS = require('aws-sdk'); const ecs = new AWS.ECS(); const codeDeploy = new AWS.CodeDeploy({ apiVersion: '2014-10-06' }); exports.handler = async (event, context, callback) => { console.log('Drush execution lambda invoked'); const deploymentId = event.DeploymentId; const lifecycleEventHookExecutionId = event.LifecycleEventHookExecutionId; try{ let validationTestResult = 'Failed'; const clusterName = process.env.CLUSTER_NAME; const containerName = process.env.CONTAINER_NAME; const taskListParams = { cluster: clusterName, desiredStatus: 'RUNNING', }; const taskList = await ecs.listTasks(taskListParams).promise(); const activeTask = taskList.taskArns[0]; console.log('Active task: ' + activeTask); ....................... const cimParams = { command: 'drush cim -y', interactive: true, task: activeTask, cluster: clusterName, container: containerName }; await ecs.executeCommand(cimParams, function (err, data) { if (err) { console.log(err, err.stack, "FAILED on drush cim -y"); } else { validationTestResult = 'Succeeded'; console.log(data, "Succeeded on drush cim -y"); } }).promise(); ............................. // Pass CodeDeploy the prepared validation test results. await codeDeploy.putLifecycleEventHookExecutionStatus({ deploymentId: deploymentId, lifecycleEventHookExecutionId: lifecycleEventHookExecutionId, status: validationTestResult // status can be 'Succeeded' or 'Failed' }).promise(); }catch (e) { console.log(e); console.log('Drush execution lambda failed'); await codeDeploy.putLifecycleEventHookExecutionStatus({ deploymentId: deploymentId, lifecycleEventHookExecutionId: lifecycleEventHookExecutionId, status: 'Failed' // status can be 'Succeeded' or 'Failed' }).promise(); } };
当前问题:命令执行日志显示成功,但网站无预期变更;第二次运行流水线时变更才生效。手动在ECS容器执行drush cim -y可正常生效,怀疑ECS执行环节存在问题,现有日志不足以定位根因,需明确有效的ECS命令调试方法。
调试与排查方案
一、完善日志采集,获取执行细节
- 捕获Drush命令的完整输出:修改
drush cim -y为drush cim -y -v 2>&1,添加 verbose 参数并将错误输出重定向到标准输出,同时在Lambda中捕获命令执行的完整输出(可通过ECS ExecuteCommand的会话日志,或在命令中将输出写入容器内文件后读取)。 - 验证目标任务的正确性:当前代码直接取
taskArns[0],流水线部署时可能存在新旧任务共存的情况,需确认执行命令的是新部署的任务。可通过筛选任务的启动时间、CodeDeploy关联的目标组标签,或从CodeDeploy事件中获取目标任务ARN,避免误操作旧任务。 - 补充环境与权限日志:在执行Drush命令前,先执行
printenv && pwd && whoami,输出容器的环境变量、工作目录和执行用户,对比手动执行时的环境,排查环境差异问题。
二、排查ECS命令执行的时机与逻辑
- 确认命令触发时机:检查Lambda是否绑定到CodeDeploy的正确生命周期钩子,确保在新任务启动完成、流量切换前执行命令,避免命令执行在旧任务上,或新任务未完全就绪时执行。
- 修复Lambda异步逻辑缺陷:当前代码同时使用回调函数和
.promise(),会导致validationTestResult的更新逻辑混乱,甚至出现命令实际失败但仍返回成功状态的情况。修改为纯Promise风格:try { const data = await ecs.executeCommand(cimParams).promise(); validationTestResult = 'Succeeded'; console.log(data, "Succeeded on drush cim -y"); } catch (err) { console.log(err, err.stack, "FAILED on drush cim -y"); }
三、验证ECS命令执行的一致性
- 模拟Lambda执行环境:在本地或测试容器中,使用Lambda角色的权限调用
aws ecs execute-command,模拟Lambda的执行流程,对比手动执行和自动化执行的差异。 - 检查命令执行的权限:确认Lambda角色拥有
ecs:ExecuteCommand、ssm:StartSession权限,且容器的SSM Agent版本符合要求,确保命令能正常下发到容器内。
内容的提问来源于stack exchange,提问作者Dynamdilshan
相关产品推荐
相关产品推荐

