[小ネタ] TerraformでRDSのCloudWatch Logsを管理したい
はじめに
こんにちは、ぐっさんです。
TerraformでRDS for SQL ServerをデプロイするにあたってCloudWatch Logsまわりを制御したい場面がありました。
やりたかったことは2つです。
- ログの保持期間を設定したい - デフォルトでは無期限になってしまいコストが気になる。可能ならIaCで一元管理したい。
terraform destroy時の挙動を制御したい - テスト環境ではログも一緒に削除したいが、本番環境ではログは残しておきたい。
今回は terraform-aws-modules/rds/aws を使ってこれを解決したので紹介します。
なお、本記事ではTerraformモジュールの基礎については扱いません。
デフォルトの挙動(問題点)
RDSをTerraformで作成する際に enabled_cloudwatch_logs_exports を設定すると、CloudWatch Logsへのログ出力ができます。
resource "aws_db_instance" "rds" {
enabled_cloudwatch_logs_exports = ["agent", "error"]
...
}
しかしこの場合、RDSインスタンスがロググループを自動作成します。
自動作成されたロググループは以下のような問題があります。
- 保持期間が無期限(設定されない)
- Terraform管理外のため
terraform destroyしても削除されない
コストを抑えたい場合や、テスト環境で綺麗にIaCからリソースを管理・削除したい場合には都合が悪いです。
解決策: Terraform Registry のモジュールでロググループを事前作成する
Terraform Registryとは、Terraformで使えるプロバイダーやモジュールを公開・共有するためのプラットフォームです。
個人や企業が自作モジュールを自由に公開することもできます!
今回使用する terraform-aws-modules/rds/aws はその中で公開されているRDS管理用のモジュールで、RDSインスタンスのほか、サブネットグループ・パラメータグループ・オプショングループ・CloudWatch Log Groupsといった関連リソースをまとめて管理できます。
terraform-aws-modules/rds/aws モジュールには create_cloudwatch_log_group というオプションがあります。これを true にすると、RDSインスタンスより先にロググループをTerraformが作成してくれます。
module "rds" {
source = "terraform-aws-modules/rds/aws"
version = "~> 6.0"
# ログ出力の設定
enabled_cloudwatch_logs_exports = ["agent", "error"]
# ロググループをTerraform管理で作成
create_cloudwatch_log_group = true
cloudwatch_log_group_retention_in_days = 90
cloudwatch_log_group_skip_destroy = true # destroyしてもログを残す
...
}
cloudwatch_log_group_retention_in_days
ロググループの保持期間(日数)を設定します。例えば90 にすれば90日分のみ保持してそれ以降は自動削除されます。
cloudwatch_log_group_skip_destroy
terraform destroy 時の挙動を制御します。
| 値 | 挙動 |
|---|---|
true |
destroyしてもロググループはAWS上に残る(Terraformの管理からのみ外れる) |
false |
destroyすると一緒に削除される |
テスト環境と本番環境で使い分けるとすっきりします。
# テスト環境: destroyで一緒に削除したい
cloudwatch_log_group_skip_destroy = false
# 本番環境: destroyしてもログは残しておきたい
cloudwatch_log_group_skip_destroy = true
モジュールの内部実装を覗いてみる
中身を見るとこうなっていました。aws_db_instance リソースに depends_on でロググループへの依存が明示されており、Terraformがロググループを必ず先に作成する順番が保証されています。
resource "aws_db_instance" "this" {
...
depends_on = [aws_cloudwatch_log_group.this] # ロググループが先に作成される
}
resource "aws_cloudwatch_log_group" "this" {
for_each = toset([for log in var.enabled_cloudwatch_logs_exports : log
if var.create && var.create_cloudwatch_log_group && !var.use_identifier_prefix])
name = "/aws/rds/instance/${var.identifier}/${each.value}"
retention_in_days = var.cloudwatch_log_group_retention_in_days
skip_destroy = var.cloudwatch_log_group_skip_destroy
...
}
ちなみに enabled_cloudwatch_logs_exports = ["agent", "error"] を渡した場合、for_each によって以下の2つのロググループが作成されます。
/aws/rds/instance/{identifier}/agent
/aws/rds/instance/{identifier}/error
RDSが自動作成するロググループと同じ名前で事前に作成しておくことで、RDSがログを書き込もうとした際に既存のロググループ(Terraform管理・保持期間設定済み)がそのまま使われます。
最初は自分で実装しようとしていましたが、ちょうど公式モジュールの話を聞いたばかりだったので確認してみると、まさにこれ!という記述があってとても嬉しかったです。
注意点: モジュールバージョンとAWS Providerの互換性
Terraform Registryのモジュールを使う際は、モジュールのバージョンとAWS Providerのバージョンの互換性に注意が必要です。
- 今回の場合
| モジュールバージョン | 必要なAWS Provider |
|---|---|
~> 7.0 |
>= 6.28.0 |
~> 6.0 |
~> 5.0 |
今回のプロジェクトではAWS Providerを ~> 5.0 で使用していたため、モジュールで~> 7.0 を指定すると以下のエラーが発生しました。
Error: Failed to query available provider packages
Could not retrieve the list of available versions for provider
hashicorp/aws: no available releases match the given constraints ~> 5.0, >= 6.28.0
プロジェクトのAWS Providerバージョンを確認してからモジュールバージョンを選定するようにしましょう。互換性はTerraform Registryのモジュールページでバージョンを選択すると「Requirements」セクションで確認できます。
まとめ
terraform-aws-modules/rds/aws を使うことで、ロググループの保持期間設定やdestroy時の挙動をTerraformで一元管理できました。デフォルトの挙動(無期限・管理外)が気になっていた方にはぜひ試してほしい設定です。
今回はRDS for SQL Serverで検証しましたが、同じモジュールはMySQL・PostgreSQL・Oracleなど他のエンジンでも使用可能なので、エンジン問わず活用できます。
以上、小ネタでした。誰かの検証のお役にたてたら幸いです。
Terraform Registryには他にも便利なモジュールが多数公開されているので、積極的に活用していきたいと思います!







