TerraformでAWSのVPC環境の構築自動化

 


 

Terraformとは

Terraformは、HashiCorp社によって提供され、環境構築の一連の手順をスクリプトで記述できる

所謂Infrastructure as codeを実現するためのツール群である。

 
TerraformはAWSに特化したツールというわけではなく、

Azure、Google Cloud、OpenStackやVMware vSphereの環境構築にも活用できる。

 
最初、AWSの環境構築自動化をCloudFormationで実現すべくJSONをしこしこ書いていたわけだが、

クライアントの気まぐれにより、Terraformで書き換えることになった。

まあ、これも1つの勉強か。

 

Terraformのインストール

 
インストールというか、ダウンロードして解凍してパス上に配置するだけである。

1、Amazon Linuxを起動してログイン

2、terraformをダウンロードして解凍


$mkdir terraform
$cd terraform
$wget https://releases.hashicorp.com/terraform/0.6.15/terraform_0.6.15_linux_amd64.zip
$unzip terraform_0.6.15_linux_amd64.zip

3、/usr/binの下に配置


$cd ..
$cp terraform /usr/bin/

4、環境変数の設定。PATHと、AWSのアクセスキー、シークレットキー、デフォルトリージョンを設定


$cd
$vim .bash_profile

.bash_profileの内容
[text highlight=”10,14-16″]
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi

# User specific environment and startup programs

PATH=$PATH:$HOME/.local/bin:$HOME/bin:/usr/bin/terraform

export PATH

export AWS_ACCESS_KEY_ID=”AKXXXXXXXXXXXXXXXX”
export AWS_SECRET_ACCESS_KEY=”XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX”
export AWS_DEFAULT_REGION=”ap-northeast-1″
[/text]

5、ホームディレクトリに、Terraformのスクリプトを配置するディレクトリを作成する


$mkdir tf
$cd tf

6、Terraformのスクリプトを作成する(変数編)

Terraformのスクリプト処理で共通的に利用する変数は、

variables.tfファイルに記述する。

[text]
#
# Require User input
variable “aws_key_name” {}
variable “aws_region” {}
variable “aws_vpc_cidr” {}
variable “subnet_dmz1_cidr” {}
variable “subnet_dmz2_cidr” {}
variable “subnet_app1_cidr” {}
variable “subnet_app2_cidr” {}

#
# Change values for your AWS environment
variable “azs” {
default {
“0” = “ap-northeast-1a”
“1” = “ap-northeast-1c”
}
}
[/text]

variable変数で値を定義しない({})場合、

terraform実行時にユーザー入力を求められるプロンプトが表示される。

Availability Zone(azs)は、自身のAWSアカウントに割り当てられた

AZに応じ、配列として定義すること。

 
7、Terraformのスクリプトを作成する(VPC編)

GitHubに上がっているTerraformのサンプルスクリプト(.tf)ファイルは

main.tfに主な処理を書くようにしているが、

作成するオブジェクト(EC2だったり、VPC定義だったり)によってファイルを

分割して配置してもよい。

 
今回はVPCを作成するので、vpc.tfに処理を記述する。

 
vpc.tfの内容。先ずはVPC本体から。
[text]
# VPC
resource “aws_vpc” “main” {
cidr_block = “${var.aws_vpc_cidr}”
tags {
Name = “Sample VPC”
}
}
[/text]

Subnetを定義。variables.tfで定義した変数は、

var.subnet_dmz1_cidrのような形で参照することができる。

[text]
# Subnets
resource “aws_subnet” “dmz1” {
vpc_id = “${aws_vpc.main.id}”
cidr_block = “${var.subnet_dmz1_cidr}”
availability_zone = “${lookup(var.azs, 0)}”

tags {
Name = “DMZ”
}
}

resource “aws_subnet” “dmz2” {
vpc_id = “${aws_vpc.main.id}”
cidr_block = “${var.subnet_dmz2_cidr}”
availability_zone = “${lookup(var.azs, 1)}”

tags {
Name = “DMZ”
}
}

resource “aws_subnet” “app1” {
vpc_id = “${aws_vpc.main.id}”
cidr_block = “${var.subnet_app1_cidr}”
availability_zone = “${lookup(var.azs, 0)}”

tags {
Name = “APP”
}
}

