TerraformでS3に複数ファイル/フォルダをまとめて上げる方法

# やりたいこと
・ローカルにあるモジュール（複数ファイル/フォルダ）を一括でS3にアップロードしたい

# 前提
・AWSアカウント作成済み
・AWS IAMユーザーを作成し、access_keyとsecret_keyを発行済み
・Terraformインストール済み
・AWS CLIインストール済み
・VSCODEインストール済み
　（お好みのエディターで大丈夫）

# 環境
```
$ terraform -v 
Terraform v1.5.5
on windows_amd64
+ provider registry.terraform.io/hashicorp/aws v5.13.1
```

# 構築リソース
・AWS S3バケット
・そのバケット配下のオブジェクト

# ディレクトリ構成
```
root
  ┣━ www
  ┃  ┗━ src
  ┃     ┗━ css
  ┃        ┗━ test.css
  ┃     ┗━ js
  ┃        ┣━ test1.js
  ┃        ┗━ test2.js
  ┃  ┗━ index.html
  ┣━ main.tf
  ┣━ variables.tf
  ┗━ s3.tf

```
# ソースの中身

### main.tf
main.tfには基本、全体共通で重要な設定、例えば「AWS プロバイダの設定」を書く
```ruby:main.tf
# AWS プロバイダの設定
provider "aws" {
  access_key = var.access_key
  secret_key = var.secret_key
  region     = var.region
}
```

### variables.tf
・variables.tfに全ソース共通の変数を書く
・リージョンは東京にしたが、適宜変更して大丈夫
・access_keyとsecret_keyは事前に発行したやつを使用
```ruby:variables.tf
variable "region" {
  default = "ap-northeast-1"
}

variable "access_key" {
  default = "自分のaccess_key"
}

variable "secret_key" {
  default = "自分のsecret_key"
}

```

### s3.tf

・一つS3バケットを構築し、指定したローカルパス配下のファイル/フォルダをオブジェクトとしてS3へアップロード
・terraformの**for_each**を使うと、forを回すみたいなイメージで一括で指定したパス配下の中身をアップロードしてくれる


```ruby:s3.tf
resource "aws_s3_bucket" "yu-test-20230825" {
  bucket = "yu-test-20230825"
}

resource "aws_s3_bucket_object" "www" {
  #モジュール配下のファイルだけアップロード
  for_each = fileset("./www/", "*")
  #モジュール配下のすべてファイル/フォルダをアップロード
  #for_each = fileset("./www/", "**")
  bucket = aws_s3_bucket.s3.id
  key = "./www/${each.value}"
  source = "./www/${each.value}"
  #ローカルにあるリソースを修正すると、AWS側も連動で更新する
  etag = filemd5("./www/${each.value}")
}
```

# モジュール配下のファイルだけアップロード

今回はterraformでS3バケットを作成し、ローカルにある静的ホスティング用のモジュールをアップロードしたいと思う

早速用意したs3.tfを実行しよう～

```
terraform plan 
```
二つのリソースを実行計画にaddしてくれたそうです～
```ruby:実行結果
Plan: 2 to add, 0 to change, 0 to destroy.
```
次に、AWSへデプロイ
```
terraform apply   
```

```ruby:実行結果
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
```
デプロイ結果を確認すると、

あれっ、なんか違う？


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538617/a5c2388c-2c30-d98d-92ba-ddacacffe9a2.png)

さっきのディレクトリ構成をもう一度見ると、www配下のindex.htmlファイルのみ上がってます

```
root
  ┣━ www
  　  ┗━ src
  　    ┗━ css
  　       ┗━ test.css
  　    ┗━ js
  　       ┣━ test1.js
  　       ┗━ test2.js
      ┗━ index.html 　  ← こいつだけ
```

そう！`"*"一個の場合`、指定したパス配下の`ファイルのみ`アップロードする仕様になっているそうです。。。

```
for_each = fileset("./www/", "*")
```

# モジュール配下のすべてファイル/フォルダをアップロード

じゃ、モジュール配下のファイルやフォルダを全部まとめて、ローカルと同じツリー構造でアップロードしたい場合はどうしたらいいか？

*を二つにすれば簡単にできるよ！

`"**"二個の場合`、指定したパス配下の`すべての中身`をアップロードしてくれる！

```
for_each = fileset("./www/", "**")
```

```
root
  ┣━ www　↓↓以下全部
  　  ┗━ src
  　    ┗━ css
  　       ┗━ test.css
  　    ┗━ js
  　       ┣━ test1.js
  　       ┗━ test2.js
      ┗━ index.html 　  
```

いったん、先ほど作ったS3を削除して作り直しよう！
```
terraform destroy 
```
```ruby:実行結果
Destroy complete! Resources: 2 destroyed.
```
そして、アスタリスクを二つにしたうえ、実行計画を変更しよう
```
terraform plan 
```
今回はちゃんと5つのリソース（バケット1つとオブジェクト4つ）をaddしてくれたそうです～

```ruby:実行結果
Plan: 5 to add, 0 to change, 0 to destroy.
```
AWSへデプロイしよう
```
terraform apply   
```

```ruby:実行結果
Apply complete! Resources: 5 added, 0 changed, 0 destroyed.
```

AWSを確認すると、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538617/0a116aa1-8aa0-e040-4fea-e5d6f384c941.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538617/99905b34-a587-52e5-d425-ab121b90c651.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3538617/2a104c67-e04f-c25e-698e-cefa4141b465.png)

今度はモジュール配下の全部のファイルやフォルダを一括でまとめてアップロードしてくれた！Good！

# 終わりに
お疲れ様です！今回のやりたいことが無事終わった！
・ローカルにあるモジュール（複数ファイル/フォルダ）を一括でS3にアップロードしたい
　⇒配下のファイルだけアップロードしたい場合は * 一つ、ファイルとフォルダを全部アップロードしたい場合は ** 二つ、っていけばいいよ

# 参考サイト

https://shinbaichi.com/upload-multi-files-for-s3-using-terraform/

https://developer.hashicorp.com/terraform/language/functions/fileset