如何在AWS CloudFormation中运行Bash命令并解决CommandRunner可用区报错
报错修复方案
你碰到的错误是t3.micro实例类型在你当前指定的可用区us-east-1e不支持,针对AWSUtility::CloudFormation::CommandRunner的修复方式如下:
- 给CommandRunner资源新增
SubnetId参数,指定报错提示中支持t3.micro的可用区(us-east-1a/1b/1c/1d/1f)下的公有子网ID - 也可以新增
InstanceType参数,替换为对应可用区支持的实例类型(比如全AZ普遍支持的t2.micro)
修复后的配置示例如下:
Resources: CommandRunner: Type: AWSUtility::CloudFormation::CommandRunner Properties: Command: 'aws ssm get-parameter --name BucketName --region us-east-1 --query Parameter.Value --output text > /command-output.txt' SubnetId: subnet-xxxxxx # 替换为你账号下在支持t3.micro的AZ中的公有子网ID InstanceType: t2.micro # 按需替换为对应AZ支持的实例类型 RoleArn: arn:aws:iam::你的账号ID:role/CommandRunner执行角色ARN # 替换为你自己的执行角色ARN
CloudFormation运行Bash脚本的原生通用方案
如果不想依赖第三方私有Registry类型,也可以使用AWS原生方案实现,常用的有两种:
1. EC2 UserData方案
适合需要完整Linux运行环境、执行时间较长的脚本,直接在EC2资源的UserData字段定义Bash脚本即可:
Resources: EC2Instance: Type: AWS::EC2::Instance Properties: InstanceType: t2.micro ImageId: ami-0c55b159cbfafe1f0 # 替换为对应区域的Amazon Linux 2 AMI ID SubnetId: subnet-xxxxxx # 替换为自己的子网ID IamInstanceProfile: !Ref InstanceProfile UserData: Fn::Base64: | #!/bin/bash # 此处填写你需要执行的Bash命令 BUCKET_NAME=$(aws ssm get-parameter --name BucketName --region us-east-1 --query Parameter.Value --output text) echo $BUCKET_NAME > /tmp/command-output.txt # 执行完成后上报结果到CloudFormation /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource EC2Instance --region ${AWS::Region} CreationPolicy: ResourceSignal: Timeout: PT5M # 最长等待脚本执行5分钟 InstanceProfile: Type: AWS::IAM::InstanceProfile Properties: Roles: - !Ref EC2ExecutionRole EC2ExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: ec2.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore - arn:aws:iam::aws:policy/service-role/AWSCloudFormationSignalEndpointAccess Policies: - PolicyName: SSMParameterAccess PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: ssm:GetParameter Resource: arn:aws:ssm:us-east-1:你的账号ID:parameter/BucketName
2. 无服务器自定义资源方案
适合轻量脚本,不需要长期运行EC2,执行速度快成本低,通过Lambda运行Bash命令:
Resources: ExecuteBashFunction: Type: AWS::Lambda::Function Properties: Runtime: python3.9 Handler: index.lambda_handler Role: !GetAtt LambdaExecutionRole.Arn Code: ZipFile: | import boto3 import cfnresponse import subprocess def lambda_handler(event, context): if event['RequestType'] == 'Delete': cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) return try: # 执行Bash命令 result = subprocess.run( ['aws', 'ssm', 'get-parameter', '--name', 'BucketName', '--region', 'us-east-1', '--query', 'Parameter.Value', '--output', 'text'], capture_output=True, text=True, check=True ) bucket_name = result.stdout.strip() cfnresponse.send(event, context, cfnresponse.SUCCESS, {'BucketName': bucket_name}) except Exception as e: cfnresponse.send(event, context, cfnresponse.FAILED, {'Error': str(e)}) LambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyName: SSMParameterAccess PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: ssm:GetParameter Resource: arn:aws:ssm:us-east-1:你的账号ID:parameter/BucketName # 触发脚本执行 ExecuteBashCustomResource: Type: Custom::ExecuteBash Properties: ServiceToken: !GetAtt ExecuteBashFunction.Arn # 输出执行结果 Outputs: BucketName: Value: !GetAtt ExecuteBashCustomResource.BucketName
内容的提问来源于stack exchange,提问作者Shahzaib Butt
相关产品推荐
相关产品推荐

