具有资源属性 CloudFormation 的 UserData 脚本

Posted

技术标签:

【中文标题】具有资源属性 CloudFormation 的 UserData 脚本【英文标题】:UserData script with Resource Attribute CloudFormation 【发布时间】:2018-07-15 11:54:27 【问题描述】:

主要问题:如何在云形成模板中引用相关资源属性来构建用户数据脚本。

我的尝试

    列出的方法here。 来自sub function 的示例

我正在为三节点 Kafka 集群构建 CloudFormation 模板。

我在这里采用的方法是使用 EC2 实例上的 UserData 脚本在集群的每个节点上配置 Zookeeper 和 Kafka。

我正在使用Sub 和Base64 函数用我的NetworkInterface 的PrimaryPrivateIpAddress 填充我的用户数据脚本,但它们以空字符串而不是实际值的形式出现。我知道这些值被正确填充,因为它们是我在模板中输出的一部分。

我在下面包含了我的模板的资源块作为参考。为了简洁起见,我省略了一些无趣的部分。我还说明了我尝试过的几种不同方法来解决 EC2 资源块不一致的问题。

EC2I8MWW:
  Type: 'AWS::EC2::Instance'
  DependsOn:
    - EC2NI2E8ES
    - EC2NI2PFST
    - EC2NI54B66
  Properties:
    KeyName: !Ref DesiredKeyName
    InstanceType: !Ref InstanceType
    NetworkInterfaces:
      - NetworkInterfaceId: !Ref EC2NI54B66
        DeviceIndex: "0"
    UserData:
      Fn::Base64:
        Fn::Sub:
          - |
            #!/bin/bash
            CONF="/etc/zookeeper/conf.dist/zoo.cfg"
            PRIVATE_1=$Private1
            PRIVATE_2=$Private2
            PRIVATE_3=$Private3
            echo "# Zookeeper configuration for Talentreef" > "$CONF"
            cat <<EOT >> "$CONF"
            maxClientCnxns=50
            tickTime=2000
            initLimit=10
            syncLimit=5
            EOT
            echo "server.1=$PRIVATE_1:2888:3888" >> $CONF
            echo "server.2=$PRIVATE_2:2888:3888" >> $CONF
            echo "server.3=$PRIVATE_3:2888:3888" >> $CONF
            service zookeeper-server init --myid=$NODE_ID
            chkconfig zookeeper-server on
          - 
            Private1: !GetAtt EC2NI2E8ES.PrimaryPrivateIpAddress,
            Private2: !GetAtt EC2NI2PFST.PrimaryPrivateIpAddress,
            Private3: !GetAtt EC2NI54B66.PrimaryPrivateIpAddress
            
EC2I2JVJI:
  Type: 'AWS::EC2::Instance'
  DependsOn: EC2NI54B66
  Properties:
    KeyName: !Ref DesiredKeyName
    InstanceType: !Ref InstanceType
    BlockDeviceMappings:
      - DeviceName: /dev/xvdb
        Ebs:
          VolumeType: st1
          DeleteOnTermination: 'true'
          VolumeSize: '500'
      - DeviceName: /dev/xvda
        Ebs:
          VolumeType: gp2
          DeleteOnTermination: 'true'
          VolumeSize: '8'
    ImageId: !FindInMap
      - AWSRegionArch2AMI
      - !Ref 'AWS::Region'
      - !FindInMap
        - AWSInstanceType2Arch
        - !Ref InstanceType
        - Arch
    NetworkInterfaces:
      - NetworkInterfaceId: !Ref EC2NI2PFST
        DeviceIndex: "0"
    UserData:
      Fn::Base64: !Sub |
        #!/bin/bash
        CONF="/etc/zookeeper/conf.dist/zoo.cfg"
        cp $CONF /etc/zookeeper/conf.dist/zoo.cfg.bak-$(date +%s)
        echo "# Zookeeper configuration for Talentreef" > "$CONF"
        cat <<EOT >> "$CONF"
        maxClientCnxns=50
        tickTime=2000
        initLimit=10
        syncLimit=5
        server.1=$EC2NI2E8ES.PrimaryPrivateIpAddress:2888:3888
        server.2=$EC2NI2PFST.PrimaryPrivateIpAddress:2888:3888
        server.3=$EC2NI54B66.PrimaryPrivateIpAddress:2888:3888
        EOT
        service zookeeper-server init --myid=$NODE_ID
        chkconfig zookeeper-server on
        service zookeeper-server start