resource “aws_subnet” “app2” {
vpc_id = “${aws_vpc.main.id}”
cidr_block = “${var.subnet_app2_cidr}”
availability_zone = “${lookup(var.azs, 1)}”

tags {
Name = “APP”
}
}
[/text]

 
Internet Gatewayと、S3 Endpointを定義。

[text]
# Internet Gateway
resource “aws_internet_gateway” “igw” {
vpc_id = “${aws_vpc.main.id}”
tags {
Name = “IGW”
}
}

# S3 Endpoint
resource “aws_vpc_endpoint” “s3endpoint” {
vpc_id = “${aws_vpc.main.id}”
service_name = “com.amazonaws.ap-northeast-1.s3”
route_table_ids = [
“${aws_route_table.route_dmz.id}”,
“${aws_route_table.route_app.id}”
]
policy = <<POLICY
{
“Statement”: [
{
“Action”: “*”,
“Effect”: “Allow”,
“Resource”: “*”,
“Principal”: “*”
}
]
}
POLICY
}
[/text]

 
Route Tablesの定義とサブネットとの関連付け

[text]
# Route Tables
resource “aws_route_table” “route_dmz” {
vpc_id = “${aws_vpc.main.id}”
route {
cidr_block = “0.0.0.0/0”
gateway_id = “${aws_internet_gateway.igw.id}”
}
tags {
Name = “route_dmz”
}
}

resource “aws_route_table_association” “route_dmz1_assoc” {
subnet_id = “${aws_subnet.dmz1.id}”
route_table_id = “${aws_route_table.route_dmz.id}”
}

resource “aws_route_table_association” “route_dmz2_assoc” {
subnet_id = “${aws_subnet.dmz2.id}”
route_table_id = “${aws_route_table.route_dmz.id}”
}

resource “aws_route_table” “route_app” {
vpc_id = “${aws_vpc.main.id}”
route {
cidr_block = “0.0.0.0/0”
gateway_id = “${aws_internet_gateway.igw.id}”
}
tags {
Name = “route_app”
}
}

resource “aws_route_table_association” “route_app1_assoc” {
subnet_id = “${aws_subnet.app1.id}”
route_table_id = “${aws_route_table.route_app.id}”
}

resource “aws_route_table_association” “route_app2_assoc” {
subnet_id = “${aws_subnet.app2.id}”
route_table_id = “${aws_route_table.route_app.id}”
}
[/text]

 

Terraformの実行

 

先ずはplanし、エラーがないことを確認。

※いちいちプロンプトに入力するのは面倒だと思うので、

シェル化するとよいでしょう。


/usr/bin/terraform plan \
-var 'aws_key_name=hogehoge-key' \
-var 'aws_region=ap-northeast-1' \
-var 'aws_vpc_cidr=192.168.0.0/16' \
-var 'subnet_dmz1_cidr=192.168.11.0/24' \
-var 'subnet_dmz2_cidr=192.168.12.0/24' \
-var 'subnet_app1_cidr=192.168.21.0/24' \
-var 'subnet_app2_cidr=192.168.22.0/24'

planでエラーが表示されないことを確認したら、

applyしてAWS環境を自動構築しましょう。


/usr/bin/terraform apply \
-var 'aws_key_name=hogehoge-key' \
-var 'aws_region=ap-northeast-1' \
-var 'aws_vpc_cidr=192.168.0.0/16' \
-var 'subnet_dmz1_cidr=192.168.11.0/24' \
-var 'subnet_dmz2_cidr=192.168.12.0/24' \
-var 'subnet_app1_cidr=192.168.21.0/24' \
-var 'subnet_app2_cidr=192.168.22.0/24'

 
環境を削除する時はterraform destroyで。

困ったらドキュメントを読みましょう。

https://www.terraform.io/docs/index.html

 
CloudFormationと比較すると、ネット上の情報も少ない。

ググってもGitHubのコメントとかしか出ないので、

がんばってドキュメントを読むしかない感じ。

ただ、コメントがつけられるのはいいね。JSONより人間にやさしいし。