こんにちは。
現在、GCPを業務で利用していて、モニタリングツールとしては基本的にCloud Monitoringを使っています。今回は、この設定をTerraform化しようとした時の話になります。
Terraformのコードでリソースのあるべき状態を管理しているのでCloud Monitoringも例外なく管理しますが、Cloud Monitoringのアラートポリシーは1からTerraformで作成することはなかなか大変で(\
でエスケープとかしないといけない)、かつ記述する内容はGUIから判断がつきにくいものになっています(公式にも私が探した限りはない)。なので、基本的にGUIで設定してからterraform import
コマンドでコード化すればこの点はあまり悩まなくて済みますが、公式の書き方で実行してもなぜかimportできず、沼にはまりかけました。一筋縄ではいかないCloud Monitoringのコード化ですが、ハマったところから無事コード化できるところまで持っていこうと思います。
GUIで作ってからインポートする
業務では「こんな監視設定にしてほしい。」や「これと同じアラートポリシーを作ってほしい。」などといった声を受けて設定しています。GUIでの設定は比較的簡単ですので、要件に対しては早めにコミットできます。GUIで作ったリソースを、Terraformで作成したリソースのあるべき状態を記しているtfstateに反映させるためには、terraform import
という素晴らしいコマンドがあります。つけたいリソースネームと、インポートしたいリソースを打ち込むだけでtfstateに反映されます。Cloud Monitoringもこのコマンドでできるはずなのですが、出てきたのはエラーでした。
Githubにも全く同じパターンでハマっている人がいたので別の方法を考えます。
https://github.com/terraform-providers/terraform-provider-google/issues/4610
(Terraformのバージョンを新しくして試してみてください。といったことが書かれていますが今回ここについては掘り下げません。)
Terraformerを使う
また便利なツールがありまして、コード化したいリソースを指定するだけで自動的にコード化してくれるTerraformerというツールがあります。元々wazeで作られていたOSSですが、現在はGoogleに買収されており、GoogleのOSSとしてリリースされています。今回使い方については割愛しますが、Terraformerを使ったソースをみてみると、なかなか読みにくいことがわかります。ちなみに、以下がTerraformerで出力されるコードの一例になります。
resource "google_monitoring_notification_channel" "tfer--projects--project-name--notificationChannels--0123456789" {
display_name = "hogehoge@testcompany.com"
enabled = "true"
labels = {
email_address = "hogehoge@testcompany.com"
}
project = "projece-name"
type = "email"
}
resource "google_monitoring_alert_policy" "tfer--projects--project-name--alertPolicies--17320504" {
combiner = "OR"
conditions {
condition_threshold {
aggregations {
alignment_period = "60s"
per_series_aligner = "ALIGN_MEAN"
}
comparison = "COMPARISON_GT"
duration = "60s"
filter = "metric.type=\"agent.googleapis.com/disk/percent_used\" resource.type=\"gce_instance\" metric.label.\"state\"=\"used\" metric.label.\"device\"=\"rootfs\" metadata.user_labels.\"name\"=\"sample-instance-1\""
threshold_value = "80"
trigger {
count = "1"
percent = "0"
}
}
display_name = "use-80-percent-resource-disk"
}
display_name = "use-80-percent-resource-disk"
enabled = "true"
notification_channels = ["projects/project-name/notificationChannels/0123456789"]
project = "projet-name"
}
上記はアラートが上がったときに通知されるメールアドレスと、ディスクの使用率が80%を超えたときに上がるアラートを定義しています。普段自分でコードを書くのであれば、作成したリソースを別のところで参照したり、locals
などを使って変数を定義することで可読性やコードの短縮化を図ることができますが、Terraformerで出力されたソースは全てがベタ書きになっています。このコードを読みやすくして、後のメンテナンスや他のアラート作成にも使いやすくなるようにします。
読みやすくする
Terraformerで出力されるファイルにはtfstateも含まれます。今回は出力されたtfstateをGCSバケットに置いて作業しています。GCSバケットへのアップロードはgsutil
コマンドを使ってアップロードします。バケットの指定が適切であればterraform state list
でtfstateのリソースを確認でき、上記のリソースは
$ terraform state list
google_monitoring_notification_channel.tfer--projects--project-name--notificationChannels--0123456789
google_monitoring_alert_policy.tfer--projects--project-name--alertPolicies--17320504
と出力されるかと思います。まずはリソース名を分かりやすくしていきます。
リソース名を変える
リソース名の変更にはterraform state mvコマンドを使って変更します。今回はコードを以下のように修正します。
google_monitoring_notification_channel
# 変更前
resource "google_monitoring_notification_channel" "tfer--projects--project-name--notificationChannels--0123456789" {
....
}
# 変更後
resource "google_monitoring_notification_channel" "hogehoge_email" {
....
}
google_monitoring_alert_policy
# 変更前
resource "google_monitoring_alert_policy" "tfer--projects--project-name--alertPolicies--17320504" {
....
}
# 変更後
resource "google_monitoring_alert_policy" "use_80_percent_resource_disk" {
....
}
あとは以下のコマンドでtfstateとの差異がなくなります。
$ tf state mv google_monitoring_notification_channel.tfer--projects--project-name--notificationChannels--0123456789 google_monitoring_notification_channel.hogehoge_email
$ tf state mv google_monitoring_alert_policy.tfer--projects--project-name--alertPolicies--17320504 google_monitoring_alert_policy.use_80_percent_resource_disk
ソースコードを読みやすくする
リソース名を変更したことによりそのリソースが何を定義しているものなのか分かりやすくなりました。一方、google_monitoring_alert_policy
の中で指定されてるnotification_channels
のブロックを見てみると、指定されているチャンネルがパッと見たとき分かりにくいですね。notification_channels
のブロックで参照しているのは各リソースのidになるので、以下のように書き換えます。
# 変更前
resource "google_monitoring_alert_policy" "use_80_percent_resource_disk" {
....
notification_channels = ["projects/project-name/notificationChannels/0123456789"]
....
}
# 変更後
resource "google_monitoring_alert_policy" "use_80_percent_resource_disk" {
....
notification_channels = [
google_monitoring_notification_channel.hogehoge_email.id
]
....
}
このように書き換えてterraform planを実行しましょう。変更が起こらなければ成功です!
まとめ
何回かCloud MonitoringをTerraform化してきたので、これはナレッジとしてまとめたいなと思って書きました。
Terraformのソースはインフラの設定などを記載してあるので、「どこで、なにが」指定されているかわかりやすくなっていることが望ましいかと考えています。今回のネタはある意味リファクタリングになりますが、Terraformのリファクタリングはどこまでいってもソースとしてのパフォーマンスは上がらないんだよな、とふと最近思っています。(可読性が上がる、という意味で人のパフォーマンスは上がるのかもしれないですが。)