CloudFormation基于实例族选AMI时FindInMap传参报错问题
CloudFormation中FindInMap嵌套Select/Split函数报错原因与解决方案
问题描述
需要实现基于实例族动态匹配AMI的逻辑:实例族通过截取InstanceType参数中点号.前的前缀确定,初始模板逻辑为使用!Select搭配!Split截取实例族前缀,作为第三个参数传入FindInMap查找对应区域的AMI ID,但创建栈时抛出如下验证错误:
调用CreateStack操作时返回ValidationError:模板错误,每个Fn::FindInMap对象需传入三个参数,分别为映射表名称、映射键、待返回的属性值
初始问题模板片段如下:
AWSTemplateFormatVersion: 2010-09-09 Description: my new server Parameters: InstanceType: Description: Instance Type Type: String AllowedValues: - t2.micro - t3a.small - t3a.medium - t4g.micro - t4g.small - t4g.medium Mappings: AmiMap: us-east-1: ## AMD64 Instances t2: ami-0f65ab0fd913bc7be t3a: ami-0f65ab0fd913bc7be ## Graviton (ARM) Instances t4g: ami-0cf2a935e8b19b29b Resources: LaunchConfig: Type: AWS::AutoScaling::LaunchConfiguration Properties: ... ImageId: !FindInMap - AmiMap - "us-east-1" - !Select [0, !Split [".", !Ref InstanceType ]]
报错根本原因
这个报错和函数返回值是不是有效字符串没有关系,核心是CloudFormation解析器的语法兼容问题:
- 早期CloudFormation对
Fn::FindInMap的键参数有严格限制,不支持嵌套任何固有函数,必须传入静态字符串;后续版本虽然放开了嵌套函数支持,但仅支持完整Fn::前缀的长格式函数嵌套,不支持!开头的短格式函数在FindInMap的参数列表里多层嵌套。 - 你写的
!Select [0, !Split [".", !Ref InstanceType ]]属于三层短格式函数嵌套,YAML解析器处理时会把嵌套结构错误拆分,导致CloudFormation最终识别到的FindInMap入参数量不是要求的3个,直接抛出参数数量不匹配的校验错误。
修复方案
有两种可直接落地的修复方式:
- 方案1:改用完整长格式Fn::语法书写嵌套函数(推荐,改动最小)
把短格式的!开头函数写法换成完整的Fn::前缀长格式,解析器就能正确识别嵌套结构,不需要调整原有映射逻辑:ImageId: !FindInMap - AmiMap - "us-east-1" - Fn::Select: - 0 - Fn::Split: - "." - !Ref InstanceType - 方案2:拆分映射层避免多层嵌套(兼容所有旧版解析器,最稳妥)
如果你的CloudFormation栈使用的是较旧的API版本,长格式写法依然不兼容,可以提前在Mappings里维护实例类型到实例族的对应关系,分两次查找映射,完全避免多层函数嵌套:Mappings: # 新增实例类型到实例族的直接映射 InstanceFamilyMap: t2.micro: t2 t3a.small: t3a t3a.medium: t3a t4g.micro: t4g t4g.small: t4g t4g.medium: t4g AmiMap: us-east-1: t2: ami-0f65ab0fd913bc7be t3a: ami-0f65ab0fd913bc7be t4g: ami-0cf2a935e8b19b29b Resources: LaunchConfig: Type: AWS::AutoScaling::LaunchConfiguration Properties: # 先查实例族,再查对应AMI ImageId: !FindInMap - AmiMap - "us-east-1" - !FindInMap [InstanceFamilyMap, !Ref InstanceType]
补充:如果模板需要跨区域部署,不要硬编码
us-east-1,可以使用AWS::Region伪参数作为FindInMap的第二层键,同时在AmiMap里补充所有目标区域的AMI映射即可。
内容的提问来源于stack exchange,提问作者Brandon
相关产品推荐
相关产品推荐

