如何通过Lambda借助SSM逐行执行EC2命令并实时获取输出?
Lambda 在 Linux EC2 上逐行执行命令并实时获取输出的方案
现有实现的问题
当前通过SSM批量发送命令的代码如下:
import boto3, time client = boto3.client("ssm", region_name="eu-west-1") INSTANCE_ID = "some-instance-id" commands = ["ls -la","uname"] response = client.send_command( InstanceIds=[INSTANCE_ID], DocumentName="AWS-RunShellScript", Parameters={"commands": commands}, ) command_id = response["Command"]["CommandId"] while True: time.sleep(3) result = client.get_command_invocation( CommandId=command_id, InstanceId=INSTANCE_ID, ) if result["Status"] == "InProgress": continue print(result["StandardOutputContent"]) print(result["StandardErrorContent"]) break
存在两个明显弊端:
- 批量发送命令时,一旦某条命令失败,无法直接定位具体是哪条命令出错
- 固定3秒的
time.sleep轮询会浪费不必要的等待时间,降低执行效率
需求是实现类似以下的逻辑:逐个发送命令,立即获取每条命令的输出,出错时直接终止流程:
commands = ["ls -la", "uname"] for command in commands: output, errors = some_client.send_command(command) if errors: break
尝试过SSM.Client.start_session方法,但Lambda运行环境没有预装Session Manager插件,无法使用交互式会话。
可行解决方案
方法1:拆分命令为单独的SendCommand调用
每次仅发送一条命令,单独追踪执行状态和结果,同时优化轮询间隔提升效率。代码示例:
import boto3 import time from botocore.exceptions import ClientError ssm_client = boto3.client("ssm", region_name="eu-west-1") INSTANCE_ID = "some-instance-id" def run_single_command(command): try: # 发送单条命令 cmd_response = ssm_client.send_command( InstanceIds=[INSTANCE_ID], DocumentName="AWS-RunShellScript", Parameters={"commands": [command]} ) cmd_id = cmd_response["Command"]["CommandId"] # 轮询命令状态,用1秒间隔替代3秒,减少等待 while True: invocation_result = ssm_client.get_command_invocation( CommandId=cmd_id, InstanceId=INSTANCE_ID ) # 命令完成(成功/失败/取消)时返回结果 if invocation_result["Status"] not in ["Pending", "InProgress"]: return (invocation_result["StandardOutputContent"], invocation_result["StandardErrorContent"]) time.sleep(1) except ClientError as e: return "", str(e) # 逐个执行命令,出错即终止 commands = ["ls -la", "uname"] for cmd in commands: output, errors = run_single_command(cmd) print(f"=== 命令 `{cmd}` 输出 ===") print(output) if errors: print(f"=== 命令 `{cmd}` 错误 ===") print(errors) break
这个方案的优势:
- 每条命令的结果独立,能精准定位出错的命令
- 缩短轮询间隔,提升整体执行效率
- 不需要额外插件,Lambda原生支持SSM的SendCommand和get_command_invocation接口
方法2:自定义SSM文档实现分步执行(可选)
如果需要更结构化的步骤管理,可以创建自定义SSM文档,将每个命令作为单独执行步骤,这样能在结果中查看每个步骤的状态。示例文档(JSON格式):
{ "schemaVersion": "2.2", "description": "逐行执行Shell命令", "parameters": { "command1": { "type": "String", "description": "第一条命令" }, "command2": { "type": "String", "description": "第二条命令" } }, "mainSteps": [ { "action": "aws:runShellScript", "name": "executeCmd1", "inputs": { "runCommand": ["{{ command1 }}"] } }, { "action": "aws:runShellScript", "name": "executeCmd2", "inputs": { "runCommand": ["{{ command2 }}"] } } ] }
在Lambda中调用该文档时,可通过get_command_invocation的StepExecutions字段获取每个步骤的具体结果。不过这种方式需要预先定义步骤数量,灵活性不如方法1。
内容的提问来源于stack exchange,提问作者alterionisto
相关产品推荐
相关产品推荐

