はじめに
Terraformって便利ですよね。
サーバ構成や設定をコードで管理するためのツール(IaC:Infrastructure as Code)で、AWS、GCP、Azureを始め、様々なサービスに対応してます。
必要な環境をまとめて構築、変更、削除でき、設定値を変えれば開発環境、ステージング環境、本番環境を同じ構成で作れるので、とても便利です。
使えるようになるとメンテナンス性が飛躍的にアップするので、まずは基本だけでもマスターしましょう
※Linuxのコマンドラインを操作できる方が対象となります。
※各公式サイトのリンクを貼っているので、Mac以外の環境については、そちらをご確認ください
Windowsの場合は、WSL(Windows上でLinuxを動作させる仕組み)を使うといいかもしれません。
https://docs.microsoft.com/ja-jp/windows/wsl/
今回やること
- 事前準備
- Terraformの初期設定
- VPCの作成
事前準備
AWSのアクセスキー、シークレットキーを発行
- AWSのアカウント&作業用ユーザーを用意(手順は割愛します)
- 作業用ユーザーに、構築に必要な権限を付与する(してもらう)
- 作業用ユーザーの「認証情報>アクセスキー」からアクセスキーを発行する
- アクセスキー、シークレットキーをメモまたはダウンロードしておく(※シークレットキーは作成したときしか知ることはできません。必ず控えておきましょう。)
※個人のAWSアカウントでやる場合も、ルートユーザーは使わずに、作業用のユーザーを作成した方がいいです。(必要最小限の権限に絞れるので)
※作業用ユーザーの権限は、よく分からなかったらAdministratorAccess管理ポリシーを付与しておけば大丈夫です。(ルートユーザーではないので)
AWS CLIのインストール
$ curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg"
$ sudo installer -pkg AWSCLIV2.pkg -target /
他の環境へのインストールや詳しい情報はこちら
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-install.html
tfenv(Terraformの管理ツール)のインストール
Terraformはバージョンが変わると、一部、互換性が無い場合があります。自分が作ったものであれば問題ありませんが、他人が作ったものはバージョンが違ったりすることも。
tfenvはバージョンをすぐに切り替えられて便利なので、これを使って進めます。
$ brew install tfenv
他の環境へのインストールや詳しい情報はこちら
https://github.com/tfutils/tfenv
terraformのインストール
$ tfenv install latest
Installing Terraform v0.15.4
Downloading release tarball from https://releases.hashicorp.com/terraform/0.15.4/terraform_0.15.4_darwin_amd64.zip
######################################################################## 100.0%
Downloading SHA hash file from https://releases.hashicorp.com/terraform/0.15.4/terraform_0.15.4_SHA256SUMS
==> Downloading https://ghcr.io/v2/homebrew/core/pcre/manifests/8.44
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/pcre/blobs/sha256:ed9b483538da7bc6559d2e63dd36659736fab9510681661d970d707a18731de4
〜中略〜
All commands have been installed with the prefix "g".
If you need to use these commands with their normal names, you
can add a "gnubin" directory to your PATH from your bashrc like:
PATH="/usr/local/opt/grep/libexec/gnubin:$PATH"
No keybase install found, skipping OpenPGP signature verification
Archive: tfenv_download.xfh6sb/terraform_0.15.4_darwin_amd64.zip
inflating: /usr/local/Cellar/tfenv/2.2.2/versions/0.15.4/terraform
Installation of terraform v0.15.4 successful. To make this your default version, run 'tfenv use 0.15.4'
バージョンを指定してインストールしたいときは、以下のようにinstallの後にバージョンを書いてください。
$ tfenv install 0.12.6
Installing Terraform v0.12.6
Downloading release tarball from https://releases.hashicorp.com/terraform/0.12.6/terraform_0.12.6_darwin_amd64.zip
######################################################################## 100.0%
Downloading SHA hash file from https://releases.hashicorp.com/terraform/0.12.6/terraform_0.12.6_SHA256SUMS
No keybase install found, skipping OpenPGP signature verification
Archive: tfenv_download.Y85qVG/terraform_0.12.6_darwin_amd64.zip
inflating: /usr/local/Cellar/tfenv/2.2.2/versions/0.12.6/terraform
Installation of terraform v0.12.6 successful. To make this your default version, run 'tfenv use 0.12.6'
使うバージョンを指定するため、インストール済みのバージョンを確認します。
$ tfenv list
0.15.4
0.12.6
No default set. Set with 'tfenv use <version>'
バージョン0.15.4 を使うように、useで指定します。
$ tfenv use 0.15.4
Switching default version to v0.15.4
Switching completed
$ tfenv list
* 0.15.4 (set by /usr/local/Cellar/tfenv/2.2.2/version)
0.12.6
awsのcredentialsを設定
※「region name」は、利用するAWSアカウントのリージョンと合わせてください。
https://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-available-regions
ここでは「アジアパシフィック (東京)」の想定で、「ap-northeast-1」を使います。
$ aws configure
AWS Access Key ID [None]: AAAAAAAAAAAAAAAAAAA
AWS Secret Access Key [None]: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Default region name [None]: ap-northeast-1
Default output format [None]: json
$ cat ~/.aws/credentials
[default]
aws_access_key_id = AAAAAAAAAAAAAAAAAAA
aws_secret_access_key = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
実際の開発では開発環境、本番環境などでAWSアカウントを分ける場合が多いので、切り替えられるようにprofileも設定しておきます。(Terraformで環境を切り替えるのに必要です)
$ aws configure --profile dev-user
AWS Access Key ID [None]: BBBBBBBBBBBBBBBBBBB
AWS Secret Access Key [None]: YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
Default region name [None]: ap-northeast-1
Default output format [None]: json
$ cat ~/.aws/credentials
[default]
aws_access_key_id = AAAAAAAAAAAAAAAAAAA
aws_secret_access_key = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[dev-user]
aws_access_key_id = BBBBBBBBBBBBBBBBBBB
aws_secret_access_key = YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
作業場所の用意
ローカルの環境もすっきりさせておきたいので、作業場所を作っておきます。(ディレクトリ名は何でもOKです)
$ mkdir -p ~/work/dev-test-terraform
$ cd ~/work/dev-test-terraform
※ mkdirに-pオプションを付けると、ディレクトリをまとめて作成してくれます。
tfstateファイルの置き場所をS3に用意
tfstateというのは、terraformで構築した情報が入っているファイルです。
S3に置かずローカルだけでもいいのですが、最初からS3に置いた方が、利便性が飛躍的に高まります。複数人での共同作業や、作業PCが壊れることも考えて、最初からS3に置くようにしましょう。
$ aws s3 mb --profile dev-user s3://xxxxxxxx-dev-terraform-tfstate
make_bucket: xxxxxxxx-dev-terraform-tfstate
※S3のバケット名はグローバルで一意な必要があります。すでに使われているものは設定できないので、xxxxxxxx部分を適切に変更してください。
今回はAWS CLIを使ってS3にバケットを作成しました。
AWS CLIは非常に便利なので、使えるようになると、開発作業が楽になります。
[参考] AWS CLIのS3コマンド
https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-services-s3-commands.html
ここまでで、事前準備が終わりです
それでは、Terraformを使ってVPCの構築を行なってみましょう
Terraformを使った構築
ディレクトリ構成
まず、完成イメージから。
ディレクトリのイメージは、以下のようになります。
$ pwd;find . | sort | sed '1d;s/^\.//;s/\/\([^/]*\)$/|--\1/;s/\/[^/|]*/| /g'
/Users/xxxxxxx/work/dev-test-terraform
|--backend.tf
|--dev.tfvars
|--main.tf
|--modules
| |--vpc
| | |--main.tf
| | |--output.tf
| | |--variables.tf
|--provider.tf
(余談ですが)以下のコマンドを使うと、treeコマンドが無くても擬似的にツリー表示ができて便利です。
$ pwd;find . | sort | sed '1d;s/^\.//;s/\/\([^/]*\)$/|--\1/;s/\/[^/|]*/| /g'
.tfファイルの用意
完成イメージに沿って、各.tfファイルを用意します。
main.tf
sourceで.tfファイルの場所を指定します。
ディレクトリ構成に合わせ、今回は「./module/vpc」を指定します。
その他、必要な変数をここで設定してください。
(var.envなど、変数の設定は後で行います)
module "vpc" {
source = "./modules/vpc"
env = var.env
vpc_cidr = var.vpc_cidr
app_name = "test-application"
}
他のリソース(EC2, RDB, Lambda, API Gatewayなど)を増やす場合は、同様にmoduleを増やしていきます。
provider.tf
Terraformで利用するプロバイダー(AWS,GCP,Azure,Datadogなど)を指定します。
今回はAWSの構築を行うので、「aws」を指定します。
「shared_credentials_file」はデフォルトでこの値なので、もし、AWSの認証情報を書いたファイルが別にある場合は、そのパスを設定してください。
また、「profile」で指定した値をcredentialsから読み込みます。(今回は、準備で設定した「dev-user」を使います)
provider "aws" {
region = var.region
profile = var.profile
shared_credentials_file = "~/.aws/credentials"
}
backend.tf
このファイルでは、使用するTerraformのバージョンや.tfstateファイルの置き場所を設定します。
前述のように、Terraformはバージョンによって文法が異なるケースがあります。環境による文法エラーを防ぐため、バージョンは固定しておきましょう。(今回は0.15.4を指定してます)
terraform {
required_version = "0.15.4"
backend "s3" {
region = "ap-northeast-1"
bucket = "xxxxxxxx-dev-terraform-tfstate"
key = "terraform/aws.tfstate"
}
}
dev.tfvars
環境ごとの設定を指定します。
他にもstg.tfvars、prd.tfvarsなども作成することで、ステージング環境や本番環境の値も設定することができます。
※.tfファイルや.tfvarsはGitにプッシュしたり誰かと共有したりする前提で作成してください。
AWSの認証情報やDBのパスワードなど、秘匿情報は環境変数に設定し、構築時にコマンドで環境変数を渡すと、より安全に作業を行えます。
env = "dev"
region = "ap-northeast-1"
profile = "dev-user"
vpc_cidr = "172.31.0.0/16"
VPCのCIDRは、以下の範囲が推奨されているので、いずれかの値を指定してください。
・10.0.0.0/16
・172.31.0.0/16
・192.168.0.0/20
詳しくはこちら
https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/VPC_Subnets.html
modules/vpc/main.tf
VPCを構築するためのresourceを設定します。
lower()を使うと全て小文字にしてくれるので便利です。
#####################################
# VPC Settings
#####################################
resource "aws_vpc" "vpc" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
tags = {
Name = lower("${var.env}-${var.app_name}-vpc")
project = var.app_name
}
}
modules/vpc/variables.tf
ここでは、モジュール内(vpc/main.tf)で使う変数の設定を行います。
直接値を書くこともできますが、ここでは値を空にして、dev.tfvarsで設定した値をmain.tfから受け取ってます。
variable "env" {}
variable "app_name" {}
variable "vpc_cidr" {}
modules/vpc/output.tf
設定されている値を出力し、他のモジュールで使うことができます。
このファイルは空でも大丈夫ですが、今回はvpcのidを出力してみます。
output "vpc_id" {
value = aws_vpc.vpc.id
}
VPCの構築
それでは、TerraformでVPCを構築してみましょう。
まずは初期化コマンドを実行して、AWSを構築する環境を整えます。
terraformの初期化コマンド
「terraform init」を実行します。
$ terraform init
Initializing modules...
- dev-test in modules/vpc
Initializing the backend...
Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing provider plugins...
- Finding latest version of hashicorp/aws...
- Installing hashicorp/aws v3.47.0...
- Installed hashicorp/aws v3.47.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.
これにより、必要なライブラリがインストールされたり、状態を管理する.tfstateファイルが作成されます。
各ファイルの中身は、実際に確認してみるといいと思います。
/Users/xxxxxxx/work/dev-test-terraform
|--.terraform.lock.hcl
|--.terraform
| |--modules
| | |--modules.json
| |--providers
| | |--registry.terraform.io
| | | |--hashicorp
| | | | |--aws
| | | | | |--3.47.0
| | | | | | |--darwin_amd64
| | | | | | | |--terraform-provider-aws_v3.47.0_x5
| |--terraform.tfstate
Workspaceの作成
上記で設定ファイル「dev.tfvars」を作成しました。
TerraformではWorkspaceという機能を使って構成ファイル(.tfstate)を別々に管理できるので、「dev」ワークスペースを作成します。
$ terraform workspace new dev
Created and switched to workspace "dev"!
You're now on a new, empty workspace. Workspaces isolate their state,
so if you run "terraform plan" Terraform will not see any existing state
for this configuration.
このコマンドを実行することで、S3に以下のファイルが作られます。
xxxxxxxx-dev-terraform-tfstate.s3.ap-northeast-1.amazonaws.com / env: / dev / terraform / dev-aws.tfstate
続いて、Workspaceの確認を行います。
$ terraform workspace list
default
* dev
すでにdevが選択されてますね。
もし違うWorkspaceが選択されていたら、以下のコマンドを実行してください。
$ terraform workspace select dev
特に何も出力されないので、再度、「terraform workspace list」コマンドで確認すればOKです。
terraform planコマンドの実行
Terraformの実行環境は整ったので、次は「terraform plan」コマンドを実行してみます。
これは、実際に反映する前に、実行計画を確認できるコマンドです。
文法的に間違っている場合などは、ここでエラーになります。
さて、うまくいくでしょうか。
$ terraform plan -var-file=dev.tfvars
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:
# module.dev-test.aws_vpc.vpc will be created
+ resource "aws_vpc" "vpc" {
+ arn = (known after apply)
+ assign_generated_ipv6_cidr_block = false
+ cidr_block = "172.31.0.0/16"
+ default_network_acl_id = (known after apply)
+ default_route_table_id = (known after apply)
+ default_security_group_id = (known after apply)
+ dhcp_options_id = (known after apply)
+ enable_classiclink = (known after apply)
+ enable_classiclink_dns_support = (known after apply)
+ enable_dns_hostnames = true
+ enable_dns_support = true
+ id = (known after apply)
+ instance_tenancy = "default"
+ ipv6_association_id = (known after apply)
+ ipv6_cidr_block = (known after apply)
+ main_route_table_id = (known after apply)
+ owner_id = (known after apply)
+ tags = {
+ "Name" = "dev-test-application-vpc"
+ "project" = "test-application"
}
+ tags_all = {
+ "Name" = "dev-test-application-vpc"
+ "project" = "test-application"
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Note: You didn't use the -out option to save this plan, so Terraform can't guarantee to take exactly these actions if you run "terraform apply" now.
無事に、作成されるVPCの内容が表示されましたね。
それでは、これから実際にAWSへ反映し、構築してみます。
terraform applyコマンドの実行
先ほどは実行計画を確認するだけでしたが、今度は確認後、「yes」で承認します。
$ terraform apply -var-file=dev.tfvars
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:
# module.dev-test.aws_vpc.vpc will be created
+ resource "aws_vpc" "vpc" {
+ arn = (known after apply)
+ assign_generated_ipv6_cidr_block = false
+ cidr_block = "172.31.0.0/16"
+ default_network_acl_id = (known after apply)
+ default_route_table_id = (known after apply)
+ default_security_group_id = (known after apply)
+ dhcp_options_id = (known after apply)
+ enable_classiclink = (known after apply)
+ enable_classiclink_dns_support = (known after apply)
+ enable_dns_hostnames = true
+ enable_dns_support = true
+ id = (known after apply)
+ instance_tenancy = "default"
+ ipv6_association_id = (known after apply)
+ ipv6_cidr_block = (known after apply)
+ main_route_table_id = (known after apply)
+ owner_id = (known after apply)
+ tags = {
+ "Name" = "dev-test-application-vpc"
+ "project" = "test-application"
}
+ tags_all = {
+ "Name" = "dev-test-application-vpc"
+ "project" = "test-application"
}
}
Plan: 1 to add, 0 to change, 0 to destroy.
Do you want to perform these actions in workspace "dev"?
Terraform will perform the actions described above.
Only 'yes' will be accepted to approve.
Enter a value: yes
module.dev-test.aws_vpc.vpc: Creating...
module.dev-test.aws_vpc.vpc: Still creating... [10s elapsed]
module.dev-test.aws_vpc.vpc: Creation complete after 12s [id=vpc-0308ce2f14a10adfd]
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
terraform applyは成功したようです。
実際にVPCが作成されているか、コンソール画面で確認してみましょう。
VPCが作成されました!
今回はこれで終わりですが、皆さんもVPCの作成ができたでしょうか?
ここまでを理解しておけば他のリソースにも応用できるので、順次追加していこうと思います。
最後に
今回は、TerraformによるAWS構築について、準備からVPCの作成までを行いました。
視覚的に分かりやすくするため、コマンドをそのまま書きましたが、慣れてきたらシェルなどを使って、環境ごとのスクリプトを実行するだけで構築できるようにすることも可能です。
次回はAPI GatewayとLambdaを使った、サーバレスの環境を構築します