Lambda调用SSM文档遇Invalid Instance ID错误排查与解决
问题背景
我在实现Auto Scaling实例终止的自动化流程时踩了坑:设计的流程是实例终止→生命周期钩子→CloudWatch事件→Lambda→SSM Run Command,Lambda在测试环境(调用运行中的实例)能正常工作,但在真实终止流程中触发后,却抛出了InvalidInstanceId错误。
Lambda函数代码如下:
const AWS = require('aws-sdk'); const ssm = new AWS.SSM(); const SSM_DOCUMENT_NAME = process.env.SSM_DOCUMENT_NAME; AWS.config.update({region: 'ap-south-1'}); const sendCommand = (instance_id) => { var params = { DocumentName: SSM_DOCUMENT_NAME, InstanceIds: [instance_id], TimeoutSeconds: 300 }; console.log("before call:"+params.InstanceIds); return ssm.sendCommand(params).promise(); } exports.handler = async (event) => { console.log('event ', JSON.stringify(event)); try { const instance_id = event.detail.EC2InstanceId; console.log("processing autoscaling event for "+instance_id); await sendCommand(instance_id); console.log('sent command'); } catch (error) { throw error; } }
触发时的错误日志:
Invoke Error
{
"errorType": "InvalidInstanceId",
"errorMessage": null,
"code": "InvalidInstanceId",
"message": null,
"time": "2020-06-19T09:43:10.348Z",
"requestId": "150decf1-be1d-407f-9a86-a4f986c04807",
"statusCode": 400,
"retryable": false,
"retryDelay": 20.23844834854607,
"stack": [
"InvalidInstanceId: null",
" at Request.extractError (/var/runtime/node_modules/aws-sdk/lib/protocol/json.js:51:27)",
" at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:106:20)",
" at Request.emit (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:78:10)",
" at Request.emit (/var/runtime/node_modules/aws-sdk/lib/request.js:683:14)",
" at Request.transition (/var/runtime/node_modules/aws-sdk/lib/request.js:22:10)",
" at AcceptorStateMachine.runTo (/var/runtime/node_modules/aws-sdk/lib/state_machine.js:14:12)",
" at /var/runtime/node_modules/aws-sdk/lib/state_machine.js:26:10",
" at Request.(/var/runtime/node_modules/aws-sdk/lib/request.js:38:9)",
" at Request.(/var/runtime/node_modules/aws-sdk/lib/request.js:685:12)",
" at Request.callListeners (/var/runtime/node_modules/aws-sdk/lib/sequential_executor.js:116:18)"
]
}
问题根源分析
- 实例生命周期与SSM托管状态不匹配:当实例进入
termination:wait状态后,会立刻从Systems Manager的托管实例列表中移除,此时Lambda触发SSM命令时,SSM已经找不到该实例ID,自然抛出InvalidInstanceId错误——就算把生命周期等待时间拉到600秒也没用,因为实例一旦进入终止流程,SSM的注册状态会直接失效。 - 测试场景完全不符合真实流程:之前的测试是针对运行中的实例,但手动终止实例根本不会触发生命周期钩子!只有当Auto Scaling策略判定实例不健康(比如ELB健康检查失败)时,才会触发对应的生命周期钩子,这导致之前的测试完全无法复现真实问题。
- Lambda代码的小bug:代码里先创建了SSM实例,再更新AWS区域配置,这会导致区域配置不生效,虽然这次错误不是直接由此引发,但会影响整体稳定性。
解决方案
1. 调整生命周期钩子的触发时机
把生命周期钩子的触发事件调整到实例刚进入终止流程的早期阶段,确保在实例还没从SSM托管列表中移除时就执行SSM命令:
- 在Auto Scaling Group的生命周期钩子配置中,选择
InstanceTerminating作为触发事件,设置合理的等待时间(保证SSM命令能在实例被注销前执行完成)。 - 确认CloudWatch Events规则能及时触发Lambda,不要有延迟。
2. 修正Lambda代码的区域配置顺序+增加实例校验
把AWS区域配置移到创建SSM实例之前,同时新增实例在SSM托管列表中的校验逻辑,避免无效调用:
const AWS = require('aws-sdk'); AWS.config.update({region: 'ap-south-1'}); // 先更新区域配置,再创建SSM实例 const ssm = new AWS.SSM(); const SSM_DOCUMENT_NAME = process.env.SSM_DOCUMENT_NAME; const sendCommand = (instance_id) => { var params = { DocumentName: SSM_DOCUMENT_NAME, InstanceIds: [instance_id], TimeoutSeconds: 300 }; console.log("before call:"+params.InstanceIds); return ssm.sendCommand(params).promise(); } exports.handler = async (event) => { console.log('event ', JSON.stringify(event)); try { const instance_id = event.detail.EC2InstanceId; console.log("processing autoscaling event for "+instance_id); // 新增:提前验证实例是否在SSM托管列表中 const instanceInfo = await ssm.describeInstanceInformation({ InstanceInformationFilterList: [ { key: 'InstanceIds', valueSet: [instance_id] } ] }).promise(); if (instanceInfo.InstanceInformationList.length === 0) { console.error(`Instance ${instance_id} is not managed by SSM, skipping command`); return { statusCode: 200, body: 'Instance not found in SSM' }; } await sendCommand(instance_id); console.log('sent command'); return { statusCode: 200, body: 'Command sent successfully' }; } catch (error) { console.error('Error executing command:', error); throw error; } }
3. 用正确的方式测试流程
不要手动终止实例测试,而是模拟Auto Scaling的不健康实例场景(比如停止实例的SSM Agent,或者让ELB健康检查失败),触发Auto Scaling的终止流程,这样才能正确触发生命周期钩子。
4. 确保实例能被SSM正常管理
- 确认实例上的SSM Agent已正确安装并运行,且实例拥有
AmazonSSMManagedInstanceCore这个IAM权限策略。 - 实例所在的VPC需要能访问SSM服务(可以通过VPC端点或公网访问),避免实例无法注册到SSM。
内容的提问来源于stack exchange,提问作者Shurmajee

