作りながら覚えるTerraform入門シリーズの第7回です。
今回はRDSをマルチAZ構成で構築していきます。DBエンジンはMySQL8.0で進めていきます。
作りながら覚えるTerraform入門シリーズ
- インストールと初期設定
- 基本編
- VPC編
- EC2編
- Route53 + ACM編
- ELB編
- RDS編 => 今回はコチラ
今回の学習ポイントは・・・
変更を無視するignore_changes
というlifecycle
が登場しますが、RDSを構築する上でのAWS観点でのポイントがいくつかあると思いますので、参考になれば嬉しいです!
サブネットグループの作成
DBインスタンスを作成する前に○○グループを順番に作成していきましょう。
まずは、サブネットグループを作成します。
rds.tf
を作成して、以下のコードを貼り付けます。
################################
# RDS
################################
# Subnet group
resource "aws_db_subnet_group" "subnet" {
name = "${var.prefix}-db-subnet"
subnet_ids = [
aws_subnet.private_subnet_1a.id,
aws_subnet.private_subnet_1c.id
]
}
これはプライベートサブネットのIDを指定しているだけなのでシンプルですね。
パラメータグループの作成
続いて、パラメータグループを作成します。
rds.tf
に以下のコードを追加します。
# Parameter group
resource "aws_db_parameter_group" "mysql" {
name = "${var.prefix}-parameter-group"
family = "mysql8.0"
parameter {
name = "general_log"
value = "1"
apply_method = "immediate"
}
parameter {
name = "slow_query_log"
value = "1"
apply_method = "immediate"
}
parameter {
name = "long_query_time"
value = "0"
apply_method = "immediate"
}
parameter {
name = "log_output"
value = "FILE"
apply_method = "immediate"
}
}
パラメータグループ自体の作成はファミリーを指定するくらいなので難しくありませんが、デフォルトのパラメータのままだとエラーログ以外が出力されないので、一部パラメータを修正しています。
パラメータ | 説明 |
---|---|
general_log | 一般クエリログの出力 |
slow_query_log | スロークエリログの出力 |
long_query_time | スロークエリログを出力する秒数のしきい値 |
log_output | 出力の出力先 |
general_log
とslow_query_log
は「1」を設定してログが出力されるようにしています。
long_query_time
は「0秒」にすることで、重たいクエリを実行せずともログが出力されることを確認できるようにしています。本来は、時間のかかっているクエリを特定するために出力するログですが、ここでは単に「ログが出力されること」の動作確認を行うことを目的としています。
log_output
は「FILE」に変更しています。デフォルトは「TABLE」に書き込まれます。
「TABLE」のままであってもコンソール画面からであれば一般クエリログ、スロークエリログ、エラーログを確認できますが、RDS作成時に設定するCloudWatch Logsへのエクスポートができるよう「FILE」に変更しています(TABLEのままだとエクスポートを有効化してもCloudWatch Logsへ転送されません)
整理すると、
- すべてのパラメータがデフォルトのままでもエラーログだけはコンソール画面から確認できる
-
general_log
slow_query_log
を「1」にするとそれぞれのログもコンソール画面から確認できる -
log_output
をFILEにするとテーブルではなくファイルにログが書き込みされる - RDSのログエクスポートを有効にするとファイルとして出力されたログがCloudWatch Logsに転送される
ということになります。
このあたりTerraformあまり関係ありませんが、少しわかりにくいと感じたので補足させて頂きました。
それぞれのパラメータのapply_method
はデフォルトがimmediate
「すぐに適用」なので省略しても構いません。
オプショングループの作成
次は、オプショングループを作成します。
rds.tf
に以下のコードを追加します。
# Option group
resource "aws_db_option_group" "mysql" {
name = "${var.prefix}-option-group"
engine_name = "mysql"
major_engine_version = "8.0"
option {
option_name = "MEMCACHED"
port = "11211"
vpc_security_group_memberships = [aws_security_group.rds_sg.id]
option_settings {
name = "BACKLOG_QUEUE_LIMIT"
value = "1024"
}
option_settings {
name = "BINDING_PROTOCOL"
value = "auto"
}
}
}
こちらもオプショングループ自体の作成はDBエンジン、バージョンを指定するくらいなので難しくありませんが、オプションを追加する場合のサンプルとして「memcached」を追加しています。これ自体に意味はありませんし接続確認もしません。
option_settings{}
の中は省略してもデフォルト値が採用されるので省略できますが、2つだけサンプルで記載しています。コンソール画面で追加する場合の以下の画面のオプション設定に該当します。
モニタリングロールの作成
次に、モニタリングロールを作成します。
モニタリングロールはRDSの「拡張モニタリング」を有効にする場合に必要なIAMロールで、RDS内部のCPU使用率などのメトリクスをCloudWatch Logsに転送するために利用されます。
コンソール画面から作成した場合、「デフォルト」を選択すると「rds-monitoring-role」の名前で自動的にIAMロールが作成されるので、すでに存在しているかもしれません。
ここでは「rds-enhanced-monitoring-role」の名前で新規に作成します。
iam.tf
に以下のコードを追加します。
data "aws_iam_policy" "rds_monitoring_role" {
arn = "arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole"
}
data "aws_iam_policy_document" "rds_monitoring_role" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["monitoring.rds.amazonaws.com"]
}
}
}
resource "aws_iam_role" "rds_monitoring_role" {
name = "rds-enhanced-monitoring-role"
assume_role_policy = data.aws_iam_policy_document.rds_monitoring_role.json
}
resource "aws_iam_role_policy_attachment" "rds_monitoring_role" {
role = aws_iam_role.rds_monitoring_role.name
policy_arn = data.aws_iam_policy.rds_monitoring_role.arn
}
やっていることはEC2編の「IAMロールの作成」と変わりありません。「AmazonRDSEnhancedMonitoringRole」の管理ポリシーをデータソースを使って参照しアタッチしています。
DBインスタンスの作成
最後に、DBインスタンスを作成します。
rds.tf
に以下のコードを追加します。
# DB Instance
resource "aws_db_instance" "mysql" {
engine = "mysql"
engine_version = "8.0.20"
license_model = "general-public-license"
identifier = "${var.prefix}-db-instance"
username = "admin"
password = "password"
instance_class = "db.t3.medium"
storage_type = "gp2"
allocated_storage = 20
max_allocated_storage = 100
multi_az = true
db_subnet_group_name = aws_db_subnet_group.subnet.name
publicly_accessible = false
vpc_security_group_ids = [aws_security_group.rds_sg.id]
port = 3306
iam_database_authentication_enabled = false
name = "cloud"
parameter_group_name = aws_db_parameter_group.mysql.name
option_group_name = aws_db_option_group.mysql.name
backup_retention_period = 7
backup_window = "19:00-20:00"
copy_tags_to_snapshot = true
storage_encrypted = true
performance_insights_enabled = true
performance_insights_retention_period = 7
monitoring_interval = 60
monitoring_role_arn = aws_iam_role.rds_monitoring_role.arn
enabled_cloudwatch_logs_exports = ["error", "general", "slowquery"]
auto_minor_version_upgrade = false
maintenance_window = "Sat:20:00-Sat:21:00"
deletion_protection = false
skip_final_snapshot = true
apply_immediately = false
tags = {
Name = "${var.prefix}-db-instance"
}
lifecycle {
ignore_changes = [password]
}
}
output "rds_endpoint" {
description = "The connection endpoint in address:port format."
value = aws_db_instance.mysql.endpoint
}
DBインスタンスはパラメータが多いですが、コンソール画面から作成する場合の並び順に合わせて記述していますので、画面と見比べながら読んでいくとそれほど難しくはないと思います。
username
password
をべた書きしていますが、変数化してterraform.tfvars
を参照させたほうが良いです。ただ、コードから隠蔽してもterraform.tfstate
には平文で書き込まれてしまいますので、仮のパスワードを設定しておいてあとで変更するのが良さそうです。lifecycle
ブロックのignore_changes
では、Terraform管理下からpassword
を除外して、パスワードが変更されても差分検知されないようにしています。
instance_class
はt3.medium
にしています。
パフォーマンスインサイトを有効にするには一定サイズ以上にする必要があるのでt3.medium
を選択しています。
multi_az = true
を指定してマルチAZ構成にしています。
シングル構成にする場合はfalse
にして、availability_zone
でAZを指定できます。
multi_az = false
availability_zone = "ap-northeast-1a"
enabled_cloudwatch_logs_exports
では「エラーログ」「一般クエリログ」「スロークエリログ」をCloudWatch Logsにエクスポートするようにしています。繰り返しになりますが、前述のパラメータグループでログ出力を有効化し、かつ、log_output
を「FILE」にしておく必要があります。
skip_final_snapshot
はDBインスタンスを削除する時にスナップショットを取得するかどうかの設定です。もしtrue
にして取得する場合はfinal_snapshot_identifier
のパラメータも合わせて指定する必要があります。
output
ブロックではDBインスタンスのエンドポイントを出力させています。
今回の構成では本番環境を意識して、極力、RDSで利用できる機能を網羅できるような形にしています。(本来は削除保護も有効にすべきですが)マルチAZでかつ、db.t3.mediumにしているのでやや高額になりますので注意しましょう。
db.t3.micro
で十分な場合はパフォーマンスインサイトを無効にすればOKですので、以下のように修正してください。
# サイズはt3.micro
instance_class = "db.t3.micro"
# シングルAZ構成
multi_az = false
availability_zone = "ap-northeast-1a"
# パフォーマンスインサイトは無効(コメントアウト or 削除)
# performance_insights_enabled = true
# performance_insights_retention_period = 7
それでは、terraform apply
を実行して、もろもろ作成されていることを確認しましょう。
作成できたら、EC2からmysql
コマンドで接続できることを確認します。
mysql -h cloud02-db-instance.cnio2sb0qm8v.ap-northeast-1.rds.amazonaws.com -u admin -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 23
Server version: 8.0.20 Source distribution
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| cloud |
| information_schema |
| innodb_memcache |
| mysql |
| performance_schema |
| test |
+--------------------+
6 rows in set (0.00 sec)
mysql> exit
また、CloudWatchのロググループを開いて、ログが保存されていることを確認しましょう。
/aws/rds/instance/<db_instance_identifier>/<log_type>
が各種ログのエクスポートで、RDSOSMetrics
がCPU使用率などの拡張モニタリングのログになります。
今回は以上です。
これまで作成したリソースは不要になった時点でdestory
しておきましょう。くれぐれも高額なRDSを起動しっぱなしにしないようにだけご注意ください。CloudWatchのロググループは自動的に削除されないので手動で削除してください。
terraform destroy -auto-approve
まとめ
作りながら覚えるTerraform入門シリーズはひとまず終了ですが、また少し追記するかもしれません。
Terraformには Modules や Workspaces など、まだまだ便利な機能が他にもありますが、今回使用した機能だけでも十分にInfrastructure as Code(IaC)を体験できると思います。
まだまだ学習中の身ですが、悩める初学者の皆さんの参考になれば幸いです。