死なずに生きるのが得意

海の見える丘の上の家に光回線を引いてリモートワークで暮らしたい

(local-execつかったほうがいいよ) aws_spot_instance_request でインスタンスに terraform 管理下のタグをつける

はじめに

おとなしく local-exec 使ったほうが時間が節約されます。

背景

terraform の aws provider でスポットインスタンスを利用するには、 aws_spot_instance_request を使う。

ただ、この resource には作成されたインスタンスに対するタグ付与機能が ない 。タグをつけるには事後処理が必要となる。

resource aws_spot_instance_requesttag の仕様について

aws_spot_instance_request は、言ってしまえば aws_instance にスポットインスタンス起動に必要な設定項目を追加したものである。 そのため、 tags の適用対象は スポットリクエス であり、インスタンスではない。

では、インスタンス側にそれを適用する方法があるのかというと、ない。

issue はあった

皆おなじことを思うためか、issue がある。 issue issue2

AWSAPI として用意していない方法を aws provider 独自に実装することは無い (っぽい) ため、多分今後もない。

回避方法

local-exec を使う

issue にて紹介されていた方法。

リソース作成後、 local-exec を使って AWS CLI を実行する方法である。

シンプルで十分な方法なのだが、タグが terraform の管理対象から外れてしまう。 local-exec を使う以上仕方ないのだが、terraform を使う意義が (所詮タグだが) 薄れてしまうのでできれば避けたい。

aws_ec2_tag を使う (この記事で説明)

タグも terraform で管理したいならば、 aws_ec2_tag を使えばよい。

しかし、単に aws_spot_instance_requestaws_ec2_tag を抱き合わせて使うと問題が起きる。 aws_ec2_tag では resource_idインスタンス ID を与える必要があるが、 aws_spot_instance_request の出力から spot_instance_id が取得できるようになるにはタイムラグがある。 そして、そのタイムラグを terraform は考慮してくれない。 このような挙動が起きうることはドキュメントにも記載されている。

These attributes are exported, but they are expected to change over time and so should only be used for informational purposes, not for resource dependencies:

spot_bid_status - The current bid status of the Spot Instance Request. spot_request_state The current request state of the Spot Instance Request. spot_instance_id - The Instance ID (if any) that is currently fulfilling the Spot Instance request. public_dns - The public DNS name assigned to the instance. For EC2-VPC, this is only available if you've enabled DNS hostnames for your VPC public_ip - The public IP address assigned to the instance, if applicable. private_dns - The private DNS name assigned to the instance. Can only be used inside the Amazon EC2, and only available if you've enabled DNS hostnames for your VPC private_ip - The private IP address assigned to the instance tags_all - A map of tags assigned to the resource, including those inherited from the provider default_tags configuration block.

引用元: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/spot_instance_request#attributes-reference

そのため、タグ付与は別 tfstate に分けることとする。 1

スポットリクエストを作成した tfstate に aws_spot_instance_requestoutput し、別 terraform から参照する。 出力されているスポットリクエスト情報にある spot_instance_id をもとにインスタンスを取得し、 aws_ec2_tag でタグを付与する。

local-exec に頼らない方法としてこちらをやってみたので内容を説明する。

スポットリクエスト作成側

resource "aws_spot_instance_request" "instance" {
  for_each = local.mariadb_instances

  # インスタンスに関する 各種設定
}

output "spot_request" {
  value = aws_spot_instance_request.instance
}

タグ付与側

data "terraform_remote_state" "state" {
  # 利用している tfstate 保存方法にあわせてよしなに設定する
}

resource "aws_ec2_tag" "tag" {

  resource_id = data.terraform_remote_state.state.outputs.spot_request.spot_instance_id
  key         = "Name"
  value       = "spot-instance"
}

終わりに

脚注でも書いたが、正直 local-exec でいい。 aws_spot_instance_request を使うようなシチュエーションは検証がほとんどなので。

それか AutoScaling つかって起動テンプレートに書けばいいと思う。でも固定 Private IP とかしたい場合は無理なのでやっぱり local-exec でいいとおもう。

追記

output するタイミングで spot_instance_id が確定していないので、「スポットリクエスト作成側」の terraform は 2 回実行する必要があるので、やっぱ local-exec でいいと思います。


  1. この時点でめんどい。そもそも aws_spot_instance_request を使うような状況は検証時なので、それならタグが terraform 管理から漏れてもどうでもいいため、 local-exec でいいと思う。