Terraformで一度作成したAWSリソースを後からコードをモジュール化して再度適用したらdestory&createされるよ
最近はAWSリソース構築にterraformを使っているのですが、一からコードを書くのは面倒なのでterraformingを使ってコード生成しております。(他にterraformerとかもあったりしますね)
terraformingは便利なツールですが、万能ではなく、機械的に抽出されるためかそのままだとコードは冗長なものになりがちです。 私の普段見ているシステムのように作成するリソース数が多いとファイルの行数がトンデモないことになるんじゃないかなと思います。
terraformingで抽出したコードを、そのまま適用してしまってあとで悲しみに暮れている私と同じ運命を辿らないように、terraformingで抽出したコードはしっかりモジュール化を検討した上で適用することをおすすめします(マジで)
流派的にはterraformの機能であるWorkspacesを使ってコード量を少なくするという案もありますが、今回はモジュール化でやってます
それでは本題ですが、あとからterraformコードをモジュール化しようとするとどうなるのかっていうところを実際にやってみました(地獄)
環境
- Terraform v0.12.0
- provider.aws v2.12.0
前提
- terraform実行環境は構築済み
- cloudwatch agentがインストールされているec2構築済み
検証作業
今回はcloudwatch alarmを作成するケースで試してみる
ディレクトリ構成はこんな感じ
# tree . ├── cloudwatch │ ├── backend.tf │ ├── main.tf │ ├── provider.tf │ └── versions.tf ├── module │ └── cloudwatch_alarm │ ├── java_process.tf │ └── variables.tf
まずは愚直にモジュール使ってないmain.tfファイルを作成(内容はjava process監視)
resource "aws_cloudwatch_metric_alarm" "java-process-down" { alarm_name = "java-process-down" comparison_operator = "LessThanThreshold" evaluation_periods = "1" metric_name = "procstat_lookup_pid_count" namespace = "CWAgent" period = "60" statistic = "Average" threshold = "1.0" alarm_description = "" ok_actions = ["arn:aws:sns:ap-northeast-1:XXXXXXXXXXXX:test-cloudwatch-to-slack-alert"] alarm_actions = ["arn:aws:sns:ap-northeast-1:XXXXXXXXXXXX:test-cloudwatch-to-slack-alert"] dimensions = { exe = "java" InstanceId = "i-XXXXXXXXXXXXXXX" ImageId = "ami-XXXXXXXXXXXXXXXXX" pid_finder = "native" InstanceType = "t2.micro" } }
terraform apply
# tf apply --auto-approve aws_cloudwatch_metric_alarm.java-process-down: Creating... aws_cloudwatch_metric_alarm.java-process-down: Creation complete after 0s [id=java-process-down] Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
これでcloudwatch alarmが作成されましたね。 続いて先ほど作成したmain.tfをモジュール呼び出すようにして同じ内容になるように修正します
module "cloudwatch_alarm_java_process-down" { source = "../module/cloudwatch_alarm/" instance_id = "i-XXXXXXXXXXXXXXX" image_id = "ami-XXXXXXXXXXXXXXXXX" instance_type = "t2.micro" slack_notice = "arn:aws:sns:ap-northeast-1:XXXXXXXXXXXX:test-cloudwatch-to-slack-alert" }
モジュールの呼び出し先であるjava_process.tfも作成する
resource "aws_cloudwatch_metric_alarm" "java-process-down" { alarm_name = "java-process-down" comparison_operator = "LessThanThreshold" evaluation_periods = "1" metric_name = "procstat_lookup_pid_count" namespace = "CWAgent" period = "60" statistic = "Average" threshold = "1.0" alarm_description = "" ok_actions = ["${var.slack_notice}"] alarm_actions = ["${var.slack_notice}"] dimensions = { exe = "java" InstanceId = "${var.instance_id}" ImageId = "${var.image_id}" pid_finder = "native" InstanceType = "${var.instance_type}" } }
モジュールをインストールするために terraform init してから、再び terraform apply
# tf apply --auto-approve aws_cloudwatch_metric_alarm.java-process-down: Refreshing state... [id=java-process-down] aws_cloudwatch_metric_alarm.java-process-down: Destroying... [id=java-process-down] module.cloudwatch_alarm_java_process-down.aws_cloudwatch_metric_alarm.java-process-down: Creating... module.cloudwatch_alarm_java_process-down.aws_cloudwatch_metric_alarm.java-process-down: Creation complete after 0s [id=java-process-down] aws_cloudwatch_metric_alarm.java-process-down: Destruction complete after 0s Apply complete! Resources: 1 added, 0 changed, 1 destroyed.
コマンドラインでは Apply complete! と表示されてましたが、マネジメントコンソールから確認してみると作成されていない...
もう一度 terraform apply
# tf apply --auto-approve module.cloudwatch_alarm_java_process-down.aws_cloudwatch_metric_alarm.java-process-down: Refreshing state... [id=java-process-down] module.cloudwatch_alarm_java_process-down.aws_cloudwatch_metric_alarm.java-process-down: Creating... module.cloudwatch_alarm_java_process-down.aws_cloudwatch_metric_alarm.java-process-down: Creation complete after 0s [id=java-process-down] Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
今度は作成されました。 terraform を使ってると割とよくあるんですけど、コマンドライン上は成功してもAWS上では作成されない事象。再度applyすると作成はされるが、何が原因かはよく分かっておらず...
とりあえず、一度作成したリソースをtfファイルをモジュールを利用するように修正すると、リソース自体が再作成されるので、本番環境だと慎重にやる必要がある
あと、おまけで試してみたけど main.tfファイルを単純に分割するのはリソース再作成にはならない模様(tfファイルが冗長になったら分割したくなるので)