EC2I56LVQ:
  Type: 'AWS::EC2::Instance'
  DependsOn: EC2NI54B66
  Properties:
    KeyName: !Ref DesiredKeyName
    InstanceType: !Ref InstanceType
    BlockDeviceMappings:
      - DeviceName: /dev/xvdb
        Ebs:
          VolumeType: st1
          DeleteOnTermination: 'true'
          VolumeSize: '500'
      - DeviceName: /dev/xvda
        Ebs:
          VolumeType: gp2
          DeleteOnTermination: 'true'
          VolumeSize: '8'
    ImageId: !FindInMap
      - AWSRegionArch2AMI
      - !Ref 'AWS::Region'
      - !FindInMap
        - AWSInstanceType2Arch
        - !Ref InstanceType
        - Arch
    NetworkInterfaces:
      - NetworkInterfaceId: !Ref EC2NI2E8ES
        DeviceIndex: "0"
    UserData:
      Fn::Base64:
        Fn::Sub:
          - |
            CONF="/etc/zookeeper/conf.dist/zoo.cfg"
            cp $CONF /etc/zookeeper/conf.dist/zoo.cfg.bak-$(date +%s)
            echo "# Zookeeper configuration for Talentreef" > "$CONF"
            cat <<EOT >> "$CONF"
            maxClientCnxns=50
            tickTime=2000
            initLimit=10
            syncLimit=5
            EOT
            echo "server.1=$Private1:2888:3888" >> $CONF
            echo "server.2=$Private2:2888:3888" >> $CONF
            echo "server.3=$Private3:2888:3888" >> $CONF
            service zookeeper-server init --myid=$NODE_ID
            chkconfig zookeeper-server on
          - 
            Private1: !GetAtt EC2NI2E8ES.PrimaryPrivateIpAddress,
            Private2: !GetAtt EC2NI2PFST.PrimaryPrivateIpAddress,
            Private3: !GetAtt EC2NI54B66.PrimaryPrivateIpAddress
            
EC2NI54B66:
  Type: 'AWS::EC2::NetworkInterface'
  DependsOn: EC2NI2PFST
  Properties: 
EC2NI2PFST:
  Type: 'AWS::EC2::NetworkInterface'
  DependsOn: EC2NI2E8ES
  Properties 
EC2NI2E8ES:
  Type: 'AWS::EC2::NetworkInterface'
  Properties: 

当此脚本运行时,我在 zoo.cfg 文件中得到以下输出:

maxClientCnxns=50
tickTime=2000
initLimit=10
syncLimit=5
server.1=:2888:3888
server.2=:2888:3888
server.3=:2888:3888

如果我在这里做错了什么或者我必须改变我的方法,请告诉我。谢谢你的帮助。

【问题讨论】:

【参考方案1】:

我认为你走在正确的道路上。我会稍微修改一下传递 3 个“私有”替代变量的方式,例如(我在模板中经常使用):

UserData:
  Fn::Base64:
    Fn::Sub:
      - |
        CONF="/etc/zookeeper/conf.dist/zoo.cfg"
        cp $CONF /etc/zookeeper/conf.dist/zoo.cfg.bak-$(date +%s)
        echo "# Zookeeper configuration for Talentreef" > "$CONF"
        cat <<EOT >> "$CONF"
        maxClientCnxns=50
        tickTime=2000
        initLimit=10
        syncLimit=5
        EOT
        echo "server.1=$Private1:2888:3888" >> $CONF
        echo "server.2=$Private2:2888:3888" >> $CONF
        echo "server.3=$Private3:2888:3888" >> $CONF
        service zookeeper-server init --myid=$NODE_ID
        chkconfig zookeeper-server on
      - Private1: !GetAtt EC2NI2E8ES.PrimaryPrivateIpAddress
        Private2: !GetAtt EC2NI2PFST.PrimaryPrivateIpAddress
        Private3: !GetAtt EC2NI54B66.PrimaryPrivateIpAddress

所以没有括号 也没有逗号 ,

【讨论】:

谢谢!我在那里也遇到了一些糟糕的 bash,所以我也修复了它并且一切正常。 谢谢,它也解决了我在 Userdata 中使用 !GetAtt 的问题

以上是关于具有资源属性 CloudFormation 的 UserData 脚本的主要内容,如果未能解决你的问题,请参考以下文章

CloudFormation 创建的资源的有效属性

cloudformation 验证返回:无效的模板资源属性

具有 CloudFormation 的 Amazon DynamoDB 属性类型

AWS Cloudformation:有条件地创建资源的属性

AWS cloudformation 错误:模板验证错误:模板错误:资源 NotificationsTopic 不支持 Fn::GetAtt 中的属性类型 Arn

如何使用 Cloudformation 在 AWS RestAPI 中创建嵌套资源路径?