【Terraform】IaC初心者がterraformに入門してみた

# 【Terraform】IaC初心者がterraformに入門してみた

普段AWSのリソースをデプロイする際にはCloudFormationを利用することが多く、
Terraformについてはあまり触れる機会がありませんでした。

本記事は筆者のようなIaCの初心者がTerraformに入門するまでのステップをまとめ、
同じ様な状況の方が「Terraform使ってみたい！」と思える様になれば、と思いで書きました。

## 想定読者
- IaCに興味がある方、もしくはIaCを始めたい方
- Terraformのメリットがいまいちわからない、という方
- とにかくTerraformを触ってみたい方

## Terraformとは
Terraformは2014年にHashiCorp社が発表したIaCツールの1つです。

最大の特徴はすべてのクラウドに対して単一かつ共通のワークフローを提供しており、
マルチプラットフォーム環境を容易に実現することが可能です。

## なぜTerraformを使うのか？
先述の通り、Terraformを使うメリットはデプロイ先のプラットフォームを選ばないという点です。
Terraformを使えば同じワークフロー、同じ構文で様々なインフラを定義、構築することができます。

　　　　　　　　![fig1.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3880214/4d737886-fb1e-fe17-2a14-64c277a5baae.png)
    

さらに、[HCP Terraform](https://developer.hashicorp.com/terraform/cloud-docs)やTerraform Enterpriseの様なエンタープライズ向けのソリューションも提供されており、ある程度組織やインフラの規模が大きくなっても効率性を失わずに、ベストプラクティスに沿った形で運用することができます。

## とりあえずインストールしてみる

LinuxまたはMacOSを使っている場合はパッケージマネージャーからインストールできるので躓くポイントは特にないはずです。

MacOSの場合は以下。
```
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
```

RedHat系のLinuxなら以下。
```
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
sudo yum install terraform -y
```

VSCodeで開発する場合、以下のプラグインは入れておきましょう。

https://marketplace.visualstudio.com/items?itemName=HashiCorp.terraform

## とりあえず使ってみる
以下の公式チュートリアルをやってみます
（ドキュメントを自分で読みたい方は読み飛ばしてOKです）。
https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-build

まずは、以下のような構成で作業用ディレクトリと.tfファイルを作成します。
```
learn-terraform-aws-instance
 ├── main.tf           # メインのファイル: プロバイダやリソースを宣言する
 ├── variables.tf      # 変数を宣言する
 └── outputs.tf        # 出力を定義する
```
ソースコードは以下の通りです。

https://github.com/OchiShuji/learn-terraform-aws-instance

`ap-northeast-1`に`t3.micro`のEC2インスタンスを1つ定義して
ARNを出力するだけのシンプルなコードです。

ファイルを配置したら、Terraform CLIを使って実際にリソースを適用します。
Terraformは基本的に以下の様なライフサイクルで定義された一連のコマンドに従って動作します。

![fig2.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3880214/8b509baa-10f6-87c3-cdcc-04991916341d.png)

初めに`terraform init`を実行して、作業ディレクトリを初期化します。
（このコマンドは新しいモジュールやプロバイダを追加した際あるいはバージョンを変更した場合に毎回打つ必要があります。）
```sh
% terraform init
Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 4.16"...
- Installing hashicorp/aws v4.67.0...
- Installed hashicorp/aws v4.67.0 (signed by HashiCorp)
Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

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.
```

次に`terraform plan`で実行計画を生成します。
現状のインフラ構成と.tfファイルで定義された構成を比較し、terraformで実行すべきアクションが明示されます。

```sh
% terraform plan
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.app_server will be created
  + resource "aws_instance" "app_server" {
      + ami                                  = "ami-04d3ba818c434b384"
      + arn                                  = (known after apply)
 (中略)
      + root_block_device (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + id = (known after apply)
```

Terraformにより実行されるアクションの詳細が記述されています。
今回は`Plan: 1 to add`と記載されており、想定通りの実行計画となっていることが確認できます。

terraform initとterraform planの実行結果が期待通りであれば、
いよいよterraform applyで構成をデプロイします。

```sh
% terraform apply

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_instance.app_server will be created
  + resource "aws_instance" "app_server" {
      + ami                                  = "ami-04d3ba818c434b384"
      + arn                                  = (known after apply)
（中略）
      + root_block_device (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Changes to Outputs:
  + id = (known after apply)

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_instance.app_server: Creating...
aws_instance.app_server: Still creating... [10s elapsed]
aws_instance.app_server: Creation complete after 13s [id=i-0e775a1fdab9297b7]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

id = "arn:aws:ec2:ap-northeast-1:xxxxxxxxxxxx:instance/i-0e775a1fdab9297b7"
```

リソースの作成に成功しました。
実行結果の末尾にはoutputs.tfで宣言した通りEC2のARNが出力されていることがわかります。

リソースを削除したい場合は`terraform destloy`を実行します。
```
% terraform destroy
```

## 困った時は

プロバイダのドキュメントにはすぐにアクセスできるようにしておきましょう。
AWSなら`terraform aws`と調べたら上の方にドキュメントが出てくるはずです。

https://registry.terraform.io/providers/hashicorp/aws/latest/docs

## まとめ

この記事ではTerraformについて、入門ステップをまとめました。

これまでCloudFormationでいいじゃん！というマインドをどこかで持っていましたが、
実際に使ってみるとyamlよりHCLの方が変数や出力を扱いやすい、Terraformの方が
ワークフローわかりやすい、など様々な利点が見えてきました。

ある程度Terraformに慣れてきたらHCP Terraformなども触ってみようかな、と思います。

## 参考
- Ravi Mishra, Terraformの教科書