【问题标题】:If a distro is selected, find in map cloudformation如果选择了发行版,请在地图 cloudformation 中查找
【发布时间】:2019-10-15 09:10:40
【问题描述】:

我正在尝试创建一个 CloudFormation 脚本,该脚本允许用户从三个选项(ubuntu、redhat、centos)中选择一个 Linux 发行版。然后,根据用户选择的选项,我想从现有映射中为正在创建 CloudFormation 堆栈的区域选择正确的 AMI。最后,我想使用该区域特定的 AMI 作为 EC2 实例的映像 ID。

我为每个分布映射了该区域的 AMI。

我希望这一切都自动化,所以我可以只使用一个 CloudFormation 脚本,而不是每个操作系统都使用一个。

我有一个 Web 应用程序,它可以根据客户偏好在 Ubuntu、CentOS 或 Red Hat 上运行。我不想为每个发行版维护三个单独的 CloudFormation 脚本,特别是考虑到每个发行版唯一不同的是 EC2 实例的 ImageId

我知道我可能应该使用 CloudFormation 的条件函数,但我还没有真正想出办法。

我无法在网上找到任何可以提供这么大帮助的东西。那是因为真的很容易没有人发布任何关于它的东西,或者不可能,我觉得可能是后者,但希望看到一些其他的观点。

这是我目前正在使用的内容的摘录。

Parameters:
  ApplicationServerLinuxDistribution:
    Type: "String"
    AllowedValues:
      - ubuntu
      - redhat
      - centos

Mappings:
# Ubuntu 18.04 AMIs
  AWSUbuntuAMIRegionMap:
    ap-northeast-1:
      HVM64: "ami-0cd744adeca97abb1"
    ap-northeast-2:
      HVM64: "ami-00379ec40a3e30f87"
# Red Hat 8 AMIs
  AWSRedHatAMIRegionMap:
    ap-northeast-1:
      HVM64: "ami-0c45b9b8b241f629f"
    ap-northeast-2:
      HVM64: "ami-090f71670acf741d8"
# CentOS 7 AMIs
  AWSCentOSAMIRegionMap:
    ap-northeast-1:
      HVM64: "ami-045f38c93733dd48d"
    ap-northeast-2:
      HVM64: "ami-06cf2a72dadf92410"

Resources:
   ApplicationServer:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: 

所以要明确我想要的是,如果用户在 eu-west-1 并选择 Ubuntu,我想查询我的 Ubuntu 区域/AMI 地图以查找 eu-west-1 AMI,并使用该 AMI 创建EC2 实例,如果用户选择 Red Hat 或 CentOS,则执行相同的操作,但要使用这些地图。

【问题讨论】:

    标签: amazon-web-services conditional-statements amazon-cloudformation


    【解决方案1】:

    你快到了,但是因为 Fn::FindInMap 只能返回与两级映射中的键对应的值,所以我会从映射中删除 HVM64 属性:

      AMIRegionMap:
        ap-northeast-1: 
          ubuntu: "ami-0cd744adeca97abb1"
          redhat: "ami-0c45b9b8b241f629f"
          centos: "ami-045f38c93733dd48d"
        ap-northeast-2: 
          ubuntu: "ami-00379ec40a3e30f87"
          redhat: "ami-090f71670acf741d8"
          centos: "ami-06cf2a72dadf92410"
    

    然后在“资源”部分中,您可以使用 AWS::Region 伪参数和 ApplicationServerLinuxDistribution 参数来访问您需要的 AMI:

    Resources:
       ApplicationServer:
        Type: "AWS::EC2::Instance"
        Properties:
          ImageId: !FindInMap [AMIRegionMap, !Ref "AWS::Region", !Ref ApplicationServerLinuxDistribution]
    

    区域必须作为一级key,如果作为二级key会遇到Mappings attribute name 'ap-northeast-1' must contain only alphanumeric characters.documentation声明:

    名称只能包含字母数字字符 (A-Za-z0-9)。

    但不清楚这仅适用于二级密钥!

    【讨论】:

    • 感谢您回复@Patrick,我遇到了地区名称中的连字符问题,最初我收到了Mappings attribute name 'ap-northeast-1' must contain only alphanumeric characters. 错误。如果我删除了连字符,我可以继续,但随后又遇到了另一个错误Unable to get mapping for AMIRegionMap::redhat::eu-west-3。我已经在下面回答了我的问题,因为我能够解决它,您的回答确实帮助我走上了正确的道路,所以谢谢你。?
    • 嗨@JakePrice 让我感到震惊,因为我只使用区域作为地图中的第一级键,文档确实说键名只能包含字母数字字符,但这似乎并不适用于第一级密钥。从映射中的键中删除连字符时出现的错误是由于 FindInMap 函数试图查找 !Ref "AWS::Region" 计算结果为 ap-northeast-1,这与您的键 apnortheast1 不匹配。
    • 谢谢@Patrick,是的,这在两个方面都很有意义,很高兴知道未来!
    【解决方案2】:

    这实际上比我最初想象的要简单得多,并且可以在完全不使用条件的情况下完成。

    解决方案

    # Define the distribution's a user can choose from.
    Parameters:
      LinuxDistributionSelection:
        Type: "String"
        AllowedValues:
          - ubuntu
          - centos
          - redhat
    
    # Create a single map where each Region is a TopLevelKey, and each Parameter is a SecondLevelKey with the AMI as the key's value.
    Mappings:
      AMIMapping:
        ap-east-1:
          ubuntu: "ami-59780228"
          centos: "null"
          redhat: "ami-7b374d0a"
        ap-northeast-1:
          ubuntu: "ami-04a1c725d8678428c"
          centos: "ami-045f38c93733dd48d"
          redhat: "ami-0c45b9b8b241f629f"
        ap-northeast-2:
          ubuntu: "ami-0df5bf8255e3a317f"
          centos: "ami-06cf2a72dadf92410"
          redhat: "ami-090f71670acf741d8"
    
    # Query the map
    Resources:
       ApplicationServer:
        Type: AWS::EC2::Instance
        Properties:
          ImageId: !FindInMap [AMIMapping, !Ref "AWS::Region", !Ref LinuxDistributionSelection ]
    
    

    为什么会这样?

    这是可行的,因为TopLevelKey 下可以有多个SecondLevelKey,正如Fn::FindInMap 文档所述:here。因此,每个区域中每个分布的 AMI 可以只是区域键下的键/值对。下面的例子。

    Fn::FindInMap: [ MapName, TopLevelKey=<region>, SecondLevelKey=<parameter-reference> ]
    

    CloudFormation 然后可以逻辑地处理事情。因此,当您需要根据用户选择的内容获取 EC2 实例的 ImageId 参数的 AMI 时,您可以告诉 CloudFormation 使用 !FindInMapFn::FindInMap 的简写)查询您的区域地图。然后 CloudFormation 将使用 !Ref "AWS::Region" 引用您正在运行脚本的区域,最后 CloudFormation 能够使用 !Ref LinuxDistributionSelection 引用所选参数。

    !FindInMap [AMIMapping, !Ref "AWS::Region", !Ref LinuxDistributionSelection ]
    

    我希望我的回答是足够的,并且对于任何在同一问题上苦苦挣扎的人来说都足够好。这是我的第一个答案,所以请善待,如果它具有误导性,或者我误解了这里实际发生的事情,请随时批评它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-04
      • 1970-01-01
      相关资源
      最近更新 更多