今回は RDS を構築してみたいと思います。
これまでに、「VPC編」、「terraform.tfvars編」、「EC2編」とやってきましたので、だいたいコツが掴めてきました。
今回は、AuroraMySQL(ver 2.08.1) のクラスター構成(インスタンス2台)でやってみたいと思います。
※EC2を作成するところまでは「EC2編」のものを継承して行います。
Resource
まずは、Terraform の AWS provider ページから、RDS に必要な resource の仕様について目を通します。
DBクラスター作成するために「DBサブネット」「セキュリティグループ」「クラスターパラメータグループ」「DBパラメータグループ」「オプショングループ」を用意します。
全体のファイル構成は以下の通りです。
terraform-aws-test03
|-- .terraform
|-- ec2.tf
|-- key_pair.tf
|-- provider.tf
|-- rds.tf
|-- security_group.tf
|-- subnet.tf
|-- terraform.tfstate.backup
|-- terraform.tfvars
|-- variables.tf
|-- version.tf
|-- vpc.tf
サービス毎にファイルを分けても大丈夫なのでしょうか?と私は疑問に思っていました。
先にネットワークコンポーネントから作成していかないと、EC2 や RDS の構築ができないはずです。
ですが、Terraform のすごいところは、この resource の依存関係を自動的に解決して処理をしてくれることです。
世の中で注目されるのも頷けますね。
DBサブネット作成 count / index / length
DBサブネットを作成するためには、最低でも2つ以上のサブネットが必要です。
そこで、Terraform の cidrsubnet 関数と、count / index / length を使って動的にサブネットを作成します。
構成としては、EC2用のサブネット "subnet_ec2" 1つとDBサブネット用の "subnet_rds" 3つを作成します。
まずは、結論から書きますとこのようになります。
cidrsubnet 関数と、count / index / length
赤くしたところが cidrsubnet 関数と、count / index / length を使用している部分です。
によって、count を使い sabunet を自動的に複数作成することができます。
今回の例では、aws_vpc.vpc.cidr_block = "10.100.0.0/16" としていました。上記の例では、以下のように解釈されます。
# もともとはこうでした。
cidrsubnet(aws_vpc.vpc.cidr_block, 12, count.index + length(aws_subnet.subnet_ec2))
# aws_vpc.vpc.cidr_block = "10.100.0.0/16" です。
cidrsubnet("10.100.0.0/16", 12, count.index + length(aws_subnet.subnet_ec2))
# 1つ目の処理では、 count.index = "1" です。
cidrsubnet("10.100.0.0/16", 12, 1 + length(aws_subnet.subnet_ec2))
# length は要素の個数を表すので、今回は1個です。
cidrsubnet("10.100.0.0/16", 12, 1 + 1)
# 1 + 1 = 2 です。
cidrsubnet("10.100.0.0/16", 12, 2)
# cidrsubnet 関数を参考に計算します。
# 12 という数字は以下を表現しています。
"10.100.0.0/28" "10.100.0.16/28" "10.100.0.32/28" "10.100.0.48/28" ...
# 2 という数字はその中の2番目を表現します。つまり、
"10.100.0.16/28"
# 2つ目の処理では、count.index = "2" ですので、
"10.100.0.32/28"
# 3つ目の処理では、count.index = "3" ですので、
"10.100.0.48/28"
count で作成した Subnet の参照方法
count を使って作成した Subnet は、そのまま aws_subnet.subnet_rds.id とやろうとしても Error となります。
aws_subnet.subnet_rds は内部的には配列になっています。そのため、参照するためには index を指定する必要があります。
それが、DB Subnet を作成する部分に表現されています。
index はゼロから始まるので以下のような指定の仕方になります。
subnet_ids = [
aws_subnet.subnet_rds.0.id,
aws_subnet.subnet_rds.1.id,
aws_subnet.subnet_rds.2.id
]
セキュリティグループ
セキュリティグループはこんな感じです。
security_group.tf
# Security Group
resource "aws_security_group" "public_security_group" {
name = var.aws_public_sg
description = "Twemily EC2 Public Security Group"
vpc_id = aws_vpc.vpc.id
ingress {
description = "SSH"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [var.my_home_ip, var.my_office_ip]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Service = var.aws_tags_service
Owner = var.aws_tags_owner
}
}
resource "aws_security_group" "private_security_group" {
name = var.aws_private_sg
description = "Twemily RDS Private Security Group"
vpc_id = aws_vpc.vpc.id
ingress {
description = "MySQL"
from_port = 3306
to_port = 3306
protocol = "tcp"
security_groups = [
aws_security_group.public_security_group.id
]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Service = var.aws_tags_service
Owner = var.aws_tags_owner
}
}
オプション・パラメータグループ
クラスターパラメータグループは、後で使いやすいように文字コードを "utf8mb4" に揃え、collation を "utf8mb4_bin" に揃えます。
TimeZone もデフォルトは UTC ですので、東京にしています。
DBパラメータグループとオプショングループの設定は特に変更せず、とりあえず作っただけになっています。
rds.tf
# aws_rds_cluster_parameter_group
resource "aws_rds_cluster_parameter_group" "rds_cluster_parameter_group" {
name = var.rds_cluster_parameter_name
family = var.rds_cluster_parameter_family
tags = {
Service = var.aws_tags_service
Owner = var.aws_tags_owner
}
parameter {
name = "character_set_client"
value = var.rds_cluster_parameter_character
apply_method = "immediate"
}
parameter {
name = "character_set_connection"
value = var.rds_cluster_parameter_character
apply_method = "immediate"
}
parameter {
name = "character_set_database"
value = var.rds_cluster_parameter_character
apply_method = "immediate"
}
parameter {
name = "character_set_filesystem"
value = var.rds_cluster_parameter_character
apply_method = "immediate"
}
parameter {
name = "character_set_results"
value = var.rds_cluster_parameter_character
apply_method = "immediate"
}
parameter {
name = "character_set_server"
value = var.rds_cluster_parameter_character
apply_method = "immediate"
}
parameter {
name = "collation_connection"
value = var.rds_cluster_parameter_collation
apply_method = "immediate"
}
parameter {
name = "collation_server"
value = var.rds_cluster_parameter_collation
apply_method = "immediate"
}
parameter {
name = "time_zone"
value = var.rds_cluster_parameter_timezone
apply_method = "immediate"
}
}
# aws_db_parameter_group
resource "aws_db_parameter_group" "db_parameter_group" {
name = var.rds_db_parameter_name
family = var.rds_db_parameter_family
tags = {
Service = var.aws_tags_service
Owner = var.aws_tags_owner
}
}
# aws_db_option_group
resource "aws_db_option_group" "db_option_group" {
name = var.rds_db_option_name
engine_name = var.rds_db_option_engine_name
major_engine_version = var.rds_db_option_major_engine
tags = {
Service = var.aws_tags_service
Owner = var.aws_tags_owner
}
}
以上のところまで書いたところで、Terraform apply を実行しておきました。
AuroraMySQL の構築
さて、いよいよ本丸です。
インスタンスは3台構成としましょう。先ほどの count を使って作ってみます。
Terraform apply からの Error !
さて、緊張の Terraform コマンド実行です。
$ Terraform plan
Plan: 4 to add, 0 to change, 0 to destroy.
$ Terraform apply
Error: error creating RDS DB Instance: InvalidParameterCombination: Cannot find version 5.7.mysql_aurora.2.08.0 for aurora
status code: 400, request id: f3db0ccb-81b9-4e8e-9eaf-84f49e8a6ed6
ふむふむ「Cannot find version 5.7.mysql_aurora.2.08.0 for aurora」バージョンが存在しないだと。。。
もしかして、クラスターからエンジン種別が継承できていないのか?と思い、インスタンス側にも "engine" "engine_version" を指定して再実行してみました。
rds.tf
# aws_rds_cluster_instance
resource "aws_rds_cluster_instance" "rds_cluster_instance" {
count = var.rds_instance_count
identifier = "${var.rds_instance_identifier}-${count.index}"
cluster_identifier = aws_rds_cluster.rds_cluster.cluster_identifier
instance_class = var.rds_instance_class
engine = var.rds_cluster_engine
# 追記
engine_version = var.rds_cluster_engine_version
# 追記
monitoring_interval = 60
db_subnet_group_name = aws_db_subnet_group.db_subnet.name
db_parameter_group_name = aws_db_parameter_group.db_parameter_group.name
copy_tags_to_snapshot = true
performance_insights_enabled = false
tags = {
Service = var.aws_tags_service
Owner = var.aws_tags_owner
}
}
さあ、これでどうでしょうか。
$ Terraform plan
Plan: 3 to add, 0 to change, 0 to destroy.
$ Terraform apply
...
aws_rds_cluster_instance.rds_cluster_instance[2]: Creating...
aws_rds_cluster_instance.rds_cluster_instance[0]: Creating...
aws_rds_cluster_instance.rds_cluster_instance[1]: Creating...
...
Error: error creating RDS DB Instance: InvalidParameterCombination: A MonitoringRoleARN value is required if you specify a MonitoringInterval value other than 0.
status code: 400, request id: 8a57597d-40ee-40a7-9a5f-868d8afc34a1
またまた、Error が出てしまいました。
"monitoring_interval" は IAM Role がないと指定できないようですね。"monitoring_interval = 60" は削除します。
ただ、DBインスタンスは作成されてしまっているようです。
ハマった!
先の画面からインスタンスが『作成中』から全く進みません。取り消すことも出来ません。
そのため、一旦全て削除(terraform destroy)しました。
"monitoring_interval = 60" を削除した状態で再度実行してみます。
では、いきます。
$ Terraform plan
Plan: 21 to add, 0 to change, 0 to destroy.
$ Terraform apply
Apply complete! Resources: 21 added, 0 changed, 0 destroyed.
できました!!
ここまで長かったですね。
接続確認
では、EC2 に接続したのち、mysql コマンドで接続を試みてみましょう。
無事に接続することが出来ました。また、TimeZone も東京時間になっていることを確認しました。
次回は S3 に terraform.tfstate を配置したいと思います。Terraform の output 機能も使ってみたいと思っています。
TerraformRDSMySQL