【Terraform 再入門】EC2 + RDS によるミニマム構成な AWS 環境をコマンドライン一発で構築してみよう

[ 前置き ] 初心者だけどインフラの構成をコードで管理したい

僕が Amazon Web Services ( 以下、AWS ) を触り始めたのが今から一年ほど前。当時、弊社コーポレートサイトのサーバを間借りしていた当ブログを AWS 上に移管したいというのが動機でした。その頃の学習の跡は以下のエントリにまとめられています。

AWS のマネジメントコンソールはその膨大な機能を上手くまとめた非常に完成度の高い UI をしており、しかも日本語にも対応しているという実にユーザーフレンドリーな GUI です。ちょっとした構成ならば、少し勉強するだけでわりと簡単にインフラを構築することができます ( ※ オレ調べ ) 。

しかしいくら分かりやすい UI とはいえ、設定項目をひとつずつ画面上でポチポチと入力していくのは中々どうして骨が折れるものです。いち Web サービスのインフラとなると小規模でも設定項目の数はそれなりにあるので、一度限りの構築ならともかく何度も作っては壊してを繰り返すとなると人的ミスのリスクもつきまといます。

そこで登場するのが Terraform というわけです。

改めて Terraform とは?

terraform_logo

HashiCorp社が手掛けるオーケストレーションツールのことです。構築したいインフラの構成をテキスト形式のテンプレートファイルに定義し、ターミナルからコマンドを実行するだけでクラウド上に適用 ( 構築 ) が出来てしまいます。

cloudformation_logo

類似するテクノロジーに AWS CloudFormation という AWS 純正のリソース ( サービス ) がありますが、Terraform には CloudFormation と比較して主に以下の様な特徴があります。

  • AWS だけでなく Azure / GoogleCloud / Heroku などのプロバイダー ( プラットフォーム ) にも対応している
  • テンプレート内にコメントを記述することができ、自然な変数参照が可能
    • ※ CloudFormation のテンプレートは JSON 形式なので、そのままではコメントが記述できない
  • Dry-Run 機能によって実際に動かす前に差分を確認することが出来る
  • プラグインがわりと豊富にある ( Vagrant や Packer で実績のあるやつとか )

最新の AWS リソースによっては対応しきれていないというデメリットはありますが、公式のチュートリアルやドキュメントが非常に充実しているのもあって、今からでも習得する価値は充分にあると言えるでしょう。

今回のゴール

【AWS 再入門】EC2 + RDS によるミニマム構成なサーバー環境を構築してみよう と全く同じ構成内容を Terraform で定義・管理し、コマンド一発で構築してみたいと思います。

vpc-minimum-e1428418965131

EC2 インスタンス x 1台、RDS インスタンス x 1台のミニマム構成です。具体的に作成する AWS リソースは以下の通り。

  • VPC
    • Subnet
    • Internet Gateway
    • Route Table
    • Security Group
  • RDS
    • Instance
    • DB Subnet Group
  • EC2
    • Instance
    • Elastic IP

前提条件

  • AWS アカウントを取得済みである
  • EC2 に SSH 接続するためのキーペアを登録済みである
  • Terraform から AWS を操作するためのクレデンシャル情報 ( IAM ) が用意されている
  • Mac 環境である ( Windows 環境の方は適宜読み替えていただく必要があります )

Terraform のインストール

公式サイトからバイナリファイルをダウンロードするか Homebrew からインストールすることが出来ます。なお、2016年9月時点での最新版は 0.7.3 となっております。

公式サイトからダウンロード

公式サイトのダウンロードページ から Mac OS X 64-bit 版 をダウンロードします。Zip ファイルを展開し、terraform ファイルを任意のディレクトリに配置します。今回は /opt/terraform/0.7.3/ というディレクトリを作成して底に配置してみます。配置したらターミナルから簡単に呼び出せるようパスを通します。Zsh をお使いの方は ~/.zshrc 、 Bash をお使いの方は ~/.bash_profile に以下を追記して保存します。


無事にインストールできたか確認してみましょう。ターミナルを起動して以下のコマンドを実行してみます。

$ terraform version
Terraform v0.7.3

このようにバージョン情報が表示されたらインストールは成功です。

Homebrew からインストール

Mac 環境であればこちらの方が何かとお手軽かつ便利なのでオススメです。

