Terraform - 仕組みと導入部分を簡単にまとめてみる

**「Terraform」** してますか？

とても便利ですよね。クラウド構築するときに GUI 操作することがほとんどなくなりました。しかし、まだ使用し始めて長くないため、全体像がぼんやりしています。
自分のような Terraform 初心者に向けて、サービスの概要を俯瞰できるような情報をまとめます。

## はじめに

Terraform は HashiCorp によって作成された **Infrastructure as Code** を実現するOSSです。
**HCL (Hashicorp Configuration Language)** または optionally JSON によってインフラに関する情報を定義し、様々なクラウドベンダーのサービスを操作することができます。

2014年に v0.0.1 がリリースされ、今日（2019/07/06）現在では、 v0.12.3 がリリースされています。

Terraform を使用し始める前まで私は、**自作のscriptでAWSの構築**をしていましたが、**環境の変更や削除までは自動化することができずに手間が多く**なっていました。
また、 **AWS CloudFormation** も多少は触ってみましたが、**直感的に分かりづらく、なかなか本格利用には至っておりません**でした。

実際に Terraform を利用し始めると、構築・更新・削除が非常に効率的に実施できとても感動しました。
文献も多く、時間を掛けて調べれば痒いところにも手が届く感覚があります。

ただし、**まだまだ初心者には感覚的に分かりづらい**ような情報もあり、**開発チームへの導入・浸透にあたっては、もう少し丁寧な解説情報が必要そう**だと感じています。

こういった背景から、**特に使い始めたころの自分が欲しかったような情報を中心に**まとめてゆきます。

### 書くこと

- Terraform の位置付け
- Terraform が AWS を操作する方法の概要
- Terraform の簡単な実行方法
- Terraform が クラウド操作する大雑把な流れ

### 書かないこと

- 実戦向きの `~.tf` ファイルの書き方
- `terrafirn.tfstate` の backend 設定

## Terraform の概観

### 基本情報

Terraform の基本的な情報を下表にまとめます。

