如何让CloudFormation嵌套模板内的资源引用同模板内其他资源?
嵌套CloudFormation模板内资源引用问题的解决办法
你遇到的问题根源在于:父模板会优先解析嵌套模板TemplateBody里所有!开头的短格式函数,而InnerA是嵌套模板内部的资源,父模板根本不知道它的存在,所以会抛出“未定义资源”的错误。要让嵌套模板内部的资源引用生效,有几种可行方案:
方案一:用YAML字面量包裹嵌套模板内容(最简单)
把嵌套模板的内容用|标记为字符串字面量,这样父模板会把整个内容原封不动传给嵌套栈,由嵌套栈自己解析内部的资源引用。修改后的模板如下:
AWSTemplateFormatVersion: '2010-09-09' Resources: OuterA: Type: AWS::S3::Bucket TestStack: Type: AWS::CloudFormation::Stack Properties: TemplateBody: | AWSTemplateFormatVersion: '2010-09-09' Resources: InnerA: Type: AWS::S3::Bucket OuterB: Type: AWS::S3::Bucket # 父模板资源引用依然有效 BucketName: !GetAtt OuterA.BucketName OuterC: Type: AWS::S3::Bucket BucketName: !Ref OuterA InnerB: Type: AWS::S3::Bucket # 嵌套内部资源引用现在会被嵌套栈正确解析 BucketName: !GetAtt InnerA.BucketName InnerC: Type: AWS::S3::Bucket BucketName: !Ref InnerA
方案二:将嵌套模板存为独立文件(推荐,适合复杂场景)
把嵌套模板的内容单独保存为一个文件(比如nested-template.yaml),上传到S3后,父模板通过TemplateURL引用它。这种方式彻底分离父模板和嵌套模板,各自解析自己的资源引用,维护起来更清晰:
父模板
AWSTemplateFormatVersion: '2010-09-09' Resources: OuterA: Type: AWS::S3::Bucket TestStack: Type: AWS::CloudFormation::Stack Properties: # 替换成你存储嵌套模板的S3地址 TemplateURL: https://your-s3-bucket.s3.amazonaws.com/nested-template.yaml # 如果需要把父模板的资源传给嵌套模板,用参数传递 Parameters: ParentBucketName: !Ref OuterA
嵌套模板(nested-template.yaml)
AWSTemplateFormatVersion: '2010-09-09' Parameters: ParentBucketName: Type: String Resources: InnerA: Type: AWS::S3::Bucket OuterB: Type: AWS::S3::Bucket BucketName: !Ref ParentBucketName InnerB: Type: AWS::S3::Bucket BucketName: !GetAtt InnerA.BucketName InnerC: Type: AWS::S3::Bucket BucketName: !Ref InnerA
方案三:用Fn::Sub混合处理父/内部引用(可读性较差,不推荐)
如果必须在父模板里写TemplateBody,可以用Fn::Sub处理父模板资源的引用,同时用${!XXX}的转义写法保留嵌套模板内部的引用,避免被父模板提前解析:
AWSTemplateFormatVersion: '2010-09-09' Resources: OuterA: Type: AWS::S3::Bucket TestStack: Type: AWS::CloudFormation::Stack Properties: TemplateBody: !Sub | AWSTemplateFormatVersion: '2010-09-09' Resources: InnerA: Type: AWS::S3::Bucket OuterB: Type: AWS::S3::Bucket # 父模板资源引用由Sub解析 BucketName: ${OuterA} OuterC: Type: AWS::S3::Bucket BucketName: ${!GetAtt OuterA.BucketName} InnerB: Type: AWS::S3::Bucket # 内部引用不受Sub影响,由嵌套栈解析 BucketName: !GetAtt InnerA.BucketName InnerC: Type: AWS::S3::Bucket BucketName: !Ref InnerA
内容的提问来源于stack exchange,提问作者Sparr
相关产品推荐
相关产品推荐

