はじめに
本記事では、Terraformを用いてAWS上に単純なWeb三層アーキテクチャ(Web/APP/DB)を最小構成で設計・コード化します。Web(外部公開)、APP(内部のみ)、DB(APPのみ)という基本的な要件を、EC2(Web/APP)、RDS(DB)、Security Groupの関係で表現します。
実際のアプリケーションのデプロイは扱いません。
事前準備
必要環境
- AWSアカウント
- AWS作業用ユーザー
- AWS CLI
- Terraform
AWS CLIのインストール
以下の公式ドキュメントを参考にインストール
Installing or updating to the latest version of the AWS CLI
homebrewをインストールされている方は以下のコマンドからインストールできます
$ brew install awscli
Terraformのインストール
以下の公式ドキュメントを参考にインストール
Install Terraform
homebrewをインストールされている方は以下のコマンドからインストールできます
$ brew tap hashicorp/tap
$ brew install hashicorp/tap/terraform
AWSのアクセスキーを発行
- AWSアカウントと作業用ユーザーを用意
- 作業用ユーザーに必要な権限を付与する
- 作業用ユーザーの「認証情報>アクセスキー」からアクセスキーを発行する
- アクセスキーをメモまたはダウンロードしておく(本当はセキュリティ的に良くないし、悪用されるリスクがあるので絶対に漏洩しないように)
※アクセスキーを使わない方法はこちらの記事を参考にしてください
アクセスキーを使ったaws-cliはもうやめよう!
AWSのcredentialsを設定
「region name」は利用するAWSアカウントのリージョンと合わせてください
ここでは「アジアパシフィック(東京)」の「ap-northeast-1」を使います
$ aws configure
AWS Access Key ID [None]: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
AWS Secret Access Key [None]: YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
Default region name [None]: ap-northeast-1
Default output format [None]: json
設定が適用されているか確認
$ cat ~/.aws/credentials
[default]
aws_access_key_id = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
aws_secret_access_key = YYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
作業ディレクトリの作成
terraformのコードを配置する作業ディレクトリを作成
$ mkdir -p ~/workspace/test_terraform
$ cd ~/workspace/test_terraform
構成図
今回作成する基盤構成は以下の図になります
フロントエンド用のEC2とバックエンド用のEC2を立ち上げます
DBはPostgresのRDSインスタンスを立ち上げます
セキュリティグループはフロントエンド、バックエンド、データベースの3グループ作って付与します
ファイルの作成
ディレクトリ構成
以下のファイルを作成してください
今回は機密情報をterraform.tfvarsに記載しているのでgitに上げる際は必ずignoreしてください
~/workspace/test_terraform
├── main.tf # プロバイダーの設定と自分のグローバルIPの取得
├── ec2.tf # EC2インスタンスの設定
├── rds.tf # データベースインスタンスの設定
├── security_groups.tf # セキュリティグループの設定
├── variables.tf # 機密情報を読めるようにするための変数
├── terraform.tfvars # postgresのユーザー、パスワードなどの機密情報
└── .gitignore # terraform.tfvarsを除外
main.tf
AWS上に構築するのでプロバイダーの設定とEC2にSSH接続できるように自身のグローバルIPアドレスを取得する項目を記述します
provider "aws" {
profile = "default"
region = "ap-northeast-1"
}
data "http" "my_ip" {
url = "https://ifconfig.me/ip"
}
ec2.tf
フロントエンドサーバー、バックエンドサーバーとして使うEC2インスタンスを設定します
amiはAmazonLinux最新イメージを指定します
instance_typeには低価格のt3.microを指定します
フロントエンドサーバーにはaws_security_group.frontend-sg.idでセキュリティグループを設定します
バックエンドサーバーにはaws_security_group.backend-sg.idでセキュリティグループを設定します
resource "aws_instance" "frontend-server" {
tags = {
Name = "frontend-server"
}
ami = "ami-03852a41f1e05c8e4"
instance_type = "t3.micro"
vpc_security_group_ids = [aws_security_group.frontend-sg.id]
key_name = "terraform-test"
availability_zone = "ap-northeast-1a"
}
resource "aws_instance" "backend-server" {
tags = {
Name = "backend-server"
}
ami = "ami-03852a41f1e05c8e4"
instance_type = "t3.micro"
vpc_security_group_ids = [aws_security_group.backend-sg.id]
key_name = "terraform-test"
availability_zone = "ap-northeast-1a"
}
rds.tf
データベースインスタンスの設定を記述します
instance_classには低価格のdb.t3.microインスタンスを設定します
username、passwordにはvar.db_usernameとvar.db_passwordと記述することでvariables.tfに書いてある変数の情報を使えます
セキュリティグループにはaws_security_group.db-sg.idを設定します
resource "aws_db_instance" "db" {
identifier = "db"
engine = "postgres"
engine_version = "17.6"
instance_class = "db.t3.micro"
allocated_storage = 20
username = var.db_username
password = var.db_password
db_name = "db"
vpc_security_group_ids = [aws_security_group.db-sg.id]
availability_zone = "ap-northeast-1a"
skip_final_snapshot = true
}
security_groups.tf
フロントエンドのセキュリティグループには自分のグローバルIPアドレスからのSSH通信を許可します
HTTP、HTTPS通信はどこからでも許可するように設定します
バックエンドのセキュリティグループにも同じく自分のグローバルIPアドレスからのSSH通信を許可します
フロントエンドセキュリティグループからの8080番のTCP通信を許可するように設定します
データベースのセキュリティグループにはバックエンドセキュリティグループからの5432番のTCP通信のみを許可するように設定します
resource "aws_security_group" "frontend-sg" {
name = "frontend-sg"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["${chomp(data.http.my_ip.response_body)}/32"]
}
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
}
resource "aws_security_group" "backend-sg" {
name = "backend-sg"
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["${chomp(data.http.my_ip.response_body)}/32"]
}
ingress {
from_port = 8080
to_port = 8080
protocol = "tcp"
security_groups = [aws_security_group.frontend-sg.id]
}
}
resource "aws_security_group" "db-sg" {
name = "db-sg"
ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.backend-sg.id]
}
}
variables.tf
DBインスタンスを立ち上げるために必要なユーザー名、パスワード変数を定義します
variable "db_username" {
type = string
sensitive = true
}
variable "db_password" {
type = string
sensitive = true
}
terraform.tfvars
ユーザー名、パスワードの実際の値を記述します
db_username = "<postgres_username>"
db_password = "<postgres_password>"
コマンドの実行
初期化
ファイルを作った後に初期化コマンドを実行します
$ terraform init
Initializing the backend...
Initializing provider plugins...
- Reusing previous version of hashicorp/http from the dependency lock file
- Reusing previous version of hashicorp/aws from the dependency lock file
- Using previously-installed hashicorp/aws v6.25.0
- Using previously-installed hashicorp/http v3.5.0
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.
実行計画の確認
terraformでは何が作られるのか計画を確認する必要があります
$ terraform plan
data.http.my_ip: Reading...
data.http.my_ip: Read complete after 1s [id=https://ifconfig.me/ip]
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:
(中略)
Plan: 6 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.
適用
これを実行すると実際にAWSマネジメントコンソールでインスタンスやセキュリティグループが作られて実行されていることが確認できます
$ terraform apply
data.http.my_ip: Reading...
data.http.my_ip: Read complete after 0s [id=https://ifconfig.me/ip]
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:
Plan: 6 to add, 0 to change, 0 to destroy.
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
aws_security_group.frontend-sg: Creating...
aws_security_group.frontend-sg: Creation complete after 5s [id=sg-0b4df123d70fbf2ca]
aws_security_group.backend-sg: Creating...
aws_instance.frontend-server: Creating...
aws_security_group.backend-sg: Creation complete after 5s [id=sg-0033e989303e3c86e]
aws_security_group.db-sg: Creating...
aws_instance.backend-server: Creating...
aws_security_group.db-sg: Creation complete after 4s [id=sg-08927331a15814b0b]
aws_db_instance.db: Creating...
(中略)
Apply complete! Resources: 6 added, 0 changed, 0 destroyed.
これでインスタンスとセキュリティグループが作成されました
マネジメントコンソールで確認してみると実際につくられていることが確認できます
削除
今回作ったインスタンス・設定を全て削除するときに実行します
EC2やRDSは起動していなくてもストレージ料がかかるので削除することを忘れないようにしてください
$ terraform destroy
data.http.my_ip: Reading...
data.http.my_ip: Read complete after 1s [id=https://ifconfig.me/ip]
aws_security_group.frontend-sg: Refreshing state... [id=sg-0b4df123d70fbf2ca]
aws_security_group.backend-sg: Refreshing state... [id=sg-0033e989303e3c86e]
aws_instance.frontend-server: Refreshing state... [id=i-04e7b1250bc9383ea]
aws_security_group.db-sg: Refreshing state... [id=sg-08927331a15814b0b]
aws_instance.backend-server: Refreshing state... [id=i-0d9a44c3c77f917fd]
aws_db_instance.db: Refreshing state... [id=db-TPRVLYAGZIZBYK724Z4LGHFYKQ]
Terraform used the selected providers to generate the following execution plan. Resource actions
are indicated with the following symbols:
- destroy
Terraform will perform the following actions:
(中略)
Plan: 0 to add, 0 to change, 6 to destroy.
Do you really want to destroy all resources?
Terraform will destroy all your managed infrastructure, as shown above.
There is no undo. Only 'yes' will be accepted to confirm.
Enter a value: yes
aws_db_instance.db: Destroying... [id=db-TPRVLYAGZIZBYK724Z4LGHFYKQ]
aws_instance.backend-server: Destroying... [id=i-0d9a44c3c77f917fd]
aws_instance.frontend-server: Destroying... [id=i-04e7b1250bc9383ea]
(中略)
Destroy complete! Resources: 6 destroyed.
これでインスタンスとセキュリティグループが削除されました
マネジメントコンソールでも実際になくなっていることが確認できます
参考文献
以下の記事が大変参考になりました、ありがとうございます
アクセスキーを使ったaws-cliはもうやめよう!
