GeekFactory

int128.hatenablog.com

Terraformでcloud-configを記述する

AWSのEC2インスタンスでは、User Dataにシェルスクリプトを渡すことで起動時にスクリプトを実行できます。ファイルを配置したり、パッケージをインストールしたり、といった複雑なことがやりたい場合はcloud-initが便利です。詳しくは公式ドキュメントの例を参照してください。

docs.aws.amazon.com

例えば、下記のようなYAMLをUser Dataに指定すると、OSの起動時にsystemdで独自のサービスを開始できます。

#cloud-config
write_files:
  - path: /etc/systemd/system/helloworld.service"
    content: |
      [Unit]
      Description = Hello World
      [Service]
      ExecStart = /usr/local/bin/helloworld.sh
      Restart = always
      Type = simple
      [Install]
      WantedBy = multi-user.target
  - path: /usr/local/bin/helloworld.sh"
    permissions: 0755
    content: |
      #!/bin/sh
      while true; do date; sleep 1; done
runcmd:
  - ["systemctl", "start", "helloworld"]
  - ["systemctl", "enable", "helloworld"]

Terraformでcloud-configを指定する場合、下記のように外部ファイルを読み込むと簡単に書けます。

resource "aws_instance" "this" {
  user_data_base64 = filebase64('./cloud-config.yaml')
}

ただ、YAMLの中にインラインでシェルスクリプトなどをベタ書きしているため、可読性がよくないというデメリットがあります。エディタで開いてもsyntax highlightingしてくれません。

そこで、下記のように動的にYAMLを組み立てることで、シェルスクリプトなどのファイルを外部化できます。

resource "aws_instance" "this" {
  user_data_base64 = base64encode(join("\n", [
    "#cloud-config",
    yamlencode({
      write_files : [
        {
          path : "/etc/systemd/system/helloworld.service",
          content : file("./helloworld.service"),
        },
        {
          path : "/usr/local/bin/helloworld",
          content : file("./helloworld.sh"),
          permissions : "0755",
        },
      ],
      runcmd : [
        ["systemctl", "enable", "helloworld"],
        ["systemctl", "start", "helloworld"],
      ],
    })
  ]))
} 

サンプルが下記にあるので参考にどうぞ。

github.com