$ brew install terraform
==> Downloading https://homebrew.bintray.com/bottles/terraform-0.7.3.el_capitan.bottle.tar.gz
######################################################################## 100.0%
==> Pouring terraform-0.7.3.el_capitan.bottle.tar.gz
==> Caveats
zsh completion has been installed to:
  /usr/local/share/zsh/site-functions
==> Summary
🍺  /usr/local/Cellar/terraform/0.7.3: 3 files, 122.4M

無事にインストールできたか確認してみましょう。

$ terraform version
Terraform v0.7.3

バージョン情報が表示されました。成功ですね。

以前は brew cask install terraform というコマンドでインストールする必要がありましたが、2016年9月現在は brew install terraform でインストールします。

テンプレートファイルの作成

Terraform のインストールが完了したところで、早速 AWS の環境構築をはじめてみるとします。

まずは今回のプロジェクトとなるディレクトリを適当な場所に作成します。

$ mkdir -p path/to/your/directory
$ cd path/to/your/directory

ディレクトリが出来たらそこに Terraform のテンプレートファイルを新規に作成します。ファイルの拡張子は *.tf でファイル名は任意で構いません。Terraform はコマンドを実行するディレクトリにある全ての *.tf ファイルを自動的にテンプレートとして認識してくれます。ひとまず今回は main.tf としましょう。

テンプレートはHCL (HashiCorp Configuration Language) という HashiCorp 製の言語で記述します。文法は JSON と非常によく似ているので1)JSON との互換性もあるみたいです。、学習コストは非常に低いかと思います。

プロバイダーの設定

まずはじめに、どのプロバイダーを使うのかを宣言しなくてはなりません。main.tf に以下のコードを記述します。

provider "aws" {
    access_key = "ACCESS_KEY_HERE"
    secret_key = "SECRET_KEY_HERE"
    region = "ap-northeast-1"
}

Terraform のテンプレートはブロック単位で設定を追加します。今回は AWS を使いますので、 provider ブロックに aws と指定し、その中に AWS のクレデンシャル情報 ( access_key, secret_key ) とリージョン情報 ( region ) を記述します。

クレデンシャル情報をテンプレートファイルから切り出す

クレデンシャル情報はいわゆる ID とパスワードみたいなものなので、テンプレートファイルに直接記述してしまうのは非常に危険です。そのためクレデンシャル情報は環境変数や Terraform の変数を使ってテンプレートファイルの外に切り出して管理するのがセオリーです。

環境変数を使う

Terraform を使って実際にインフラ環境を構築するには terraform コマンドを実行します。つまり、以下の環境変数を設定しておくと terraform コマンド実行時にクレデンシャル情報が自動的に読み込まれるようになります。

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY

こうしておくと先程の provider ブロックに access_keysecret_key を記述する必要がなくなります。

provider "aws" {
    region = "ap-northeast-1"
}

ただし、読者の方によっては複数の AWS アカウントを使い分ける必要があるかもしれません 2)僕も業務用と個人用とで3つほどのアカウントを使い分けています。。その場合は direnv を導入するのがオススメです。ディレクトリ単位で任意の環境変数をフレキシブルにセットすることが出来るので、アカウントを使い分ける度にいちいち手作業で設定しなおさなくて済むようになります。direnv の詳しい解説につきましては以下の公式リポジトリをご参照ください。

Terraform 変数を使う

Terraform の変数は variable ブロックで定義します。記述方法は以下のとおり。

variable "aws_access_key" {}  # 空の変数を定義
variable "aws_secret_key" {}
variable "aws_region" {
    default = "ap-northeast-1"  # デフォルト値を設定
}

こうして定義された変数は以下のようにvar.<変数名>という書式で参照します。また、 ${} の中に変数を記述するとテンプレートリテラルのように文字列の中に変数を展開させて埋め込むことが出来ます。

provider "aws" {
    access_key = "${var.aws_access_key}"
    secret_key = "${var.aws_secret_key}"
    region     = "${var.aws_region}"
}

さて、変数を定義してそれを参照する方法が分かったまではいいですが、値を代入しなくては意味がありません。代入の方法は以下の3通りがあります。

i) Terraform コマンドのオプションで値を渡す。

terraform コマンド実行時に -var ‘<変数名>=<値>’ とオプションを渡すことで変数に値を代入出来ます。

$ terraform apply \
  -var ‘aws_access_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXX’ \
  -var ‘aws_secret_key=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX’
ii) 環境変数で値を渡す

先程もご紹介しましたが、あらかじめ環境変数に設定しておくことでコマンド実行時に自動的に読み込まれるようになります。こちらは direnv を導入すると良いでしょう。

