こうした声はよく聞きます。RDSはEC2やVPCと比べてリソース間の依存関係が多く、サブネットグループの設定漏れやセキュリティグループの許可ポートミスで apply 直後にエラーになるケースが後を絶ちません。
この記事では、aws_db_instance を中心に、aws_db_subnet_group・aws_db_parameter_group・aws_security_group を組み合わせたRDSのプロビジョニング手順を実践解説します。MySQLを題材に、削除保護・マルチAZ・自動バックアップ・ストレージ暗号化・RDS IAM認証といった本番環境の必須設定も含めてカバーします。
動作確認環境: Terraform 1.8.5 / AWS Provider 5.50.0(ap-northeast-1リージョン、MySQL 8.0.35)
この記事のポイント
・aws_db_instanceの前にサブネットグループとセキュリティグループの定義が必要
・aws_db_parameter_groupで文字コード・タイムゾーン・スロークエリをコードで管理できる
・本番環境ではdeletion_protection=trueとskip_final_snapshot=falseを必ず設定する
・storage_encrypted=trueはインスタンス作成後に変更できないため最初から有効にする
・iam_database_authentication_enabled=trueでパスワード不要のIAM認証接続が実現できる
・lifecycleブロックでパラメータグループの無停止差し替えとエンジンバージョンのdrift防止を両立できる
・apply後はterraform outputとAWS CLIでRDSエンドポイントと稼働状態を必ず確認する
でも安心してください。プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
なぜRDSをTerraformで管理するのか
AWSコンソールからRDSを手作業で構築すると、パラメータグループの設定値・サブネットグループのAZ構成・セキュリティグループのingressルールが別々の画面に散らばります。後からどの設定が本番と開発で異なるのかを把握しにくく、「なぜかstgで動いてprodで動かない」問題の温床になります。Terraformで管理することで次の4つの問題が解消されます。
・設定の再現性:terraform applyを実行すれば同じ構成のRDSを何度でも作れる
・差分の可視化:terraform planでパラメータ変更の影響範囲を事前に確認できる
・レビュー可能性:GitのPRでRDSの設定変更をチームでレビューできる
・ドリフト検出:コンソールからの手動変更をterraform planで即座に検知できる
「コンソールで急いでパラメータを変更したがコードに反映し忘れた」——この状態をTerraformは自動的に検知してくれます。次のapplyでコンソールの手動変更が上書きされてしまうため、設定変更はすべてコードを通す習慣が自然と身につきます。
既存のRDSをTerraform管理下に取り込む場合は terraform import を使います。新規にVPCから構築する手順はTerraformでVPCとEC2を構築する記事を先に参照してください。RDSはリソース間の依存関係が明確に決まっているため、作成順序を把握しておくことが安定した apply の前提条件になります。依存関係を図で確認してから作業に入ってください。
# RDSリソースの依存関係 aws_vpc | +-- aws_subnet (private_a, private_c) | | | +-- aws_db_subnet_group ← RDSを配置するサブネットの集合 | +-- aws_security_group (rds) ← 3306番ポートへのアクセス制御 | +-- aws_db_parameter_group ← 文字コード・タイムゾーン等の設定 | +-- aws_db_instance ← MySQLインスタンス本体(最後に作成)
・1. セキュリティグループ:aws_db_instanceに紐づける。3306番ポートへの許可元を限定する
・2. aws_db_subnet_group:RDSを配置するサブネットの集合。2つ以上のAZが必須
・3. aws_db_parameter_group:文字コード・タイムゾーンなどのMySQLパラメータを管理
・4. aws_db_instance:上記3つを参照してMySQLインスタンスを作成する
次のセクションで具体的な設定手順を解説します。
aws_db_instanceの基本設定|依存リソースの作成順序
0. 既存VPCをdata sourceで参照する
VPCとサブネットがすでに存在する環境では、resource ブロックで新規作成するのではなく data ブロックで参照するのが実務では一般的です。タグ名で既存VPCを特定し、プライベートサブネットのIDを動的に取得できます。# data.tf:既存VPCとプライベートサブネットをdata sourceで参照する data "aws_vpc" "main" { tags = { Name = "main-vpc" } } data "aws_subnets" "private" { filter { name = "vpc-id" values = [data.aws_vpc.main.id] } tags = { Tier = "private" } }
1. aws_db_subnet_groupでサブネットグループを作成する
RDSを作成するには必ず事前にサブネットグループが必要です。サブネットグループは「RDSを配置できるサブネットの集合」で、マルチAZ構成ではサブネットグループに2つ以上のAZのサブネットを含める必要があります。# subnet_group.tf resource "aws_db_subnet_group" "main" { name = "main-db-subnet-group" subnet_ids = [ aws_subnet.private_a.id, # ap-northeast-1a のプライベートサブネット aws_subnet.private_c.id, # ap-northeast-1c のプライベートサブネット ] tags = { Name = "main-db-subnet-group" Environment = "production" } }
data.aws_subnets.private.ids をそのまま渡せます。2. セキュリティグループを定義する
RDS用のセキュリティグループでは、アクセス元(アプリケーションサーバーのセキュリティグループ)からのみ3306番ポートを許可します。0.0.0.0/0 の全開放は絶対に避けてください。# security_group.tf resource "aws_security_group" "rds" { name = "rds-sg" description = "Security group for RDS MySQL" vpc_id = aws_vpc.main.id egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = { Name = "rds-sg" } } # ingressルールは aws_security_group_rule で分離して定義する resource "aws_security_group_rule" "rds_from_app" { type = "ingress" from_port = 3306 to_port = 3306 protocol = "tcp" # アプリケーションサーバーのSGからのみ許可 source_security_group_id = aws_security_group.app.id security_group_id = aws_security_group.rds.id description = "MySQL from app servers" }
セキュリティグループとあわせて、aws_db_instance 側でも
publicly_accessible = false(デフォルト値)を明示的に指定することをおすすめします。デフォルト値であっても明示することで「意図的にインターネット非公開にしている」という意図がコードに残ります。3. aws_db_instanceでMySQLを起動する
サブネットグループとセキュリティグループが揃ったら aws_db_instance を定義します。# rds.tf resource "aws_db_instance" "main" { identifier = "main-mysql" engine = "mysql" engine_version = "8.0.35" instance_class = "db.t3.micro" allocated_storage = 20 storage_type = "gp3" db_name = "appdb" username = "admin" password = var.db_password # variables.tfで定義したsensitive変数 db_subnet_group_name = aws_db_subnet_group.main.name vpc_security_group_ids = [aws_security_group.rds.id] parameter_group_name = aws_db_parameter_group.main.name # インターネットから直接接続させない(デフォルトfalseだが明示する) publicly_accessible = false # 本番必須設定 deletion_protection = true skip_final_snapshot = false final_snapshot_identifier = "main-mysql-final-snapshot" backup_retention_period = 7 backup_window = "02:00-03:00" maintenance_window = "mon:03:00-mon:04:00" # ストレージ暗号化(本番環境では必須・作成後に変更不可) storage_encrypted = true # AWSがマイナーバージョンを自動パッチしてもplan差分が出ないようにする lifecycle { ignore_changes = [engine_version] } tags = { Name = "main-mysql" Environment = "production" } } output "rds_endpoint" { value = aws_db_instance.main.endpoint sensitive = false }
lifecycle { ignore_changes = [engine_version] } を追加しておくと、AWSがマイナーバージョンを自動適用(例: 8.0.35 → 8.0.36)した際に terraform plan でノイズが出なくなります。メジャーバージョンアップはコードを意図的に変更して管理する運用です。password には必ず sensitive 変数を使い、コードに平文で書き込まないようにしてください。
# variables.tf variable "db_password" { description = "RDS admin password" type = string sensitive = true # terraform planとログに値が表示されなくなる }
# 方法1: -varオプションで直接渡す(CI/CD環境ではシークレット変数から渡す) $ terraform apply -var="db_password=MySecretPass123!" # 方法2: terraform.tfvarsファイルに書く(必ず.gitignoreに追加すること) # terraform.tfvars db_password = "MySecretPass123!" $ terraform apply # .tfvarsを自動的に読み込む # 方法3: 環境変数で渡す(variable名にTF_VAR_を付ける) $ export TF_VAR_db_password="MySecretPass123!" $ terraform apply
# Secrets Managerからパスワードを自動取得する設計(本番推奨) data "aws_secretsmanager_secret_version" "db_password" { secret_id = "prod/rds/main-mysql/password" } resource "aws_db_instance" "main" { # ... password = jsondecode(data.aws_secretsmanager_secret_version.db_password.secret_string)["password"] }
実際に terraform apply を実行するとRDSの作成が始まります。完了までの実際の出力例を見てみましょう。
$ terraform apply -var="db_password=MySecretPass123!" aws_db_subnet_group.main: Creating... aws_db_subnet_group.main: Creation complete after 4s [id=main-db-subnet-group] aws_security_group.rds: Creating... aws_security_group.rds: Creation complete after 3s [id=sg-0a1b2c3d4e5f67890] aws_db_parameter_group.main: Creation complete after 2s [id=main-mysql80] aws_db_instance.main: Creating... aws_db_instance.main: Still creating... [10s elapsed] aws_db_instance.main: Still creating... [1m0s elapsed] # ... (RDSの作成は通常5分~20分かかる) aws_db_instance.main: Creation complete after 8m42s [id=main-mysql] Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
>> Terraform実践セミナーの詳細はこちら
パラメータグループで文字コードとタイムゾーンをコード化する
1. aws_db_parameter_groupを定義する
AWSが提供するデフォルトのパラメータグループは変更不可です。カスタム設定(文字コードやタイムゾーン)が必要な場合は aws_db_parameter_group を作成してから aws_db_instance に紐づけます。# parameter_group.tf resource "aws_db_parameter_group" "main" { name = "main-mysql80" family = "mysql8.0" # engineとengine_versionに対応したfamilyを指定 description = "Custom parameter group for MySQL 8.0" parameter { name = "character_set_server" value = "utf8mb4" } parameter { name = "character_set_client" value = "utf8mb4" } parameter { name = "collation_server" value = "utf8mb4_unicode_ci" } parameter { name = "time_zone" value = "Asia/Tokyo" apply_method = "immediate" # 再起動なしで即時反映 } parameter { name = "slow_query_log" value = "1" } parameter { name = "long_query_time" value = "1" # 1秒以上のクエリをスロークエリとして記録 } parameter { name = "general_log" value = "0" # 本番では無効(全クエリ記録はI/Oに影響する) } # 最大接続数(インスタンスクラスのメモリ量に応じて調整する) parameter { name = "max_connections" value = "200" } # InnoDBバッファプールサイズ(静的パラメータのためpending-reboot) parameter { name = "innodb_buffer_pool_size" value = "134217728" # 128MB。db.t3.microの場合の目安 apply_method = "pending-reboot" } # リードレプリカ・binlogレプリケーションを使う場合に必要 parameter { name = "binlog_format" value = "ROW" apply_method = "pending-reboot" } # パラメータグループを差し替える場合に新しいグループを先に作成する lifecycle { create_before_destroy = true } tags = { Name = "main-mysql80" } }
lifecycle { create_before_destroy = true } を追加しておくと、パラメータグループの name を変更した際(例: mysql8.0系→mysql8.4系へのメジャーバージョンアップ)に新しいグループが先に作られてから古いグループが削除されます。aws_db_instance がパラメータグループを参照している状態で先に削除しようとするとエラーになるため、このオプションは実務上ほぼ必須です。max_connections のデフォルト値はインスタンスクラスのメモリ量から自動計算されます(db.t3.microでは約85)。アプリケーションの同時接続数が多い場合は明示的に設定してください。ただし大きくしすぎるとメモリを圧迫するため、接続プールの最大数と合わせて設計してください。
collation_server を utf8mb4_unicode_ci に合わせておくと、文字コードと照合順序の不整合によるエラーを防げます。binlog_format = "ROW" はリードレプリカを追加する予定がある場合やデータ変更の監査ログが必要な場合に設定します。
innodb_buffer_pool_size はInnoDBがデータキャッシュに使うメモリです。本番環境では搭載メモリの50~70%を目安に設定します。db.t3.microの2GBメモリに対して128MBという設定は小さめですが、RDS側のOSやその他プロセスとのメモリ競合を考慮した保守的な値です。
2. apply_methodの違い(immediateとpending-reboot)
パラメータの apply_method には2種類あります。・immediate:apply直後に反映。time_zoneやslow_query_logなど動的パラメータに使用できる
・pending-reboot:次のメンテナンスウィンドウまたは手動再起動後に反映。innodb_buffer_pool_sizeなどの静的パラメータに必要
静的パラメータを immediate にしてもエラーにはなりませんが反映されません。AWSドキュメントのパラメータ一覧で「Dynamic/Static」を確認してから設定してください。適用状態は AWS CLI で確認できます。
# パラメータグループの変更が反映済みかどうかを確認 $ aws rds describe-db-instances --db-instance-identifier main-mysql --query 'DBInstances[0].DBParameterGroups' [ { "DBParameterGroupName": "main-mysql80", "ParameterApplyStatus": "in-sync" } ] # "pending-reboot"が表示された場合はメンテナンスウィンドウ後または手動再起動で反映される
実務Tips|削除保護・自動バックアップ・マルチAZ・暗号化
1. 本番環境の削除保護設定
terraform destroy を実行しても本番DBが消えないよう、deletion_protection = true は必須です。削除保護が有効な状態で destroy しようとすると次のエラーになります。$ terraform destroy Error: RDS DB Instance is protected from deletion. with aws_db_instance.main, on rds.tf line 1, in resource "aws_db_instance" "main": Please disable deletion protection before deleting.
さらに強固な保護が必要な場合は lifecycle ブロックの prevent_destroy を組み合わせます。
resource "aws_db_instance" "main" { # ... deletion_protection = true lifecycle { # terraform destroyをHCLレベルでブロックする(deletion_protectionとの二重防壁) prevent_destroy = true # AWSのマイナーバージョン自動パッチによるplan差分を抑制する ignore_changes = [engine_version] } }
2. skip_final_snapshotとfinal_snapshot_identifierの設定
skip_final_snapshot = false(デフォルト)の場合、terraform destroy を実行するとRDS削除前に最終スナップショットが自動作成されます。final_snapshot_identifier には一意の名前を設定してください(省略するとエラーになります)。開発環境では毎回スナップショットが作成されるとコストがかかるため、skip_final_snapshot = true にするケースもあります。環境ごとに var-file で制御する設計が一般的です。
# environments/prod.tfvars skip_final_snapshot = false backup_retention_period = 7 # environments/dev.tfvars skip_final_snapshot = true backup_retention_period = 1 # 本番環境に適用する場合 $ terraform apply -var-file="environments/prod.tfvars"
3. マルチAZ設定でフェイルオーバーを実現する
本番環境では multi_az = true を設定します。1行追加するだけですが、コスト(インスタンス料金が約2倍)と引き換えに単一AZ障害時の自動フェイルオーバーが有効になります。resource "aws_db_instance" "main" { # ... 既存の設定 ... multi_az = true # スタンバイレプリカを別AZに自動配置 } output "rds_endpoint" { value = aws_db_instance.main.endpoint sensitive = false }
マルチAZと読み取り負荷分散を両立したい場合は aws_db_instance に replicate_source_db を指定したリードレプリカを追加します。リードレプリカはフェイルオーバーの対象にはなりませんが、参照クエリをリードレプリカのエンドポイントに向けることでプライマリの負荷を下げられます。
4. ストレージ暗号化をTerraformで管理する
本番環境ではストレージ暗号化を有効にすることがセキュリティ要件として求められるケースがほとんどです。storage_encrypted = true を設定するだけでAWS管理のKMSキーを使った暗号化が有効になります。特定のカスタマー管理キーを使う場合は kms_key_id で指定します。resource "aws_db_instance" "main" { # ... storage_encrypted = true # カスタマー管理キーを使う場合(省略するとAWS管理のaws/rdsキーが使われる) # kms_key_id = aws_kms_key.rds.arn }
5. Performance InsightsとEnhanced Monitoringを有効にする
本番環境では、クエリの遅延原因を特定するために Performance Insights を有効にすることをおすすめします。Enhanced Monitoring と組み合わせることで、CPU・メモリ・I/Oのリアルタイム監視も可能になります。# rds.tf(既存のaws_db_instanceに追加する設定) resource "aws_db_instance" "main" { # ... 既存の設定 ... # Performance Insights(クエリ単位の遅延分析) performance_insights_enabled = true performance_insights_retention_period = 7 # 7日間無料。31日・731日は有料 # Enhanced Monitoring(OSレベルのメトリクス収集) monitoring_interval = 60 # 秒単位(0で無効、60が標準) monitoring_role_arn = aws_iam_role.rds_monitoring.arn } # Enhanced Monitoring用のIAMロール resource "aws_iam_role" "rds_monitoring" { name = "rds-monitoring-role" assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{ Effect = "Allow" Principal = { Service = "monitoring.rds.amazonaws.com" } Action = "sts:AssumeRole" }] }) } resource "aws_iam_role_policy_attachment" "rds_monitoring" { role = aws_iam_role.rds_monitoring.name policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole" } # Enhanced Monitoringのログ保持期間(CloudWatch Logs) resource "aws_cloudwatch_log_group" "rds_enhanced_monitoring" { name = "RDSOSMetrics" retention_in_days = 30 }
CloudWatch Logs の RDSOSMetrics ロググループは Enhanced Monitoring を有効にすると自動作成されますが、aws_cloudwatch_log_group で明示的に管理することでログ保持期間をコードで制御できます。
6. RDS IAM認証でパスワード管理を不要にする
iam_database_authentication_enabled = true を設定すると、MySQLのパスワードの代わりにAWS IAMトークンでRDSに接続できます。EC2やLambdaからIAMロールで接続する構成では、パスワードのローテーション管理が不要になります。resource "aws_db_instance" "main" { # ... iam_database_authentication_enabled = true } # アプリサーバーのIAMロールにRDS接続権限を付与 resource "aws_iam_policy" "rds_iam_auth" { name = "rds-iam-auth-policy" policy = jsonencode({ Version = "2012-10-17" Statement = [{ Effect = "Allow" Action = "rds-db:connect" Resource = "arn:aws:rds-db:ap-northeast-1:123456789012:dbuser/main-mysql/appuser" }] }) }
# IAMトークンを取得してMySQLに接続する TOKEN= mysql -h main-mysql.c9akciq32a3n.ap-northeast-1.rds.amazonaws.com -u appuser --password=$TOKEN --enable-cleartext-plugin appdb
apply後のRDS接続確認|terraform outputとAWS CLI
apply が完了しても、実際にアプリケーションからRDSに接続できるかを確認するまでが運用の基本です。RDSの場合は「インスタンス状態の確認」と「エンドポイントの取得」の2段階で確認します。1. terraform outputでエンドポイントを確認する
# applyで出力された値を確認 $ terraform output rds_endpoint main-mysql.c9akciq32a3n.ap-northeast-1.rds.amazonaws.com:3306 # outputが定義されていない場合はstateから直接取得 $ terraform state show aws_db_instance.main | grep endpoint endpoint = "main-mysql.c9akciq32a3n.ap-northeast-1.rds.amazonaws.com:3306"
2. AWS CLIでRDSの状態を確認する
# RDSインスタンスの状態確認(availableになっていれば接続可能) $ aws rds describe-db-instances --db-instance-identifier main-mysql --query 'DBInstances[0].[DBInstanceStatus,Endpoint.Address,MultiAZ,StorageEncrypted]' --output table -------------------------------------------------------------------- | DescribeDBInstances | +-----------+----------------------------------------------+------+-----------+ | available | main-mysql.c9akciq32a3n.ap-northeast-1.rds.amazonaws.com | True | True | +-----------+----------------------------------------------+------+-----------+ # RDSのイベント履歴を確認(障害時の最初の調査ポイント) $ aws rds describe-events --source-identifier main-mysql --source-type db-instance --duration 60 --query 'Events[*].[EventCategories[0],Message,Date]' --output table
3. アプリサーバーからMySQL接続を確認する
# アプリサーバー(EC2)に接続して疎通確認 $ mysql -h main-mysql.c9akciq32a3n.ap-northeast-1.rds.amazonaws.com -u admin -p appdb -e "SELECT @@time_zone, @@character_set_server, @@collation_server;" Enter password: +-------------+------------------------+--------------------+ | @@time_zone | @@character_set_server | @@collation_server | +-------------+------------------------+--------------------+ | Asia/Tokyo | utf8mb4 | utf8mb4_unicode_ci | +-------------+------------------------+--------------------+ # ポートレベルでの疎通確認(mysqlコマンドなしで確認したい場合) $ nc -zv main-mysql.c9akciq32a3n.ap-northeast-1.rds.amazonaws.com 3306 Connection to main-mysql.c9akciq32a3n.ap-northeast-1.rds.amazonaws.com 3306 port [tcp/mysql] succeeded!
「InvalidParameterCombination」などのapplyエラーと対処法
1. サブネットグループのAZが1つしかない場合
マルチAZを有効にしようとしたとき、または一部のインスタンスタイプで複数AZのサブネットが要求されるときに発生します。$ terraform apply Error: InvalidParameterCombination: Cannot specify a DB subnet group for DB instances in VPC. # またはサブネットグループのAZが不足している場合: Error: DB subnet group "main-db-subnet-group" is invalid because it must have at least 2 availability zones.
原因2:subnet_ids に存在しないサブネットIDを記載している(スペルミス・環境の取り違え)
対処法: aws_db_subnet_group の subnet_ids に2つ以上の異なるAZのサブネットIDが含まれているか確認してください。
# サブネットのAZを確認する $ aws ec2 describe-subnets --subnet-ids subnet-aaa111 subnet-bbb222 --query 'Subnets[*].[SubnetId,AvailabilityZone]' --output table
2. パラメータグループのfamilyが一致しない場合
$ terraform apply Error: InvalidParameterValue: Could not find parameter group family "mysql8.0" for parameter group "main-mysql80" # familyの名前は厳密に確認する(例: mysql8.0, mysql8.4, aurora-mysql8.0 は別物)
原因2:Aurora MySQLに対して family = "mysql8.0"(非Aurora)を指定している
対処法: engine_version と family が対応しているか確認してください。MySQL 8.0系は family = "mysql8.0"、MySQL 8.4系は family = "mysql8.4" になります。Aurora MySQLの場合は family = "aurora-mysql8.0" です。
3. applyが途中でタイムアウトする場合
RDSの作成は最大20分かかります。CI/CDパイプラインのデフォルトタイムアウトが短いと apply が中断されます。Terraform側では timeouts ブロックで延長できます。resource "aws_db_instance" "main" { # ... timeouts { create = "40m" # デフォルトは40m。CI側も合わせて延長する update = "80m" # マルチAZ変更などは時間がかかる delete = "40m" } }
timeout-minutes: 90 も合わせて設定してください。Terraformの timeouts だけ延ばしてもCI側がジョブを打ち切ると apply が中断されます。4. セキュリティグループの設定ミスで接続できない場合
apply は正常終了したのに mysql コマンドで接続できない場合、セキュリティグループかサブネットのルーティングが原因のほとんどです。原因1:RDSのセキュリティグループにアプリサーバーのSGが登録されていない
原因2:アプリサーバーのセキュリティグループIDとTerraformのリソース参照がずれている
原因3:RDSがプライベートサブネットにあるのに、アプリサーバーから異なるVPCを経由しようとしている
# アプリサーバー(EC2)のセキュリティグループIDを確認 $ aws ec2 describe-instances --instance-ids i-0abc12345def --query 'Reservations[0].Instances[0].SecurityGroups[*].GroupId' --output text sg-0app1234567 # RDSのセキュリティグループのingressルールを確認 $ aws ec2 describe-security-groups --group-ids sg-0rds1234567 --query 'SecurityGroups[0].IpPermissions' # 確認ポイント: # - from_port/to_portが3306か # - UserIdGroupPairs に sg-0app1234567 が含まれているか
5. DBInstanceIdentifierが既に存在するエラー
一度作成したRDSをコンソールから手動で削除した後に terraform apply を実行すると、Terraformのstateには記録が残っているため「既に存在する」エラーが発生するケースがあります。逆に、既存のRDSをTerraform管理下に取り込む場合は terraform import を使います。$ terraform apply Error: creating RDS DB Instance (main-mysql): DBInstanceAlreadyExists: DB Instance already exists. # 既存RDSをTerraform管理下に取り込む場合はimportを使う $ terraform import aws_db_instance.main main-mysql # コンソールで手動削除済みでstateだけ残っている場合はstateから削除してから再apply $ terraform state rm aws_db_instance.main $ terraform apply
本記事のまとめ
TerraformでRDSをプロビジョニングする設計のポイントをまとめます。| やりたいこと | 使うリソース・設定 |
|---|---|
| 既存VPCをコードで参照する | data "aws_vpc" "main" { tags = { Name = "..." } } |
| RDSのサブネットグループを定義する | resource "aws_db_subnet_group" { subnet_ids = [...] } |
| RDS専用セキュリティグループを作る | resource "aws_security_group_rule" { from_port = 3306 } |
| MySQLインスタンスを作成する | resource "aws_db_instance" { engine = "mysql" } |
| 文字コード・タイムゾーンを設定する | resource "aws_db_parameter_group" { parameter { name = "time_zone" } } |
| 最大接続数を設定する | aws_db_parameter_group { parameter { name = "max_connections" } } |
| パラメータグループを無停止で差し替える | aws_db_parameter_group { lifecycle { create_before_destroy = true } } |
| 誤削除を二重防止する | aws_db_instance { deletion_protection = true, lifecycle { prevent_destroy = true } } |
| マイナーバージョン自動パッチのdriftを抑制する | aws_db_instance { lifecycle { ignore_changes = [engine_version] } } |
| マルチAZフェイルオーバーを有効にする | aws_db_instance { multi_az = true } |
| ストレージを暗号化する | aws_db_instance { storage_encrypted = true } |
| Performance Insightsを有効にする | aws_db_instance { performance_insights_enabled = true } |
| IAM認証でパスワード管理を不要にする | aws_db_instance { iam_database_authentication_enabled = true } |
| Secrets Managerでパスワードを管理する | data "aws_secretsmanager_secret_version" { secret_id = "prod/rds/..." } |
| apply後にRDS状態を確認する | aws rds describe-db-instances --db-instance-identifier main-mysql |
次に読む記事:
・Linuxのポート確認コマンド(ss・lsof)|RDSバックエンドアプリのLISTEN状態を確認する
・digコマンドでDNS名前解決を確認する|RDSエンドポイントが正しく解決されるか検証する
>> Terraform実践セミナーの詳細はこちら
3,100名以上が実践した「型」を無料で公開中
プロのエンジニアはコマンドを暗記していません。
「現場で使える型」を効率よく使いこなしているだけです。
その「型」を図解60Pにまとめた入門マニュアルを、完全無料でプレゼントしています。
姓・名・メールの3つだけ/30秒/解除は3秒 / 詳細はこちら

無料メルマガで学習を続ける
Linuxの実践スキルをメールで毎週お届け。
登録は30秒、解除もいつでも可。
登録無料・いつでも解除できます