CloudFormation模板中如何为ALB目标组导入并替换EC2实例ID
问题
我正在通过CloudFormation模板创建ALB,其中目标组资源需要导入之前任务导出的EC2实例ID,希望通过Sub函数替换导入名称以适配不同环境部署。用cfn-lint验证模板显示正确,但部署时收到错误:
No export named found
已确认所有预期导出名称符合命名规范且存在于对应栈中,查看CloudFormation转换后的模板,发现Fn::ImportValue后是空字符串,未读取Sub命令的结果。
原始模板内容:
AWSTemplateFormatVersion: "2010-09-09" Description: Creates an application load balancer. Parameters: pSystem: Type: String Default: your-system-name Description: 'Name of the system. Default: your-system-name' pApp: Type: String Description: 'Name of the application solution' pEnvironment: Type: String Default: sbx Description: 'Name of the deployment tier. Default: sbx' pVpcId: Type: AWS::SSM::Parameter::Value<String> Resources: rLoadBalancerTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Name: !Sub '${pSystem}-${pApp}-${pEnvironment}-public-tg' HealthCheckEnabled: true HealthCheckIntervalSeconds: 60 HealthCheckPath: 'REDACTED' HealthCheckPort: 1234 HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 10 HealthyThresholdCount: 2 Matcher: HttpCode: 200-299 Port: 1234 Protocol: HTTP ProtocolVersion: HTTP1 TargetGroupAttributes: - Key: 'deregistration_delay.timeout_seconds' Value: 300 - Key: 'stickiness.enabled' Value: false - Key: 'load_balancing.algorithm.type' Value: round_robin - Key: 'slow_start.duration_seconds' Value: 0 TargetType: instance UnhealthyThresholdCount: 2 VpcId: !Ref pVpcId Targets: - Id: !ImportValue Fn::Sub: '${pSystem}-${pApp}-01-${pEnvironment}-ec2-id' - Id: !ImportValue Fn::Sub: "${pSystem}-${pApp}-02-${pEnvironment}-ec2-id" - Id: !ImportValue Fn::Sub: "${pSystem}-${pApp}-03-${pEnvironment}-ec2-id"
转换后的模板中Targets部分:
Targets: - Id: Fn::ImportValue: '' Fn::Sub: ${pSystem}-${pApp}-01-${pEnvironment}-ec2-id - Id: Fn::ImportValue: '' Fn::Sub: ${pSystem}-${pApp}-02-${pEnvironment}-ec2-id - Id: Fn::ImportValue: '' Fn::Sub: ${pSystem}-${pApp}-03-${pEnvironment}-ec2-id
解决方案
问题出在YAML语法的嵌套写法错误:当前模板中!ImportValue和Fn::Sub被当作Id字段下的同级键,导致Fn::ImportValue没有接收任何参数,因此显示为空字符串。
正确的写法是将Fn::Sub的结果作为Fn::ImportValue的输入,需要把Sub嵌套在ImportValue内部,有两种写法:
写法1:使用短格式嵌套
Targets: - Id: !ImportValue !Sub '${pSystem}-${pApp}-01-${pEnvironment}-ec2-id' - Id: !ImportValue !Sub '${pSystem}-${pApp}-02-${pEnvironment}-ec2-id' - Id: !ImportValue !Sub '${pSystem}-${pApp}-03-${pEnvironment}-ec2-id'
写法2:使用完整函数嵌套格式
Targets: - Id: Fn::ImportValue: Fn::Sub: '${pSystem}-${pApp}-01-${pEnvironment}-ec2-id' - Id: Fn::ImportValue: Fn::Sub: '${pSystem}-${pApp}-02-${pEnvironment}-ec2-id' - Id: Fn::ImportValue: Fn::Sub: '${pSystem}-${pApp}-03-${pEnvironment}-ec2-id'
修正后的完整模板:
AWSTemplateFormatVersion: "2010-09-09" Description: Creates an application load balancer. Parameters: pSystem: Type: String Default: your-system-name Description: 'Name of the system. Default: your-system-name' pApp: Type: String Description: 'Name of the application solution' pEnvironment: Type: String Default: sbx Description: 'Name of the deployment tier. Default: sbx' pVpcId: Type: AWS::SSM::Parameter::Value<String> Resources: rLoadBalancerTargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Name: !Sub '${pSystem}-${pApp}-${pEnvironment}-public-tg' HealthCheckEnabled: true HealthCheckIntervalSeconds: 60 HealthCheckPath: 'REDACTED' HealthCheckPort: 1234 HealthCheckProtocol: HTTP HealthCheckTimeoutSeconds: 10 HealthyThresholdCount: 2 Matcher: HttpCode: 200-299 Port: 1234 Protocol: HTTP ProtocolVersion: HTTP1 TargetGroupAttributes: - Key: 'deregistration_delay.timeout_seconds' Value: 300 - Key: 'stickiness.enabled' Value: false - Key: 'load_balancing.algorithm.type' Value: round_robin - Key: 'slow_start.duration_seconds' Value: 0 TargetType: instance UnhealthyThresholdCount: 2 VpcId: !Ref pVpcId Targets: - Id: !ImportValue !Sub '${pSystem}-${pApp}-01-${pEnvironment}-ec2-id' - Id: !ImportValue !Sub '${pSystem}-${pApp}-02-${pEnvironment}-ec2-id' - Id: !ImportValue !Sub '${pSystem}-${pApp}-03-${pEnvironment}-ec2-id'
这样修改后,CloudFormation会先执行Sub生成正确的导出名称,再通过ImportValue获取对应的EC2实例ID,解决部署报错问题。
内容的提问来源于stack exchange,提问作者CodingMedic
相关产品推荐
相关产品推荐