iii) 外部ファイルに値を定義して渡す

terraform.tfvars という名前でファイルを作成し、そこに <変数名> = <値> という形式で記述しておけば環境変数の時と同じように terraform コマンド実行時に自動でこのファイルの中身が読み込まれてそれぞれの変数に代入されます。

aws_access_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
aws_secret_key = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

ファイル名は任意の名前でも構いませんが、terraform.tfvars以外の場合は以下のように terraform コマンドのオプションでファイルを指定します。


Terraform 公式ドキュメントによると、terraform.tfvars を使うことが推奨されていますが、その場合はこのファイルをバージョン管理の対象外にしておく事が重要です。

リソースの設定

いよいよ各種リソースの設定を定義していきます。リソースは resource "<リソースの種類>" "<リソース名>" {} といったブロック形式で定義し、そのブロックの中に各種項目を記述していきます。

リソースの種類ですが、プロバイダーがAWS の場合だと aws_* といった接頭辞があらかじめ Terraform 側で定義されています。VPC なら aws_vpc 、EC2 なら aws_instance、RDS なら aws_db_instance といった感じです。リソース名はユーザーが任意の名前をつけることができます。

VPC の設定

マネジメントコンソール上で作成するときの手順と同様、まずは VPC から設定してきます。今回はこのような構成にします。

Name tag CIDR block Tenancy
tf_vpc 10.0.0.0/16 default

これをテンプレートで表現すると以下のようになります。

resource "aws_vpc" "tf_vpc" {
    cidr_block           = "10.0.0.0/16"
    instance_tenancy     = "default"
    enable_dns_support   = true
    enable_dns_hostnames = true
    tags {
        Name = "tf_vpc"
    }
}

今回はミニマム構成なので設定項目はこれだけですが、その他の項目に関しては以下の公式ドキュメントをご参照ください。

Subnet の設定

今回は EC2 インスタンス ( Web サーバ ) 用、RDS インスタンス ( MySQL ) 用、RDS Multi-AZ 構成用とで計3つを設定します。

Name tag VPC Availability Zone CIIDR block
tf_public_web tf_vpc ap-northeast-1a 10.0.0.0/24
tf_private_db1 tf_vpc ap-northeast-1a 10.0.1.0/24
tf_private_db2 tf_vpc ap-northeast-1c 10.0.2.0/24

このうち tf_public_web をテンプレートで表現してみましょう。以下のようになります。

resource "aws_subnet" "public_web" {
    vpc_id                  = "${aws_vpc.tf_vpc.id}"
    cidr_block              = "10.0.0.0/24"
    availability_zone       = "ap-northeast-1a"
    map_public_ip_on_launch = true
    tags {
        Name = "tf_public_web"
    }
}

注目すべきは vpc_id に指定している値です。Subnet リソースは VPC リソースに依存しているため、VPC の ID を指定しなくてはなりませんが、既存の VPC ならともかく新規で作るとなるとどんな値なのかまだ分かりません。そこで上記のように変数として指定しておくと Terraform が上手い具合に依存関係を解決して適切な値を代入してくれるようになります。

他の二つのリソースも同様にテンプレートで表現してみましょう。

resource "aws_subnet" "private_db1" {
    vpc_id            = "${aws_vpc.tf_vpc.id}"
    cidr_block        = "10.0.1.0/24"
    availability_zone = "ap-northeast-1a"
    tags {
        Name = "tf_private_db1"
    }
}
resource "aws_subnet" "private_db2" {
    vpc_id            = "${aws_vpc.tf_vpc.id}"
    cidr_block        = "10.0.2.0/24"
    availability_zone = "ap-northeast-1c"
    tags {
        Name = "tf_private_db2"
    }
}

Internet Gateway の設定

Internet Gateway は VPC 内のサーバがインターネットと接続するための出入口です。このゲートウェイを設置しなければ、完全にインターネットから遮断された状態となり、VPN 接続のみで利用するような用途のネットワーク(※ 本エントリーの解説範囲外)を構築することができます。

基本的にテンプレートでは依存先となる VPC と Name tag を指定するだけです。

resource "aws_internet_gateway" "gw" {
    vpc_id = "${aws_vpc.tf_vpc.id}"
    tags {
        Name = "tf-gw"
    }
}

Route Table の設定