|項目|内容|
|:--|:--|
|提供会社|[HashiCorp](https://www.hashicorp.com/)|
|GitHub|[hashicorp/terraform](https://github.com/hashicorp/terraform)|
|利用形式|ソフトウェア|
|利用可能OS|Windows, macOS, Linux, and more|
|Licnense|[Mozilla Public License v2.0](https://en.wikipedia.org/wiki/Mozilla_Public_License)|
|初期リリース|2014/7/28|
|最新版|2019/6/24|
|実装言語|Go|
|公式サイト|[Terraform by HashiCorp](https://www.terraform.io/)|

### Tags で見るバージョン履歴

[GitHub の Tag情報](https://github.com/hashicorp/terraform/tags) を元に各バージョンのリリース履歴を見ると次のようになっています。

<details><summary>バージョン履歴</summary><div>

|Version|Date|
|:--|:--|
|v0.12.3 11 days ago|
|v0.12.2 23 days ago|
|v0.12.1|5 Jun 2019|
|v0.12.0|23 May 2019|
|v0.12.0-dev20190520H16|21 May 2019|
|v0.11.14|17 May 2019              |
|v0.12.0-rc1|8 May 2019            |
|v0.12.0-beta2|19 Apr 2019         |
|v0.11.13|12 Mar 2019              |
|v0.11.12|9 Mar 2019               |
|v0.12.0-beta1|1 Mar 2019          |
|v0.11.12-beta1|28 Jan 2019        |
|v0.11.11|15 Dec 2018              |
|v0.12.0-alpha4|8 Dec 2018         |
|v0.12.0-alpha3|7 Dec 2018         |
|v0.12.0-alpha2|31 Oct 2018        |
|v0.11.10|23 Oct 2018              |
|v0.12.0-alpha1|20 Oct 2018        |
|v0.11.9|20 Oct 2018               |
|v0.11.9-beta1|16 Oct 2018         |
|v0.11.8|16 Aug 2018               |
|v0.11.7|11 Apr 2018               |
|v0.11.6|6 Apr 2018                |
|v0.11.5|22 Mar 2018               |
|v0.11.4|16 Mar 2018               |
|v0.11.3|1 Feb 2018                |
|v0.11.2|10 Jan 2018               |
|v0.11.1|1 Dec 2017                |
|v0.11.0|17 Nov 2017               |
|v0.11.0-rc1|10 Nov 2017           |
|v0.11.0-beta1|4 Nov 2017          |
|v0.10.8|26 Oct 2017               |
|v0.10.7|3 Oct 2017                |
|v0.10.6|19 Sep 2017               |
|v0.10.5|15 Sep 2017               |
|v0.10.4|7 Sep 2017                |
|v0.10.3|31 Aug 2017               |
|v0.10.2|17 Aug 2017               |
|v0.10.1|16 Aug 2017               |
|v0.10.0|3 Aug 2017                |
|v0.10.0-rc1|20 Jul 2017           |
|v0.10.0-beta2|7 Jul 2017          |
|v0.9.11|4 Jul 2017                |
|v0.9.10|30 Jun 2017               |
|v0.9.9|27 Jun 2017                |
|v0.10.0-beta1|23 Jun 2017         |
|v0.9.8|8 Jun 2017                 |
|v0.9.7|7 Jun 2017                 |
|v0.9.6|26 May 2017                |
|v0.9.5|11 May 2017                |
|v0.9.4|26 Apr 2017                |
|v0.9.3|13 Apr 2017                |
|v0.9.2|28 Mar 2017                |
|v0.9.1|18 Mar 2017                |
|v0.9.0|16 Mar 2017                |
|v0.9.0-beta2|3 Mar 2017           |
|v0.8.8|3 Mar 2017                 |
|v0.9.0-beta1|16 Feb 2017          |
|v0.8.7|16 Feb 2017                |
|v0.8.6|8 Feb 2017                 |
| v0.8.5|27 Jan 2017               |
|v0.8.4|12 Jan 2017                |
|v0.8.3|10 Jan 2017                |
|v0.8.2|22 Dec 2016                |
|v0.8.1|15 Dec 2016                |
|v0.8.0|14 Dec 2016                |
|v0.8.0-rc3|9 Dec 2016             |
|v0.8.0-rc2|3 Dec 2016             |
|v0.7.13|26 Nov 2016               |
|v0.8.0-rc1|24 Nov 2016            |
|v0.7.12|23 Nov 2016               |
|v0.8.0-beta2|17 Nov 2016          |
|v0.7.11|16 Nov 2016               |
|v0.8.0-beta1|12 Nov 2016          |
|v0.7.10|10 Nov 2016               |
|v0.7.9|5 Nov 2016                 |
|v0.7.8|2 Nov 2016                 |
|0.7.7|18 Oct 2016                 |
|v0.7.7|18 Oct 2016                |
|v0.7.6|15 Oct 2016                |
|v0.7.5|7 Oct 2016                 |
|v0.7.4|20 Sep 2016                |
|v0.7.3|5 Sep 2016                 |
|v0.7.2|25 Aug 2016                |
|v0.7.1|20 Aug 2016                |
|v0.7.0|3 Aug 2016                 |
|v0.7.0-rc4|30 Jul 2016            |
|v0.7.0-rc3|16 Jul 2016            |
|v0.7.0-rc2|13 Jun 2016            |
|v0.7.0-rc1|1 Jun 2016             |
|v0.6.16|10 May 2016               |
|v0.6.15|23 Apr 2016               |
|v0.6.14|22 Mar 2016               |
|v0.6.13|16 Mar 2016               |
|v0.6.12|25 Feb 2016               |
|v0.6.11|2 Feb 2016                |
|v0.6.10|28 Jan 2016               |
|v0.6.9|9 Jan 2016                 |
|v0.6.8|3 Dec 2015                 |
|v0.6.7|24 Nov 2015                |
|v0.6.6|24 Oct 2015                |
|v0.6.5|22 Oct 2015                |
|v0.6.4|16 Oct 2015                |
|v0.6.3|12 Aug 2015                |
|v0.6.2|7 Aug 2015                 |
|v0.6.1|21 Jul 2015                |
|v0.6.0|1 Jul 2015                 |
|list  |20 Jun 2015                |
|v0.5.3|2 Jun 2015                 |
|v0.5.1|16 May 2015                |
|v0.5.0|8 May 2015                 |
|v0.4.2|11 Apr 2015                |
|v0.4.1|10 Apr 2015                |
|v0.4.0|3 Apr 2015                 |
|v0.3.7|20 Feb 2015                |
|v0.3.6|7 Jan 2015                 |
|v0.3.5|10 Dec 2014                |
|v0.3.1|22 Oct 2014                |
|v0.3.0|15 Oct 2014                |
|v0.2.2|10 Sep 2014                |
|v0.2.1|1 Sep 2014|
|v0.2.0|29 Aug 2014|
|v0.1.1|6 Aug 2014|
|v0.1.0|29 Jul 2014|

</div></details>

### Terraform と Vagrant

システムの全体像を Terraform よりも使用者が多いであろう **Vagrant** （Terraform と同じく HashiCorp社 が開発しているツール）**と比較してその特徴を**みてみます。

#### Vagrant の仕組み

**Vagrant は PC内に仮想環境を構築**する際によく利用されます。
システムは下図のようになっており、仮想化環境を実現するツール（VirtualBox, Vmware）と Box 、 Vagrantfile の情報を元にローカルPC内に仮想環境を自動で構築してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79222/fafb2783-4bae-df7d-104b-48837cd39008.png)

Vagrant では、**Vagrantfile** に構築対象の仮想環境の情報を記載し、`vagrant` コマンドの実行によって仮想環境の操作を行います。

#### Terraform の仕組み

Terraform も **Vagrant 同様にローカルPCにインストール**して使用します。
Vagrant と異なるのは、**操作によって構築する主な対象が リモートのクラウドサービス**という点です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79222/d7a588ab-115f-a0ba-bf0a-13d1262d91fd.png)

Vagrant の Vagrantfile にあたるのが、図では `main.tf` で示されたファイルです。
特定の作業フォルダ（ Working Directory ）で `terraform init` コマンドを実行し環境を構築して必要な要素を手配し、 `terraform apply` コマンドによって対象のクラウド（Targets）を操作します。

ローカルPC上の Terraform がリモートのクラウドを操作するためには、**対象のクラウドごとに用意された provider ツールを使用する必要**があります。これは、`main.tf` などに設定を記述しておくと、 `terraform init` をした際に自動で `.terraform/plugins/` 配下に用意をしてくれます。

- [Providers - Terraform by HashiCorp](https://www.terraform.io/docs/providers/index.html)

`terraform.tfstate` は、**対象クラウドに適用した最新の設定情報が全て記載されており**、非常に重要なファイルです。特定の設定がなければ作業フォルダ内の特定フォルダ配下に作成されますが、**Backendの設定を行っておくと、AWS S3 などのストレージ領域に保存しておくことができます**。
`terraform.tfstate` には構築した情報が全て詰まっているため、**破損してしまうとクラウド上に構築した対象のリソースを適切に扱うことができなくなってしまいます**。また、**複数人で開発を行う際にリソースが個人のPCの保管されると、効率が非常に悪く**なってしまいます。
こういった理由により、`terraform.tfstate` は `AWS S3` に特定のバケットを作成し、そこに配置するよう設定することが一般的なようです。

```bash:List-1_シンプルなフォルダ構成
.
├── .terraform
│   ├── plugins
│   └── terraform.tfstate
└── main.tf
```
 
## Terraform の導入

概念的な情報だけでは分かりづらいと思うので、Terraform を使用して AWS を操作する方法をまとめます。

### 必要なもの

今回はAWSを操作するので、AWSアカウントが必要です。

- AWSアカウント（クレデンシャル情報：アクセスキー・シークレットキー）
- Terraform
- awscli

### Terraform のインストール

Terraformのインストール方法は色々なサイトで既に紹介されていますので、以下のようなサイトを参照してください。

- [Terraform - CentOS 7 に Terraform をインストールして AWS へ接続 - Qiita](https://qiita.com/anfangd/items/5eac63d77264e796ffb5)
- [Terraformインストール(Windows版) - Qiita](https://qiita.com/miwato/items/b7e66cb087666c3f9583)
- [Installation / インストール - Terraform for さくらのクラウド](https://sacloud.github.io/terraform-provider-sakuracloud/installation/)
- [Download Terraform - Terraform by HashiCorp](https://www.terraform.io/downloads.html)

Windows, macOS, WSL, 仮想環境などにインストールを試してみましたが、基本的にはホストOSにインストールした方が手間取らないです。（仮想環境やWSLはやめた方が良い印象。実際にやってみて手間が多かった。）

### Terraform で VPC を作成してみる

ここからは Terraform で AWS VPC を構築する手順を紹介します。
まずは作業用のフォルダを作成しましょう。

```bash:command
// Terraform の設定情報を配置するフォルダを作成・移動
mkdir terraform-dir && cd $_
```

次に `main.tf` を作成します。

```json:main.tf
# 変数の設定
variable "aws_access_key" {}
variable "aws_secret_key" {}

# Terraform のバージョン指定
terraform {
  required_version = "= 0.12.3"
}

# 変数を利用した provider の設定
provider "aws" {
    version = "= 2.18.0"
    access_key = "${var.aws_access_key}"
    secret_key = "${var.aws_secret_key}"
    region = "ap-northeast-1"
}

# VPC の作成
resource "aws_vpc" "vpc" {
  cidr_block           = "10.0.0.0/16"
  instance_tenancy     = "default"
  enable_dns_support   = "true"
  enable_dns_hostnames = "false"

  tags {
    Name = "vpc_sample"
  }
}
```

`main.tf` の記載内容について理解を深めたい場合は以下のサイトを参照ください。

- [Terraform で変数を使う - Qiita](https://qiita.com/ringo/items/3af1735cd833fb80da75)
- [Resources - Configuration Language - Terraform by HashiCorp](https://www.terraform.io/docs/configuration/resources.html)
- [Terraformのリソースの書き方(resource, data source, variable, output) - 後ろを向いて後退します](http://micpsm.hatenablog.com/entry/2018/12/05/000000)
- [Provider: AWS - Terraform by HashiCorp](https://www.terraform.io/docs/providers/aws/index.html)
- [Terraform Settings - Configuration Language - Terraform by HashiCorp](https://www.terraform.io/docs/configuration/terraform.html)

AWSを操作するために、`access_key` と `secret_key` の情報を記載する必要がありますが、コードにそのまま記載してしまうと git の管理に含まれてしまい、そのまま情報が漏洩する危険があります。
そのため、今回は `variable` を使って変数定義し、 OSの環境変数から入力する方法を取ります。

Terraform では、次のように、 `TF_VAR_` に続いて `変数名` を付け加えた環境変数を設定することで、 `terraform`コマンドの実行時に、自動的に環境変数が読み込まれます。

```bash:command_bash
// bash を使用する場合（OSが macOS, Linux の場合）

export TF_VAR_aws_access_key="AKIAXXXXXXXXXXXXXXXXXX"
export TF_VAR_aws_secret_key="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

echo $TF_VAR_aws_access_key
echo $TF_VAR_aws_secret_key
```

```powershell:command_powershell
// Powershell を使用する場合（OSが Windows の場合）

$env:TF_VAR_aws_access_key="AKIAXXXXXXXXXXXXXXXXXX"
$env:TF_VAR_aws_secret_key="XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
$env:TF_VAR_public_key_path=".\.secret\public"

$env:TF_VAR_aws_access_key;
$env:TF_VAR_aws_secret_key;
$env:TF_VAR_public_key_path;
Get-ChildItem env:
```

ここまで設定できたら、次のコマンドで初期化を行います。

```bash:command
// 初期化
terraform init
```

初期化が成功したら、次のコマンドで ドライ・ラン を実行し、問題なければ 実際にリモートのクラウドサービスの構築を実施します。
例は VPC を作成するだけなのであまり時間は掛かりませんが、 NAT や RDS を構築する際などには数分単位で処理が継続します。

```bash:command
// ドライ・ラン
$ terraform plan

// 適用
$ terraform apply
```

起動が確認できたら、次のコマンドで削除をしてみましょう。

```bash:command
// 削除確認
$ terraform plan -destroy

// 削除
$ terraform destroy
```

### ここまでの解説

VPCを作成し、削除するまでに行ったことを解説します。

#### 作業フォルダの作成と `main.tf` の作成

Terraform がインストールされた状態で、ホストOS内の任意の場所に作業フォルダを作成し、その配下に `main.tf` を作成しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79222/341d746e-4c14-ad14-d850-5d668541d5fc.png)

#### 環境変数の設定

OSのコマンドを使用し、 Terraform が変数として取り出すことの出来る形式で 環境変数を設定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79222/f8d72f14-d530-2073-e02d-01cefbe74064.png)

#### 作業フォルダの初期化

`terraform init`コマンドの実行によって、作業フォルダを初期化すると共に、必要な provider や module を読み込みます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79222/2cfb1c15-8202-2498-e1e6-b89347bab4fa.png)

#### 環境の構築

`terraform apply` によってリモートのクラウド環境を構築します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79222/209c80e8-6aec-4c9d-b7ef-6673a2abe024.png)

#### 環境の破棄

`terraform destroy` によって、構築したクラウド環境を破棄します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79222/1c73d930-7ae8-f415-c9f3-fa9483e2af5e.png)

## おわりに

Terraform を触り始めたときに感じた以下のような疑問を解決出来るように、大雑把ではありますが情報をまとめてみました。

- Terraform はどういうツール？
- Terraform はどうやって動く？
- Terraform の実行に必要なファイルやコマンドは？

これから始める人や、ちょっと触ってみたという人には、多少参考になるのではないでしょうか。

## 次のステップ

より実践的な内容を学びたい人には、以下の書籍がとても参考になると思います。
コード付きで順を追って解説されており、後半部分は応用の効く情報もまとめられております。

1500円という金額ですが、内容的には5000円位出しても買いたいと思うような内容でした。オススメです。

[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79222/14eccb4b-19ae-4cc5-5522-9fd4daa65d2c.png)](https://booth.pm/ja/items/1318735)

> 第1章　はじめに
第2章　インストール
第3章　Terraformの基本
第4章　全体設計
第5章　権限管理
第6章　ストレージ
第7章　ネットワーク
第8章　ロードバランサとDNS
第9章　コンテナオーケストレーション
第10章　バッチ
第11章　鍵管理
第12章　設定管理
第13章　データストア
第14章　デプロイメントパイプライン
第15章　SSHレスオペレーション
第16章　ロギング
第17章　構造化
第18章　Terraformベストプラクティス
第19章　AWSベストプラクティス
第20章　モジュール設計
第21章　落ち穂拾い
第22章　巨人の肩の上に乗る

## 参考

- [Terraform by HashiCorp](https://www.terraform.io/)
- [Terraform (software) - Wikipedia](https://en.wikipedia.org/wiki/Terraform_(software))
- [hashicorp/terraform - GitHub](https://github.com/hashicorp/terraform)
- [HashiCorpのツール「ATLAS」「VAGRANT」「PACKER」「TERRAFORM」](https://www.creationline.com/hashicorp/products)
- [Terraformで始めるInfrastructure as Code - SlideShare](https://www.slideshare.net/jey0taka/terraforminfrastructure-as-code)
- [Terraform v0.7が誘う「Infrastructure as Code」の世界 - さくらのナレッジ](https://knowledge.sakura.ad.jp/5657/)