Kumogata+CloudInit+cfn-init

先日の記事があまり盛り上がらないので、新しい記事書きます。

KumogataCloudInit+cfn-initの連携について。

cfn-initはAmazon Linuxべったりな気がして使うのに抵抗があったんですが、パッケージになってますね。 Kumogataのリポジトリ内にCentOS/Ubuntu+CloudInit+cfn-initのPackerテンプレートを置きました

サンプルテンプレート

Parameters do
  Password do
    NoEcho true
    Type "String"
  end
end

Resources do
  myEC2Instance do
    Type "AWS::EC2::Instance"
    Properties do
      ImageId "ami-XXXXXXXX"
      InstanceType "m1.large"
      KeyName "your_key_name"

      UserData do
        Fn__Base64 (<<-EOS).fn_join
          #!/bin/bash
          /opt/aws/bin/cfn-init -s <%= Ref "AWS::StackName" %> -r myEC2Instance --region <%= Ref "AWS::Region" %>
        EOS
      end
    end

    Metadata do
      AWS__CloudFormation__Init do
        config do

          packages do
            yum({"httpd"=>[]})
          end

          services do
            sysvinit do
              httpd do
                enabled "true"
                ensureRunning "true"
              end
            end
          end

          commands do
            any_name do # `test` だとRubyのビルトインメソッドと競合します…
              command (<<-EOS).fn_join
                echo <%= Ref "Password" %> > /tmp/my-password
              EOS
            end
          end

        end # config
      end # AWS__CloudFormation__Init
    end # Metadata
  end
end

だいたいこんな感じで使えます。 cfn-signalを使って同期を取りながらプロビジョニングするのがいいんでしょうけど、手軽に使いたいならこういう書き方もありかなと。

_join() String#fn_join()

Fn::Joinまわりを書くのがものすごくだるかったので、String#fn_join()というビルトイン関数を追加しました。 これを使うとRubyのコードが以下のように変換されます。

UserData do
  Fn__Base64 (<<-EOS).fn_join
    #!/bin/bash
    /opt/aws/bin/cfn-init -s <%= Ref "AWS::StackName" %> -r myEC2Instance --region <%= Ref "AWS::Region" %>
  EOS
end
"UserData": {
  "Fn::Base64": {
    "Fn::Join": [
      "",
      [
        "#!/bin/bash\n/opt/aws/bin/cfn-init -s ",
        {
          "Ref": "AWS::StackName"
        },
        " -r myEC2Instance --region ",
        {
          "Ref": "AWS::Region"
        },
        "\n"
      ]
    ]
  }
}

作り始めた当初は「Rubyのjoinでいいじゃん」とか思っていたんですが、テンプレートのメタ情報をサーバ内で取得しようと思うと、Fn::ほげほげは必要ですね。 パスワードをUserDataに書くわけにもいかないし。

公式のテンプレートを読んだりすると、カジュアルにUserDataにパスワードが出力されてたりするんですが、大丈夫なんだろうか… あと、スタックを保持する場合、後からパスワード等のメタ情報を取得できそうですが、その辺のケアも気になるところ。

デモ

Please try it out!