Route Table は各サブネットに対して仮想的に配置されるルーターのルーティングテーブルのようなものです。Terraform では Route Table そのものを作成するテンプレートブロックと、サブネットと紐付けるテンプレートブロックのそれぞれを定義します。

今回は aws_subnet.public_web がインターネット ( 外界 ) への出口 ( Internet Gateway ) が必要となるので、それ用の Route Table を作成します。

resource "aws_route_table" "public_rtb" {
    vpc_id = "${aws_vpc.tf_vpc.id}"
    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = "${aws_internet_gateway.gw.id}"
    }
    tags {
        Name = "tf_rtb"
    }
}

次にこの Route Table と Subnet の紐付けをテンプレートで定義します。

resource "aws_route_table_association" "public_a" {
    subnet_id      = "${aws_subnet.public_web.id}"
    route_table_id = "${aws_route_table.public_rtb.id}"
}

Security Group の設定

セキュリティグループは、インスタンスの仮想ファイアウォールとして機能し、インバウンドトラフィックとアウトバウンドトラフィックをコントロールします。セキュリティグループは用途に合わせて複数作成しますが、今回は以下の2つを作成します。

  • アプリケーション・サーバー用のセキュリティグループ
    • Internet からの接続 ( 80番 )
    • SSH からの接続 ( 22番 )
    • サーバからインターネットへ接続するための出口 ( 65535 )
  • DB用のセキュリティグループ
    • アプリケーション・サーバーからの接続 ( 3306番 )

それぞれの設定内容は以下の通りです。

アプリケーションサーバ用のセキュリティグループ

Name tag Group name Description VPC
tf_vpc tf_web It is a security group on http of tf_vpc. tf_vpc
Inbound Rules
Type Protocol Port Range Source
SSH (22) TCP (6) 22 0.0.0.0/0
HTTP (80) TCP (6) 80 0.0.0.0/0
Outbound Rules
Type Protocol Port Range Source
All Traffic TCP (6) ALL ( 65535 ) 0.0.0.0/0

DB サーバ用のセキュリティグループ

Name tag Group name Description VPC
tf_vpc tf_db It is a security group on db of tf_vpc. tf_vpc
Inbound Rules
Type Protocol Port Range Source
MySQL ( 3306 ) TCP ( 6 ) 3306 DB サーバ用のセキュリティグループ ID

これらをテンプレートで表現してみましょう。まずはアプリケーションサーバから。

resource "aws_security_group" "app" {
    name        = "tf_web"
    description = "It is a security group on http of tf_vpc"
    vpc_id      = "${aws_vpc.tf_vpc.id}"
    tags {
        Name = "tf_web"
    }
}
resource "aws_security_group_rule" "ssh" {
    type              = "ingress"
    from_port         = 22
    to_port           = 22
    protocol          = "tcp"
    cidr_blocks       = ["0.0.0.0/0"]
    security_group_id = "${aws_security_group.app.id}"
}
resource "aws_security_group_rule" "web" {
    type              = "ingress"
    from_port         = 80
    to_port           = 80
    protocol          = "tcp"
    cidr_blocks       = ["0.0.0.0/0"]
    security_group_id = "${aws_security_group.app.id}"
}
resource "aws_security_group_rule" "all" {
    type              = "egress"
    from_port         = 0
    to_port           = 65535
    protocol          = "tcp"
    cidr_blocks       = ["0.0.0.0/0"]
    security_group_id = "${aws_security_group.app.id}"
}

セキュリティグループの概要はaws_security_group ブロックで定義し、Inbound Rules を aws_security_group_rule ブロックで定義します。そして忘れてはいけないのが Outbound Rules です。マネジメントコンソール上から作成すると自動で ALL Traffic なルールが適用されますが、Terraform から作成する場合は明示的に Outbound Rule を指定しなくてはなりません3)僕はこれに気が付かなくて半日はかり躓きました…。

DB サーバ用も同様にテンプレートで表現してみましょう。

resource "aws_security_group" "db" {
    name        = "db_server"
    description = "It is a security group on db of tf_vpc."
    vpc_id      = "${aws_vpc.tf_vpc.id}"
    tags {
        Name = "tf_db"
    }
}
resource "aws_security_group_rule" "db" {
    type                     = "ingress"
    from_port                = 3306
    to_port                  = 3306
    protocol                 = "tcp"
    source_security_group_id = "${aws_security_group.app.id}"
    security_group_id        = "${aws_security_group.db.id}"
}

