知らず知らずのうちに Terraform がディスクをほとんど一杯にしてた

# 1. はじめに
それは突然やってきた。。
MacBook Air で作業中に突然の警告。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/148868/c730d9c7-1f2a-bcf1-5336-b445c7835ba5.png)|
|:-:|

音楽ファイルも動画ファイルも保存してないし、Parallels VMs かなって思って調べたら、terraform ディレクトリがでかい！

<pre>
$ du -sh terraform/
6.5G	terraform/
</pre>

さらに terraform ディレクトリを調べてみたら、terraform-provider-aws_v2.48.0_x4 ファイルは 173MB もある。

<pre>
$ ls -laRh terraform

〜
terraform/anyservice/anyenv/awsconfig/.terraform/plugins/darwin_amd64:
total 354416
drwxr-xr-x  4 nishimura.toru  staff   128B  2 14 20:14 ./
drwxr-xr-x  3 nishimura.toru  staff    96B  2  4 20:16 ../
-rwxr-xr-x  1 nishimura.toru  staff    79B  2 14 20:14 lock.json*
-rwxr-xr-x  1 nishimura.toru  staff   173M  2 14 20:14 terraform-provider-aws_v2.48.0_x4*
〜
</pre>

この terraform-provider-aws_vナンチャラ は、Terraform で AWS を作成・管理・更新するために必要なAWSプロバイダーのプラグインで、terraform init コマンドを実行するとその実行したディレクトリ配下の ".terraform/plugins/" にダウンロードされインストールされる。

私は、Terraform のコンポーネント（tfstateの単位）を 『関心事の分離』 を意識して、次のようにサービス・環境・AWSリソース毎に分けている。
しかも、AWSアカウント毎にこのような terraform ディレクトリを作成している。
そのため、知らず知らずのうちにプラグインファイルが増殖してディスクを食べていたのだ・・・

<pre>
$ tree -L 3 terraform/
terraform/
├── anyservice
│   └── anyenv
│       ├── awsconfig
│       ├── budgets
│       ├── cloudwatchevents
│       ├── cost
│       ├── iam
│       ├── s3
│       └── sns
├── credentials
├── サービス名
│   ├── anyenv
│   │   ├── acm
│   │   └── sns
│   ├── base
│   │   ├── backup
│   │   ├── cloudwatchalarm
│   │   ├── ec2
│   │   ├── eip
│   │   ├── route53_xxx.local
│   │   ├── routetable
│   │   ├── s3
│   │   ├── securitygroup
│   │   ├── subnet
│   │   └── vpc
│   ├── development
│   │   ├── alb
│   │   ├── backup
│   │   ├── cloudwatchalarm
│   │   ├── ec2
│   │   ├── eip
│   │   ├── elasticache
│   │   ├── natgateway
│   │   ├── rds
│   │   ├── route53_xxx.xxx.jp
│   │   ├── s3
│   │   └── securitygroup
│   ├── production
│   │   ├── alb
│   │   ├── backup
│   │   ├── cloudwatchalarm
│   │   ├── ec2
│   │   ├── eip
│   │   ├── elasticache
│   │   ├── natgateway
│   │   ├── rds
│   │   ├── route53_xxx.xxx.jp
│   │   ├── s3
│   │   └── securitygroup
│   ├── staging
│   │   ├── alb
│   │   ├── backup
│   │   ├── cloudwatchalarm
│   │   ├── ec2
│   │   ├── eip
│   │   ├── elasticache
│   │   ├── natgateway
│   │   ├── rds
│   │   ├── route53_xxx.xxx.jp
│   │   ├── s3
│   │   └── securitygroup
├── provider.tf
├── terraform_remote_state.tf
└── variable.tf
</pre>


