0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【入門】TerraformでAWSにWeb三層アーキテクチャを作る

Posted at

はじめに

本記事では、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をインストールされている方は以下のコマンドからインストールできます

AWS CLIのインストール
$ brew install awscli

Terraformのインストール

以下の公式ドキュメントを参考にインストール
Install Terraform

homebrewをインストールされている方は以下のコマンドからインストールできます

terraformのインストール
$ brew tap hashicorp/tap
$ brew install hashicorp/tap/terraform

AWSのアクセスキーを発行

  1. AWSアカウントと作業用ユーザーを用意
  2. 作業用ユーザーに必要な権限を付与する
  3. 作業用ユーザーの「認証情報>アクセスキー」からアクセスキーを発行する
  4. アクセスキーをメモまたはダウンロードしておく(本当はセキュリティ的に良くないし、悪用されるリスクがあるので絶対に漏洩しないように)

※アクセスキーを使わない方法はこちらの記事を参考にしてください
アクセスキーを使ったaws-cliはもうやめよう!

AWSのcredentialsを設定

「region name」は利用するAWSアカウントのリージョンと合わせてください
ここでは「アジアパシフィック(東京)」の「ap-northeast-1」を使います

credentialsを設定
$ 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

設定が適用されているか確認

credentialsの確認
$ 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グループ作って付与します

configuration.png

ファイルの作成

ディレクトリ構成

以下のファイルを作成してください
今回は機密情報を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アドレスを取得する項目を記述します

main.tf
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でセキュリティグループを設定します

ec2.tf
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_usernamevar.db_passwordと記述することでvariables.tfに書いてある変数の情報を使えます
セキュリティグループにはaws_security_group.db-sg.idを設定します

rds.tf
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通信のみを許可するように設定します

security_groups.tf
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インスタンスを立ち上げるために必要なユーザー名、パスワード変数を定義します

variables:tf
variable "db_username" {
  type      = string
  sensitive = true
}

variable "db_password" {
  type      = string
  sensitive = true
}

terraform.tfvars

ユーザー名、パスワードの実際の値を記述します

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はもうやめよう!

TerraformでAWS構築(Mac編 事前準備〜VPC作成)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?