基本的にアプリケーションサーバのそれと殆ど同じですが、こちらはアプリケーションサーバ用セキュリティグループからのアクセスを許可するために source_security_group_id を指定しています。

DB Subnet Group の設定

RDS から VPC を利用するために設定します。

resource "aws_db_subnet_group" "main" {
    name        = "tf_dbsubnet"
    description = "It is a DB subnet group on tf_vpc."
    subnet_ids  = ["${aws_subnet.private_db1.id}", "${aws_subnet.private_db2.id}"]
    tags {
        Name = "tf_dbsubnet"
    }
}

以上で VPC 関連の設定は完了です。残りは DB サーバとアプリケーションサーバの設定です。

DB サーバの設定

特別難しく考える必要はなく、マネジメントコンソールの画面上から設定する値を素直にテンプレートに表現するだけで OK です。

resource "aws_db_instance" "db" {
    identifier              = "tf_dbinstance"
    allocated_storage       = 5
    engine                  = "mysql"
    engine_version          = "5.6.27"
    instance_class          = "db.t1.micro"
    storage_type            = "gp2"
    username                = "${var.aws_db_username}"
    password                = "${var.aws_db_password}"
    backup_retention_period = 1
    vpc_security_group_ids  = ["${aws_security_group.db.id}"]
    db_subnet_group_name    = "${aws_db_subnet_group.main.name}"
}

DB のユーザー名とパスワードは、クレデンシャル情報と同様 variable ブロックで変数を定義し、値を terraform.tfvars に定義しておきます。

variable "aws_db_username" {}
variable "aws_db_password" {}
aws_db_username = "root"
aws_db_password = "hogefuga"

アプリケーションサーバの設定

EC2 インスタンスの構成をテンプレートに表現します。今回はお手軽に Amazon Linux AMIt2.micro で使用するとします。

resource "aws_instance" "web" {
    ami                         = "ami-374db956"  # 東京リージョンにある Amazon Linux AMI の ID を指定する
    instance_type               = "t2.micro"
    key_name                    = "${var.aws_key_name}"  # EC2 に登録済の Key Pairs を指定する
    vpc_security_group_ids      = ["${aws_security_group.app.id}"]
    subnet_id                   = "${aws_subnet.public_web.id}"
    associate_public_ip_address = "true"
    root_block_device = {
        volume_type = "gp2"
        volume_size = "20"
    }
    ebs_block_device = {
        device_name = "/dev/sdf"
        volume_type = "gp2"
        volume_size = "100"
    }
    tags {
        Name = "tf_instance"
    }
}

ami の値はインスタンスのOS の種類ではなく AMI の ID 値であることに注意です。ID はマネジメントコンソールでインスタンスを生成する際に AMI を選択する画面で確認することが出来ます。

EC2 インスタンスに SSH 接続するためのキーペア名はクレデンシャル情報と同様 variable ブロックで変数を定義し、値を terraform.tfvars に定義しておくのが良いでしょう。

variable "aws_key_name" {}
aws_key_name = "xxxxxxxxxxxxxxxxxxx"

Elastic IP の設定

EC2 インスタンスに紐付けるための固定 IP を設定します。

resource "aws_eip" "web" {
  instance = "${aws_instance.web.id}"
  vpc      = true
}

単一のインスタンスに紐付けるだけの簡単な構成なので、特に難しいところはありません。

アウトプット

例えば EC2 インスタンスに紐付けた Elastic IP ( 固定 IP ) の値などインフラ構築完了後に各種リソースに割り当てられた属性値を知りたい場合があります。マネジメントコンソールを開けば確認出来ることですが、テンプレートに output ブロックを記述することで terraform コマンド実行時に指定した値がコンソール上に出力されるようになります。

output "elastic_ip_of_web" {
    value = "${aws_eip.web.public_ip}"
}

構文は至って簡単で、output "<アウトプットしたい属性の説明>" { value = "<アウトプットする属性値>" } と書きます。

Dry-Run ( 実行計画 )

ようやくテンプレートが完成しましたが、いきなりクラウド上にインフラを構築する前に作成したテンプレートに誤りが無いか、テンプレートを適用した結果期待通りのリソースが作成されるかどうかを確認しておくとします。テンプレートのあるディレクトリで terraform planを実行するとテンプレートの実行計画が確認出来ます。