参考
・ [Terraform Docs: Providers](https://www.terraform.io/docs/providers/index.html)
・ [Terraform Docs: Plugin Installation](https://www.terraform.io/docs/commands/init.html)

# 2. 対処方法
Terraform では、「[Provider Plugin Cache](https://www.terraform.io/docs/configuration/providers.html#provider-plugin-cache)」という機能が用意されていて、無駄なプラグインのダウンロードやインストールを制御することができるようになっている。

>プロバイダープラグインは非常に大きくなる可能性があるため（数百メガバイトのオーダー）、このデフォルトの動作は、低速または従量制のインターネット接続を持つユーザーにとっては不便な場合があります。そのため、Terraformでは、オプションで、ローカルディレクトリを共有プラグインキャッシュとして使用できます。これにより、個別のプラグインバイナリをそれぞれ1回だけダウンロードできます。
（引用： [Provider Plugin Cache](https://www.terraform.io/docs/configuration/providers.html#provider-plugin-cache) google翻訳ママ)


Provider Plugin Cache 機能は、terraform設定ファイルか、環境変数で有効にすることができる。

有効にすると、
>プラグインキャッシュディレクトリが有効になっている場合、terraform initコマンドは引き続きプラグイン配布サーバーにアクセスして、使用可能なプラグインに関するメタデータを取得しますが、適切なバージョンが選択されると、選択したプラグインがキャッシュで既に使用可能かどうかを最初に確認しますディレクトリ。その場合、既にダウンロードされたプラグインバイナリが使用されます。
>選択したプラグインがまだキャッシュにない場合は、最初にキャッシュにダウンロードされ、次にそこから現在の作業ディレクトリの下の正しい場所にコピーされます。
（引用： [Provider Plugin Cache](https://www.terraform.io/docs/configuration/providers.html#provider-plugin-cache) google翻訳ママ)

利用上の注意点は、
>Terraformがプラグインキャッシュに配置されると、プラグインキャッシュから削除されることはありません。時間が経つにつれて、プラグインがアップグレードされると、キャッシュディレクトリにいくつかの未使用バージョンが含まれるようになり、手動で削除する必要があります。
（引用： [Provider Plugin Cache](https://www.terraform.io/docs/configuration/providers.html#provider-plugin-cache) google翻訳ママ)

# 3. 「Provider Plugin Cache」 有効方法

## 3.1. terraform設定ファイル
terraform設定ファイルで有効にする場合は、ユーザーのホームディレクトリ配下に ".terraformrc" ファイルを作成して、下記のようにプラグインをダウンロードするパスを設定する。

$HOME/.terraformrc
<pre>
plugin_cache_dir   = "$HOME/.terraform.d/plugin-cache"
</pre>

※[Terraform Docs の説明例](https://www.terraform.io/docs/configuration/providers.html#provider-plugin-cache)では、".terraform.d"と記載があるが、実際に terraform init を実行すると作成されるディレクトリは".terraform"で作成されるので、「plugin_cache_dir   = "$HOME/.terraform/plugin-cache"」 の方がいいのかな・・

この設定方法では、そのマシン内にあるすべて terraform で AWSプロバイダープラグインを同一バージョンを使用することになる。
Provider Plugin Cache設定を行う前に、事前に AWSプロバイダープラグインのバージョンを合わせておいたほうが良いかも。

## 3.2. 環境変数
Terraform のコンポーネント毎に AWSプロバイダープラグインのバージョンを指定したい場合は、terraform init を実行する前に環境変数で有効にする。

<pre>
export TF_PLUGIN_CACHE_DIR="$HOME/.terraform.d/plugin-cache"
</pre>

この設定方法では、シェルのセッションが終わったら消えてしまう。
いちいち環境変数コマンドを実行するのは萎えるので、direnv などを使ってディレクトリごとに環境変数を設定しておいた方が良さそう。

# 4. Provider Plugin Cache を試してみる
今回は、terraform設定ファイルで Provider Plugin Cache を有効にする方法を試してみた。
Provider Plugin Cache を有効にした後、各Terraformコンポーネントにすでにある .terraform ディレクトリを削除して、terraform init を実行する。

## 4.1. Provider Plugin Cache 設定前の構成・設定確認

* terraformディレクトリ構成

 * $ tree -a terraform/

```
〜
├── anyservice
│   └── anyenv
│       ├── awsconfig
│       │   ├── .terraform
│       │   │   ├── plugins
│       │   │   │   └── darwin_amd64
│       │   │   │       ├── lock.json
│       │   │   │       └── terraform-provider-aws_v2.48.0_x4
│       │   │   └── terraform.tfstate
│       │   ├── backend.tf
│       │   ├── config-rule.tf
│       │   ├── main.tf
│       │   ├── provider.tf -> ../../../provider.tf
│       │   └── terraform_remote_state.tf -> ../../../terraform_remote_state.tf
│       ├── budgets
│       │   ├── .terraform
│       │   │   ├── plugins
│       │   │   │   └── darwin_amd64
│       │   │   │       ├── lock.json
│       │   │   │       └── terraform-provider-aws_v2.45.0_x4
│       │   │   └── terraform.tfstate
│       │   ├── backend.tf
│       │   ├── main.tf
│       │   └── provider.tf -> ../../../provider.tf
│       ├── cloudwatchevents
│       │   ├── .terraform
│       │   │   ├── plugins
│       │   │   │   └── darwin_amd64
│       │   │   │       ├── lock.json
│       │   │   │       └── terraform-provider-aws_v2.47.0_x4
│       │   │   └── terraform.tfstate
│       │   ├── awsconfig.tf
│       │   ├── backend.tf
│       │   ├── health.tf
│       │   ├── provider.tf -> ../../../provider.tf
│       │   └── variable.tf -> ../../../variable.tf
〜
```

* provider.tf ファイル
 * AWSプロバイダーバージョンを 2.48.0 に固定

```
provider "aws" {
  version                 = "2.48.0"
  shared_credentials_file = "../../../credentials"
  profile                 = "terraform"
  region                  = "ap-northeast-1"
}
provider "aws" {
  version                 = "2.48.0"
  shared_credentials_file = "../../../credentials"
  profile                 = "terraform"
  alias                   = "virginia"
  region                  = "us-east-1"
}
```

* backend.tf ファイル （terraform/anyservice/anyenv/awsconfig/backend.tfの例）
 * backendは S3 を利用
 * terraform のバージョンは 0.12.9 以上

```
terraform {
  required_version = ">= 0.12.9"
  backend "s3" {
    shared_credentials_file = "../../../credentials"
    profile                 = "terraform"
    bucket                  = "terraform-tfstate-チョメチョメ"
    key                     = "anyservice/anyenv/awsconfig/terraform.tfstate"
    region                  = "ap-northeast-1"
  }
}
```

* credentials ファイル

<pre>
[terraform]
aws_access_key_id = チョメチョメ
aws_secret_access_key = チョメチョメ
</pre>

* .gitignore ファイル

<pre>
.terraform/
credentials
</pre>

## 4.2. Provider Plugin Cache 設定有効
$HOME/.terraformrc
<pre>
plugin_cache_dir = "$HOME/.terraform.d/plugin-cache"
</pre>

ディレクトリ作成
<pre>
$ mkdir -p $HOME/.terraform.d/plugin-cache
</pre>

## 4.3. Provider Plugin Cache 設定実施

#### 4.3.1. １つ目（初回）
terraform/anyservice/anyenv/awsconfig/.terraform を削除して、terraform init を実行する。

<pre>
$ cd terraform/anyservice/anyenv/awsconfig/
$ rm -rf .terraform/
$ terraform init

Initializing the backend...

Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "aws" (hashicorp/aws) 2.48.0...

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
</pre>プラグインがダウンロードされた
<pre>
$ ls -lh $HOME/.terraform.d/plugin-cache/darwin_amd64/terraform-provider-aws_v2.48.0_x4
-rwxr-xr-x  2 nishimura.toru  staff   173M  2 15 17:29 /Users/nishimura.toru/.terraform.d/plugin-cache/darwin_amd64/terraform-provider-aws_v2.48.0_x4*
</pre>念の為の確認
<pre>
$ terraform plan
</pre>

#### 4.3.2. 2つ目
terraform/anyservice/anyenv/budgets/.terraform を削除して、terraform init を実行する。

実行前の容量確認
<pre>
$ du -sh terraform/
6.5G	terraform/
</pre>実行
<pre>
$ cd terraform/anyservice/anyenv/budgets/
$ rm -rf .terraform/
$ terraform init

Initializing the backend...

Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "aws" (hashicorp/aws) 2.48.0...

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
</pre>念の為の確認
<pre>
$ terraform plan
</pre>実行後の容量確認
<pre>
$ du -sh terraform/
6.3G	terraform/
</pre>減った！

#### 4.3.3. 3つ目
terraform/anyservice/anyenv/cloudwatchevents/.terraform を削除して、terraform init を実行する。

実行<pre>
$ cd terraform/anyservice/anyenv/cloudwatchevents/
$ rm -rf .terraform/
$ terraform init
</pre>念の為の確認
<pre>
$ terraform plan
</pre>実行後の容量確認
<pre>
$ du -sh terraform/
6.2G	terraform/
</pre>減った！

#### 4.3.4. すべての Terraformコンポーネントで実施
実行後の容量確認
<pre>
$ du -sh terraform/
180M	terraform/
</pre>6.5GB が 180MB まで減った！！
AWSプロバイダープラグインの容量が173MBなので、実際の tf ファイルは ７MB くらいか。