Help us understand the problem. What is going on with this article?

AWSのEC2とRDSをTerraformで構築する Terraform3分クッキング

はじめに

本記事はAWSのEC2とRDSをTerraformをで構築する方法について記載しています。

terraform applyで実行にかかる時間は、約3分程度です。カップラーメンの待ち時間で構築できます。

デプロイするのは以下の環境(※)になります。また、あわせてEC2は最低限のOSセットアップも行います。

terraform.png

Terraformの基本から入りたい方は、以前書いたOracle Cloudで始めるTerraform 自動化の真骨頂を参照ください。

(※)本記事で記載しているtfファイルはGitHubで公開しています。

Terraform構築

AWS環境におけるTerraformによる構築を行うためには、IAMでユーザ作成を行い、必要なクレデンシャル情報を用意します。あとはTerraformをインストールし、Terraform実行に必要なtfファイルを用意します。

AWS環境の前提条件を以下に記載します。

  • IAMでユーザの作成
  • 必要な権限を付与していること
  • SSHで使用するキーペアを作成していること

tfファイルの作成

tfファイルについて解説します。

はじめに任意の作業ディレクトリに移動します。
本記事では以下のディレクトリ構成になり、カレントディレクトリはcommonディレクトリとします。なお、sshのディレクトリの場所については他のディレクトリでも問題ありません。

  • ディレクトリ構成