$ terraform plan
Refreshing Terraform state in-memory prior to plan...
⋮
+ aws_instance.exampleInstance
    ami:                                               "ami-374db956"
    associate_public_ip_address:                       "true"
    availability_zone:                                 "<computed>"
    ebs_block_device.#:                                "1"
    ebs_block_device.2659407853.delete_on_termination: "true"
    ebs_block_device.2659407853.device_name:           "/dev/sdf"
    ebs_block_device.2659407853.encrypted:             "<computed>"
    ebs_block_device.2659407853.iops:                  "<computed>"
    ebs_block_device.2659407853.snapshot_id:           "<computed>"
    ebs_block_device.2659407853.volume_size:           "100"
    ebs_block_device.2659407853.volume_type:           "gp2"
⋮
Plan: 16 to add, 0 to change, 0 to destroy.

このようにリソースの属性と一覧が表示されます。先頭に + が付いているのが新規に作成されるリソースで、最終行には「作成 ( add )」「変更 ( change )」「削除 ( destroy )」されるリソースが表示されます。

非常に便利な plan コマンドですが、チェック出来るのは構文エラーやブロック内に設定したパラメータの正誤までで、値そのものの正しさまではチェックすることが出来ません。つまり、存在しない VPC ID や インスタンスの ID などは実行するまで分からないので、ここで拾うことが出来ないのです。

リソースの作成

それではいよいよ実際にテンプレートを適用して AWS 上にリソースを作成してみましょう。terraform applyを実行します。

$ terraform apply
aws_vpc.exampleVPC: Creating...
  cidr_block:                "" => "10.0.0.0/16"
  default_network_acl_id:    "" => "<computed>"
  default_route_table_id:    "" => "<computed>"
  default_security_group_id: "" => "<computed>"
  dhcp_options_id:           "" => "<computed>"
  enable_classiclink:        "" => "<computed>"
  enable_dns_hostnames:      "" => "true"
  enable_dns_support:        "" => "true"
  instance_tenancy:          "" => "default"
⋮
Apply complete! Resources: 16 added, 0 changed, 0 destroyed.
⋮
Outputs:
elastic_ip_of_web = 52.198.91.18

しばらく待った後4)RDS インスタンスの構築があると結構時間がかかります ( 当エントリの構成で約8分程度 ) 。Apply complete! と表示されれば全て成功です。また、実行結果の最後に output で指定した内容 ( EC2 インスタンスのパブリック IP ) が表示されているのが分かります。アウトプットは terraform output コマンドを実行することでいつでも確認することが出来ます。

テンプレートの内容に不備があって実行途中でエラーとなった場合は、その時点でリソース作成が終了します。ただし全て無かったことになるのではなく、作成に成功したリソースはそのまま残ります。その場合はテンプレートを修正して再度実行し直すことで差分のみが作成されます。

作成が完了したら、あとはアプリケーションサーバに SSH 接続して諸々初期設定などを進めていくだけです。そちらにつきましては以下のエントリで既に紹介しておりますので、よろしければご参照ください。

リソースの削除

terraform destroyコマンド一発でテンプレートに定義されているリソース一式を削除することが出来ます。

$ terraform destroy
Do you really want to destroy?
  Terraform will delete all your managed infrastructure.
  There is no undo. Only 'yes' will be accepted to confirm.
  Enter a value: yes
⋮
Destroy complete! Resources: 17 destroyed.

作成の時と同様、非常にお手軽ですね。これなら気軽に Try & Error を繰り返すことが出来ます。

[ 締め ] インフラの仕組みを体系的に把握 & 学べるのがメリット

以上、駆け足になりましたが Terraform の導入から AWS 上にミニマムなインフラ構成を作成するまでの流れをご紹介しました。実際に触れてみて感じたのは、各種サーバやネットワークがどのような関係で成り立っているのかを俯瞰して見ることが出来、それによって本当に必要なことに的を絞って学ぶことが出来るというメリットがあるということです。GUI からひとつずつ値を入力して設定するのは一見分かりやすいですが、どうしても手作業の連続となるためヒューマンエラーというリスクが付きまといます。コードで管理するということはすなわち自動化してヒューマンエラーを未然に防げるということであり、最初の学習コストさえ惜しまなければその後はかなりスムーズにあらゆることを進めることが出来るのではないかと思います。

脚注

脚注
1 JSON との互換性もあるみたいです。
2 僕も業務用と個人用とで3つほどのアカウントを使い分けています。
3 僕はこれに気が付かなくて半日はかり躓きました…。
4 RDS インスタンスの構築があると結構時間がかかります ( 当エントリの構成で約8分程度 ) 。