なんとこの記事でブログ200記事目です!2012年5月から始めたので約6年半での到達はペースとしてはかなり遅いですが、今後はガンガン書いていきます!
今回はTerraform + GCPネタです。
Auto Scaling on GCEをTerraformで書いていて、インスタンステンプレートの更新時にハマったのでそのメモです。
- インスタンステンプレートは変更の度に新規作成する
- resourceInUseByAnotherResource エラーが起こる
- インスタンスグループの更新方法を指定する必要がある
- ローリングアップデートでインスタンスを入れ替える
- まとめ
- 参考
インスタンステンプレートは変更の度に新規作成する
AWSのLaunch Configrationと同じで一度作成すると変更ができないため、イメージなどを変更するときは新規作成して、インスタンスグループ *1 に新しいインスタンステンプレートを紐付ける必要があります。
Terraformで実装するときは Lifecycle という設定を入れることで、変更が入る度にインスタンステンプレートが新規作成され、インスタンスグループに紐付けた後、古いインスタンステンプレートを削除してくれます。
resource "google_compute_instance_template" "instance_template" { name_prefix = "instance-template-" machine_type = "n1-standard-1" region = "us-central1" // boot disk disk { # ... } // networking network_interface { # ... } lifecycle { create_before_destroy = true } } resource "google_compute_instance_group_manager" "instance_group_manager" { name = "instance-group-manager" instance_template = "${google_compute_instance_template.instance_template.self_link}" base_instance_name = "instance-group-manager" zone = "us-central1-f" target_size = "1" }
Using with Instance Group Manager のコードを拝借しました。
create_before_destroy = true
とすることで、新規リソースを作成してから旧リソースを削除してくれるようになります。
resourceInUseByAnotherResource エラーが起こる
次のようなコードでインスタンステンプレートを更新するときに resourceInUseByAnotherResource
エラーが出てしまい、新しいインスタンステンプレートがインスタンスグループに紐付けができなくなってしまいました。
1 error(s) occurred: * google_compute_instance_template.instance_template: Error deleting instance template: googleapi: Error 400: The instance_template resource 'instance-template' is already being used by ' instance-group-manager', resourceInUseByAnotherResource
resource "google_compute_instance_template" "instance_template" { name_prefix = "instance-template-" machine_type = "n1-standard-1" region = "asia-northeast1" // boot disk disk { # ... } // networking network_interface { # ... } // 追加 update_strategy = "NONE" lifecycle { create_before_destroy = true } } resource "google_compute_instance_group_manager" "instance_group_manager" { name = "instance-group-manager" instance_template = "${google_compute_instance_template.instance_template.self_link}" base_instance_name = "instance-group-manager" zone = "asia-northeast1-a" target_size = "10" }
インスタンスグループの更新方法を指定する必要がある
原因は update_strategy = "NONE"
としていたことでした。
update_strategy
についてドキュメントを確認します。
- update_strategy - (Optional, Default "REPLACE") If the instance_template resource is modified, a value of "NONE" will prevent any of the managed instances from being restarted by Terraform. A value of "REPLACE" will restart all of the instances at once. "ROLLING_UPDATE" is supported as a beta feature. A value of "ROLLING_UPDATE" requires rolling_update_policy block to be set
https://www.terraform.io/docs/providers/google/r/compute_instance_group_manager.html#update_strategy
つまり、デフォルトは REPLACE
(GCEインスタンスの再起動) になっていたのを NONE
にしたことで、旧インスタンステンプレートで起動していたGCEインスタンスから、新インスタンステンプレートで起動するGCEインスタンスへの変更ができなくなったためエラーになったというわけです。
ローリングアップデートでインスタンスを入れ替える
では、デフォルト値 REPLACE
で良いかと言われるとそうでもありません。
REPLACE
だと(一度切りの)再起動 なので、イメージを入れ替えるといった場合には適しません。ROLLING_UPDATE
にすべきです。
ドキュメントでは ROLLING_UPDATE
にする場合は rolling_update_policy
ブロックの追記が必要とのことなので、このようになります。
resource "google_compute_instance_template" "instance_template" { name_prefix = "instance-template-" machine_type = "n1-standard-1" region = "asia-northeast1" // boot disk disk { # ... } // networking network_interface { # ... } // 追加 update_strategy = "ROLLING_UPDATE" rolling_update_policy{ type = "PROACTIVE" minimal_action = "REPLACE" max_surge_percent = 20 max_unavailable_fixed = 1 min_ready_sec = 60 } lifecycle { create_before_destroy = true } } resource "google_compute_instance_group_manager" "instance_group_manager" { name = "instance-group-manager" instance_template = "${google_compute_instance_template.instance_template.self_link}" base_instance_name = "instance-group-manager" zone = "asia-northeast1-a" target_size = "10" }
こうすることで、2台ずつ(10台 * 20%) 新しいインスタンステンプレートによって起動されるGCEインスタンスに置き換えられるようになります。
インスタンスグループのアップデートについては私自身に完全に理解しきれていないのでちゃんと理解できるようになったら別記事で紹介したいと思います。
まとめ
Terraformでインスタンステンプレートを更新できない場合の対処方法を紹介しました。インスタンスグループ配下にある、GCEインスタンスの入れ替え(ローリングアップデート)を行なうことでインスタンステンプレートの入れ替えもできるようになります。 このローリングアップデートはGCPのマネジメントコンソール(GUI)からでも操作が可能なので、Terraformを使わないときでも便利なので、ぜひ使ってみてください。
参考
- Google: google_compute_instance_template - Terraform by HashiCorp
- Google: google_compute_instance_group_manager - Terraform by HashiCorp
- Updating Managed Instance Groups | Compute Engine Documentation | Google Cloud
*1:今回はマネージドインスタンスグループを前提としています