.
|-- common
|   |--  userdata
|        |-- cloud-init.tpl
|   |-- ec2.tf
|   |-- env-vars
|   |-- network.tf
|   |-- provider.tf
|   |-- rds.tf
`-- ssh
    |-- id_rsa
    |-- id_rsa.pub
  • 各種ファイル説明
ファイル名 役割
cloud-init.tpl EC2用の初期構築スクリプト
ec2.tf EC2のtfファイル
env-vars プロパイダーで使用する変数のtfファイル
network.tf ネットワークのtfファイル
provider.tf プロパイダーのtfファイル
rds.tf RDSのtfファイル
id_rsa SSH秘密鍵
id_rsa.pub SSH公開鍵
  • env-vars
### Authentication
export TF_VAR_aws_access_key="<access_keyの中身をペースト>"
export TF_VAR_aws_secret_key="<secret_keyの中身をペースト>"

(※)引用符の中にはそれぞれaccess_keyとsecret_keyの中身ををペーストします。

  • provider.tf
# Variable
variable "aws_access_key" {}
variable "aws_secret_key" {}
variable "region" {
    default = "ap-northeast-1"
}

# Provider
provider "aws" {
    access_key = var.aws_access_key
    secret_key = var.aws_secret_key
    region = "ap-northeast-1"
}
  • network.tf
# vpc
resource "aws_vpc" "dev-env" {
    cidr_block = "10.0.0.0/16"
    instance_tenancy = "default"
    enable_dns_support = "true"
    enable_dns_hostnames = "false"
    tags = {
      Name = "dev-env"
    }
}

# subnet
## public
resource "aws_subnet" "public-web" {
    vpc_id = "${aws_vpc.dev-env.id}"
    cidr_block = "10.0.1.0/24"
    availability_zone = "ap-northeast-1a"
    tags = {
      Name = "public-web"
    }
}

## praivate
resource "aws_subnet" "private-db1" {
    vpc_id = "${aws_vpc.dev-env.id}"
    cidr_block = "10.0.2.0/24"
    availability_zone = "ap-northeast-1a"
    tags = {
      Name = "private-db1"
    }
}

resource "aws_subnet" "private-db2" {
    vpc_id = "${aws_vpc.dev-env.id}"
    cidr_block = "10.0.3.0/24"
    availability_zone = "ap-northeast-1c"
    tags = {
      Name = "private-db2"
    }
}

# route table
resource "aws_route_table" "public-route" {
    vpc_id = "${aws_vpc.dev-env.id}"
    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = "${aws_internet_gateway.dev-env-gw.id}"
    }
    tags = {
      Name = "public-route"
    }
}

resource "aws_route_table_association" "public-a" {
    subnet_id = "${aws_subnet.public-web.id}"
    route_table_id = "${aws_route_table.public-route.id}"
}

# internet gateway
resource "aws_internet_gateway" "dev-env-gw" {
    vpc_id = "${aws_vpc.dev-env.id}"
    depends_on = [aws_vpc.dev-env]
    tags = {
      Name = "dev-env-gw"
    }
}
  • ec2.tf
# Security Group
resource "aws_security_group" "public-web-sg" {
    name = "public-web-sg"
    vpc_id = "${aws_vpc.dev-env.id}"
    ingress {
        from_port = 22
        to_port = 22
        protocol = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
    }

    ingress {
        from_port = 80
        to_port = 80
        protocol = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
    }

    egress {
        from_port = 0
        to_port = 0
        protocol = "-1"
        cidr_blocks = ["0.0.0.0/0"]
    }
    tags = {
      Name = "public-web-sg"
    }
}

resource "aws_security_group" "praivate-db-sg" {
    name = "praivate-db-sg"
    vpc_id = "${aws_vpc.dev-env.id}"
    ingress {
        from_port = 5432
        to_port = 5432
        protocol = "tcp"
        cidr_blocks = ["10.0.1.0/24"]
    }

    egress {
        from_port = 0
        to_port = 0
        protocol = "-1"
        cidr_blocks = ["0.0.0.0/0"]
    }
    tags = {
      Name = "public-db-sg"
    }
}

# EC2 Key Pairs
resource "aws_key_pair" "common-ssh" {
  key_name   = "common-ssh"
  public_key = "<公開鍵の中身をペースト>"
}

# EC2
resource "aws_instance" "webserver" {
    ami = "ami-011facbea5ec0363b"
    instance_type = "t2.micro"
    key_name   = "common-ssh"
    vpc_security_group_ids = [
      "${aws_security_group.public-web-sg.id}"
    ]
    subnet_id = "${aws_subnet.public-web.id}"
    associate_public_ip_address = "true"
    ebs_block_device {
      device_name    = "/dev/xvda"
      volume_type = "gp2"
      volume_size = 30
      }
    user_data          = "${file("./userdata/cloud-init.tpl")}"
    tags  = {
        Name = "webserver"
    }
}

# Output
output "public_ip_of_webserver" {
  value = "${aws_instance.webserver.public_ip}"
}

(※)Security Groupで記載しているcidr_blocksは例になります。実際に使用する場合はセキュリティを充分に配慮し、特にSSHは送信元を制限しましょう。

  • rds.tf
# RDS
resource "aws_db_subnet_group" "praivate-db" {
    name        = "praivate-db"
    subnet_ids  = ["${aws_subnet.private-db1.id}", "${aws_subnet.private-db2.id}"]
    tags = {
        Name = "praivate-db"
    }
}

resource "aws_db_instance" "test-db" {
  identifier           = "test-db"
  allocated_storage    = 20
  storage_type         = "gp2"
  engine               = "postgres"
  engine_version       = "11.5"
  instance_class       = "db.t3.micro"
  name                 = "testdb"
  username             = "test"
  password             = "test"
  vpc_security_group_ids  = ["${aws_security_group.praivate-db-sg.id}"]
  db_subnet_group_name = "${aws_db_subnet_group.praivate-db.name}"
  skip_final_snapshot = true
}

(※)passwordの値は例として記載。使用不可な文字列もあります。

  • cloud-init.tpl
#cloud-config

runcmd:
# ホスト名の変更
  - hostnamectl set-hostname webserver

# パッケージのインストール
## セキュリティ関連の更新のみがインストール
  - yum update --security -y

## PostgreSQL client programs
  - yum install -y postgresql.x86_64

# タイムゾーン変更
## 設定ファイルのバックアップ
  - cp  -p /etc/localtime /etc/localtime.org

## シンボリックリンク作成
  - ln -sf  /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

Terraform構築

はじめに、以下の準備作業を行います。

  • 環境変数の有効化
    $ source env-vars
  • 環境変数の確認
    $ env

準備作業完了後、いよいよTerraform構築です。
Terraform構築作業は次の3Stepです!

  1. terraform initで初期化
  2. terraform planで確認
  3. terraform applyで適用

terraformコマンドの説明については割愛します。

terraform apply実行後、Apply complete!のメッセージが出力されると各リソースが作成されます。
 
RDSへはEC2インスタンスからpsqlを実行して接続するか、SSH経由でDBeaverなどのSQLクライアントから接続することができます。

terraform apply

plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_db_instance.test-db will be created
  + resource "aws_db_instance" "test-db" {
      + address                               = (known after apply)
      + allocated_storage                     = 20
      + apply_immediately                     = (known after apply)
      + arn                                   = (known after apply)
      + auto_minor_version_upgrade            = true
      + availability_zone                     = (known after apply)
      + backup_retention_period               = (known after apply)
      + backup_window                         = (known after apply)
      + ca_cert_identifier                    = (known after apply)
      + character_set_name                    = (known after apply)
      + copy_tags_to_snapshot                 = false
      + db_subnet_group_name                  = "praivate-db"
      + endpoint                              = (known after apply)
      + engine                                = "postgres"
      + engine_version                        = "11.5"
      + hosted_zone_id                        = (known after apply)
      + id                                    = (known after apply)
      + identifier                            = "test-db"
      + identifier_prefix                     = (known after apply)
      + instance_class                        = "db.t3.micro"
      + kms_key_id                            = (known after apply)
      + license_model                         = (known after apply)
      + maintenance_window                    = (known after apply)
      + monitoring_interval                   = 0
      + monitoring_role_arn                   = (known after apply)
      + multi_az                              = (known after apply)
      + name                                  = "testdb"
      + option_group_name                     = (known after apply)
      + parameter_group_name                  = (known after apply)
      + password                              = (sensitive value)
      + performance_insights_enabled          = false
      + performance_insights_kms_key_id       = (known after apply)
      + performance_insights_retention_period = (known after apply)
      + port                                  = (known after apply)
      + publicly_accessible                   = false
      + replicas                              = (known after apply)
      + resource_id                           = (known after apply)
      + skip_final_snapshot                   = true
      + status                                = (known after apply)
      + storage_type                          = "gp2"
      + timezone                              = (known after apply)
      + username                              = "test"
      + vpc_security_group_ids                = (known after apply)
    }

/*中略*/

aws_db_instance.test-db: Still creating... [3m0s elapsed]
aws_db_instance.test-db: Creation complete after 3m5s [id=test-db]

Apply complete! Resources: 13 added, 0 changed, 0 destroyed.

Outputs:

public_ip_of_webserver = <IPアドレス(※)>

(※)EC2のパブリックIPが出力されます。

ナレッジ

AWS環境におけるリソース作成時の留意事項について以下に記載します。

  • アベイラビリティゾーン
    RDSの作成は複数のアベイラビリティゾーンの指定が必要です。単一では作成できません。本記事執筆時点で日本リュージョンの場合、以下から2つのアベイラビリティゾーンを指定する必要があります。
zones: ap-northeast-1c, ap-northeast-1a, ap-northeast-1d.
  • terraform destroy実行時にRDSを削除したい場合
    RDSはリソース削除時にデフォルトでスナップショットの作成が求められるため、terraform destroyを行うためにはtfファイルにskip_final_snapshotのオプションをtrueに指定する必要があります。デフォルトはfalse。本番環境で行う場合は注意しましょう。

  • RDSのPostgreSQL仕様
    RDSにおけるPostgreSQLの照合順序及びCtypeのデフォルトは、en_US.UTF-8になっています。性能を考慮する場合はpsqlで接続してdropして再作成した方が良さそうです。

  • OpensshでSSHキーペアを作成した場合
    OpensshでSSHキーペアを作成し、DBeaverなどのSQLクライアントを使用してSSH経由で接続する場合は、鍵の形式を変更する必要があります。

おわりに

以上、Terraform3分クッキング:cooking:でした。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした