[Terraform]AWSインフラをコード化してみよう

#はじめに
こんにちは、AWS学習中の者です。

本日はTerraformというツールを使ったAWSインフラのコード化の手順について書いていこうと思います。

筆者自身もまだTerraformを触り始めて日が浅いので間違い等があるかもしれませんがご容赦ください。

#Terraformとは？
Terraformとはインフラのリソースの設定などをコードとして管理することができるツールです。インフラをコード化したファイルさえあればコマンドを打ち込むだけで誰でも同じインフラ環境を構築することができます。コンソールで手作業で作成するのに比べて素早くリソースの作成ができて、手順を間違えるリスクも大幅に減らすことができます。

#下準備
TerraformでAWSのリソースを作成する前に、まずはIAMユーザーの作成とAWS CLIを使えるようにしておきましょう。

「やさしいIAMユーザーの作成方法」
 https://oji-cloud.net/2019/01/10/post-1692/

「AWS CLIのインストール」
　https://qiita.com/yuyj109/items/3163a84480da4c8f402c

それから、作成したインスタンスにログインするためのキーペアを作成しておきましょう。

AWSのEC2マネジメントコンソール
↓
サイドボードの「キーペア」をクリック
↓
右上の「キーペアの作成」クリック

以上の順に操作して新しいキーペアを作成しましょう。
キーペアの設定は以下の通りです。

```html:キーペアの設定
名前：sample_key
プライベートキーの拡張子: .pem
タグ（オプション）：なし
```

ページ右下の「キーペアを作成」を押すと、「設定した名前.pem」というファイルが自動でダウンロードされます。この.pemファイルは作成したEC2インスタンスに接続するために必要であり、非常に重要なものなので無くさないように持っておきましょう。

#Terraformのインストール&下準備
諸々の準備が終わったらいよいよTerraformを使っていきます。
まずはTerraformのインストールをしていきましょう。
筆者はHomebrewを利用してインストールしました。

```html:ターミナル
brew install terraform
```

無事にTerraformのインストールが終了したら適当な場所にTerraformというディレクトリを作成しましょう。以降はここを作業ディレクトリとします。


Terraformディレクトリを作成したらその中にprovider.tfというファイルを作成しましょう。これはTerraformで操作する対象のプロバイダを定義するファイルです。プロバイダとは使用するクラウドサービスのことを指します。今回はAWSを使用するため以下のように記述しましょう。

```terraform:provider.tf
provider "aws" {
    region = "ap-northeast-1" #東京リージョン
    access_key = 〜〜〜〜〜〜　 #IAMユーザ作成時のアクセスキー
    secret_key = 〜〜〜〜〜〜　　　#IAMユーザ作成時のシークレットキー
}
```

access_keyとsecret_keyの部分にはIAMを作成した時のキーを記述しましょう。セキュリティ面が気になる場合はキーをそれぞれ環境変数として設定すると良いかもしれません。


#AWSリソースの作成
それでは実際にAWSのリソースを作成していきます。
Terraformディレクトリの中にsample.tfというファイルを作成しましょう。

今回は@naoki_mochizukiさんの記事「[世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで](https://qiita.com/naoki_mochizuki/items/f795fe3e661a3349a7ce)」を参考にリソースを作成していきたいと思います。こちらの記事の「DB・サーバ構築編」まで読んで頂けると理解がよりスムーズになるかと思います。

今回作成するのは、

・VPC
・サブネット
・インターネットゲートウェイ
・ルートテーブル
・ルート設定
・ルートテーブルとサブネットとの関連付け
・セキュリティーグループ
・EC2インスタンス
・ElasticIP

以上の９つです。

では、完成したsample.tfを以下に示します。

```terraform:Terraform/sample.tf
#VPC
resource "aws_vpc" "VPC_for_sample" {
  cidr_block = "10.0.0.0/16"
  tags = {
    Name = "VPC_for_sample"
  }
}

# サブネット
resource "aws_subnet" "sample_subnet" {
  vpc_id = "${aws_vpc.VPC_for_sample.id}"
  availability_zone = "ap-northeast-1a"
  cidr_block        = "10.0.0.0/24"
  tags = {
    Name = "sample_subnet"
  }
}

# インターネットゲートウェイ
resource "aws_internet_gateway" "Gateway_for_sample" {
  vpc_id = "${aws_vpc.VPC_for_sample.id}"
  tags = {
    Name = "Gateway_for_sample"
  }
}

# ルートテーブル
resource "aws_route_table" "Table_for_sample" {
  vpc_id = "${aws_vpc.VPC_for_sample.id}"
  tags = {
    Name = "Table_for_sample"
  }
}

# ルート設定
resource "aws_route" "Route_for_sample" {
  destination_cidr_block = "0.0.0.0/0"
  route_table_id         = "${aws_route_table.Table_for_sample.id}"
  gateway_id             = "${aws_internet_gateway.Gateway_for_sample.id}"
}

# ルートテーブルとサブネットの関連付け
resource "aws_route_table_association" "sample_association" {
  subnet_id      = "${aws_subnet.sample_subnet.id}"
  route_table_id = "${aws_route_table.Table_for_sample.id}"
}

#セキュリティーグループ
resource "aws_security_group" "sample_SecurityGroup" {
    name = "sample-SecurityGroup"
    ingress {
        from_port = 22
        to_port = 22
        protocol = "tcp"
        cidr_blocks = ["111.217.143.113/32"]
    }
    ingress {
        from_port = 80
        to_port = 80
        protocol = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
    }
    egress {
        from_port = 0
        to_port = 0
        protocol = "all"
        cidr_blocks = ["0.0.0.0/0"]
    }
    vpc_id = "${aws_vpc.VPC_for_sample.id}"
}

#EC2インスタンス
resource "aws_instance" "sample_instance" {
    ami = "ami-0b276ad63ba2d6009"
    instance_type = "t2.micro"
    key_name = "sample_key"
    vpc_security_group_ids = [
      "${aws_security_group.sample_SecurityGroup.id}"
    ]
    associate_public_ip_address = "true"

    root_block_device  {
      volume_type = "gp2"
      volume_size = "8"
    }

    subnet_id = "${aws_subnet.sample_subnet.id}"
    tags = {
        Name = "sample_instance"
    }
}

# ElasticIP
resource "aws_eip" "eip_for_sample" {
    instance = "${aws_instance.sample_instance.id}"
    vpc = true
}
```

コードの細かい解説は省略しますが、コンソールを利用してEC２インスタンスを作成したことがある人なら大体どのようなことをしているのかはお分かり頂けるかもしれません。

#Terraformの初期化〜Terraform applyまで

さて、コードが書き終わったらターミナルからTerraformコマンド使用して実際にAWS上にリソースを作成してみましょう......と言いたいところですが、その前にTerraformの初期化を行う必要があります。ターミナルで下記のコマンドを実行しましょう。

```html:ターミナル
$ Terraform init
```

このコマンドを実行すると、Terraformを動かすのに必要な様々なファイルが作成されます。

初期化が終わったら次はドライランを実行します。
ドライランとは、作成されるリソースに誤りが無いか確認するために行うものです。例えば何か書類を印刷する場合、いきなり印刷するのではなく一度プレビューを確認してから印刷しますよね、ドライランはそれと同じようなものです。

では次のコマンドを使用してドライランを実行しましょう。

```html:ターミナル
$ terraform plan
```

うまくいけば何やら色々表示されて最後の方に次のような一行が現れるかと思います。

```html:ターミナル
Plan: 9 to add, 0 to change, 0 to destroy.
```
これは、「このコードからは9つのリソースが作成される予定ですよ」ということを表しています。この一行が表示されない場合はどこかでエラーが起こっている可能性があります。

（注意！sample.tfをコピペで作成した方はcidr_blocksやamiの値が正しく記述されているかしっかり確認しましょう）

<br>

問題なくドライランが成功したらいよいよ最終段階です。今度こそ実際にAWS上にリソースを作成するコマンドを実行しましょう。

```html:ターミナル
$ terraform apply
```

すると途中で本当に実行するかどうかを聞かれるので、ここは堂々とyesを打ち込んでやりましょう。

```html:ターミナル
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　　　←打ち込む
```

最終的に以下の一行が表示されれば作成完了です。

```html:ターミナル
Apply complete! Resources: 9 added, 0 changed, 0 destroyed.
```

上の文字が表示されたら本当に作成されているかEC2のコンソールに確認しに行きましょう、
うまくいっていればインスタンスが追加されていて、サブネットやElasticIPとの関連付けも完了していると思います。

#おわりに
お疲れ様でした。

Terraformを使うと、これまでコンソールにログインして手作業で作っていたAWS上のリソースがコマンドひとつで作成できるので便利ですね。筆者もまだまだTerraformは使い始めたばかりなのでこれから更に学習を進めていきたいと思います。

ここまで閲覧してくださり、本当にありがとうございました。