TerraformでEC2を作成する時に初回起動時にスクリプトを実行したい場合のUser Dataの記載方法

## はじめに
EC2の初回起動時に使用するUser DataはTerraformファイル内に定義することができますが、
独自のShellスクリプトファイルをUser Dataに定義し、そのファイルを参照させることが可能です。

ShellスクリプトファイルにTerraformの環境変数を渡すには、data sourceを利用します。
例えば、Terraformの環境変数からS3やEFSやECRの情報をShellスクリプトに渡すことができます。

今回はuser dataにShellスクリプトファイルを配置し、Terraformの環境変数からバケット名とオブジェクト名をそのスクリプトに渡します。
User Dataに配置したスクリプトでs3からEC2にファイルをダウンロードする方法を紹介します。

## 作成するファイル

- variables.tf
- main.tf
- script.sh
- outputs.tf


### variables.tf

```terraform:variables.tf

variable "ami" {
  description = "Amazon Machine Image ID"
  type        = string
  default     = "ami-xxxxxxxxxxxxxxxx" # Replace with your actual AMI ID
}

variable "InstanceType" {
  description = "EC2 instance type"
  type        = string
  default     = "t2.micro" # Replace with your desired instance type
}

variable "az" {
  description = "Availability Zone"
  type        = string
  default     = "us-east-1a" # Replace with your desired availability zone
}

variable "subnets" {
  description = "List of subnet IDs"
  type        = list(string)
  default     = ["subnet-xxxxxxxxxxxxxxxx", "subnet-yyyyyyyyyyyyyyyy"] # Replace with your subnet IDs
}

variable "security_groups" {
  description = "List of security group IDs"
  type        = list(string)
  default     = ["sg-xxxxxxxxxxxxxxxx", "sg-yyyyyyyyyyyyyyyy"] # Replace with your security group IDs
}

variable "key_name" {
  description = "SSH key pair name"
  type        = string
  default     = "your-key-pair" # Replace with your key pair name
}

variable "bucket_name" {
  description = "BucketName"
  type        = string
  default     = "common-storage"
}
 
variable "s3_file_name" {
  description = "s3 file name to download"
  type        = string
  default     = "object1"
}

```
### main.tf

```terraform:main.tf

data "template_file" "user_data" {
  template = "${file("./script.sh")}"
  #template = "${file("${path.module}/script.sh")}" # 必要に応じてmoduleディレクトリに対し、shellスクリプトが存在するパスを変えてください。
  vars = {
      bucket_name = "${var.bucket_name}"
      s3_file_name = "${var.s3_file_name}"
 
  }
}
 
resource "aws_instance" "ec2" {
  #ami                         = var.ami
  #instance_type               = var.InstanceType
  #availability_zone           = var.az
  #subnet_id                   = var.subnets
  #vpc_security_group_ids      = var.security_groups
  #key_name                    = var.key_name
  #そのたのattributes
  user_data = "${data.template_file.user_data.rendered}"
}
```

### script.sh

```shell:script.sh
#その他のコード
aws s3 cp s3://${bucket_name}/${s3_file_name} .          #aws s3 cp s3://バケット名/オブジェクト名 /保存先を指定する（例：/s3/bucket）今回は保存先"."にしましたので、ec2-userのホームディレクトリにS3ファイルがダウンロードされます。
#その他のコード

```


### outputs.tf

```terraform:outputs.tf
output "public_ip_of_ec2" {
  description = "public ip of ec2"
  value = "${aws_instance.ec2.public_ip}"
}

```

## 解説

data "template_file" "user_data" ブロックは、Terraform内で定義された変数やリソースの値を使用して、テンプレートファイルを生成するために使われます。
具体的には、このデータソースは template 属性で指定されたテンプレートファイル（ここでは script.sh）を読み込み、その中の変数（例:`${var.bucket_name}`や`${var.s3_file_name}`）をTerraform の変数に置き換えます。
vars ブロックでは、テンプレート内の変数に対応するTerraform変数の値を指定します。この例では、bucket_name と s3_file_name がそれに該当します。
具体的な使い方は、resource "aws_instance" "ec2" 内で user_data 属性としてこのデータソースを参照しています。これにより、EC2インスタンスの起動時に、テンプレートファイル script.sh に対して Terraform の変数が埋め込まれた形で User Data が提供されます。
簡潔に言えば、data "template_file" はTerraformの変数を使用してファイルを生成し、それを他のリソースで利用するための機能です。
詳細はを参照[data-sources](https://registry.terraform.io/providers/hashicorp/template/latest/docs/data-sources/file)



- variables.tf: お使いの環境に合わせて必要な変数を定義します。
- main.tf: template_fileデータソースを使用して、Shellスクリプトに変数を埋め込みます。
- script.sh: S3からファイルをダウンロードするShellスクリプトです。
- outputs.tf: EC2のパブリックIPアドレスを出力します。

このファイル構成を使って、Terraformを実行するとEC2インスタンスが起動し、指定したS3のファイルがダウンロードされます。これにより、Terraformの環境変数をShellスクリプトに渡すことができます。
以上が、User Dataを別のShellスクリプトに定義し、Terraformの環境変数をShellスクリプトに渡す方法の説明です。必要に応じて変更や追加を行い、自分の環境に合わせてください。