[Terraform] EC2のEBS追加ボリュームをサイズ拡張しようとしたらハマった話

ebs_block_deviceの仕様をちゃんと把握していますか?
2024.02.29

こんにちは!コンサル部のinomaso(@inomasosan)です。

検証時や案件対応時にはTerraformでEC2を作成することが多いです。

ある日、EBSルートボリューム以外のEBS追加ボリュームのサイズ拡張が必要となったのですが、サイズの変更を検出しなかったりEC2自体を再作成するような挙動がみられたので調査してみました。

先に結論

  • ebs_block_deviceは初回のリソース作成時にのみ適用されるため、リソース作成後の変更は検出されない。
  • DBやファイルサーバ等の用途で、将来的にEBS追加ボリュームのサイズ変更が必要な場合は、aws_ebs_volumeaws_volume_attachmentを使用すること。
    • ただし、delete_on_terminationオプションが存在しないため注意。

検証環境

今回実行した環境は以下の通りです。

項目 バージョン
Terraform 1.7.4
AWSプロバイダー 5.38.0

事象について

以下のコードは、Amazon Linux 2023を作成した際のEBSボリューム部分の抜粋です。
EBS追加ボリュームはebs_block_deviceで定義しています。  

resource "aws_instance" "main" {
  ~中略~
  # EBSルートボリューム
  root_block_device {
    # ボリュームサイズ(GiB)
    volume_size = 8
    # ボリュームタイプ
    volume_type = "gp3"
    # GP3のIOPS
    iops = 3000
    # GP3のスループット
    throughput = 125
    # EC2終了時に削除
    delete_on_termination = true
    # EBS暗号化
    encrypted = "true"
    # EBSのNameタグ
    tags = {
      Name = "inomaso-dev-ec2-xvda"
    }
  }
  # EBS追加ボリューム
  ebs_block_device {
    device_name = "/dev/sdf"
    # ボリュームサイズ(GiB)
    volume_size = 8
    # ボリュームタイプ
    volume_type = "gp3"
    # GP3のIOPS
    iops = 3000
    # GP3のスループット
    throughput = 125
    # EC2終了時に削除
    delete_on_termination = true
    # EBS暗号化
    encrypted = "true"<br />
    # EBSのNameタグ
    tags = {
      Name = "inomaso-dev-ec2-sdf"
    }
  }
}

EBSルートボリュームのサイズ拡張は、root_block_devicevolume_sizeを変更すれば、terraform applyterraform planを実行時に該当部分の変更を検出してくれます。

一方で、EBS追加ボリュームのサイズ拡張は、ebs_block_devicevolume_sizeを変更しても、変更が検出されずNo changesと出力されます。

また、ebs_block_deviceブロック自体を追加すると、EC2自体を再作成するような挙動になることがわかりました。

原因について

Terraform公式ドキュメントを確認したところ、以下のような記載がありました。

Currently, changes to the ebs_block_device configuration of existing resources cannot be automatically detected by Terraform. To manage changes and attachments of an EBS block to an instance, use the aws_ebs_volume and aws_volume_attachment resources instead. If you use ebs_block_device on an aws_instance, Terraform will assume management over the full set of non-root EBS block devices for the instance, treating additional block devices as drift. For this reason, ebs_block_device cannot be mixed with external aws_ebs_volume and aws_volume_attachment resources for a given instance.

ebs_block_deviceは初回のリソース作成時にのみ適用され、以降は変更を検出することができない仕様のようです。

変更を検出させたい場合はaws_ebs_volumeaws_volume_attachmentを使用する必要があるようです。

改善してみたものの思わぬ落とし穴が

ebs_block_deviceブロックを削除して、aws_ebs_volumeaws_volume_attachmentで書き直してみました。

resource "aws_instance" "main" {
  ~中略~
  # EBSルートボリューム
  root_block_device {
    # ボリュームサイズ(GiB)
    volume_size = 8
    # ボリュームタイプ
    volume_type = "gp3"
    # GP3のIOPS
    iops = 3000
    # GP3のスループット
    throughput = 125
    # EC2終了時に削除
    delete_on_termination = true
    # EBS暗号化
    encrypted = "true"
    # EBSのNameタグ
    tags = {
      Name = "inomaso-dev-ec2-xvda"
    }
  }
}

# EBS追加ボリューム
resource "aws_ebs_volume" "sdf" {
  availability_zone = "ap-northeast-1a"
  # ボリュームサイズ(GiB)
  size = 8
  # ボリュームタイプ
  type = "gp3"
  # GP3のIOPS
  iops = 3000
  # GP3のスループット
  throughput = 125
  # EBS暗号化
  encrypted = "true"
  # EBSのNameタグ
  tags = {
      Name = "inomaso-dev-ec2-sdf"
  }
}

resource "aws_volume_attachment" "sdf" {
  device_name = "/dev/sdf"
  volume_id   = aws_ebs_volume.sdf.id
  instance_id = aws_instance.main.id
}

リソース作成後にsizeを変更したところ、ちゃんと変更を検出してくれました。

ただしこの書き方の場合に一つ落とし穴がありました。
それはdelete_on_terminationオプションが存在しないことです。

例えばTerraform以外でEC2を削除した際に、EBS追加ボリュームはEC2と一緒に削除されません。

現状はAWS CLI等で対応する必要があるのですが、対象数が多い場合は以下のブログを参考に対応すると良いでしょう。

将来的な改善

調べてみたところ、delete_on_terminationオプションを追加するプルリクがオープンされていました。

そのうち対応されることを願いつつ、現状はTerraform + AWS CLIで急場を凌ぎたく思います。

まとめ

TerraformでEC2の構築はこれまでたくさんやってきましたが、思わぬ落とし穴にハマりびっくりしました。 改めて公式ドキュメントをしっかり確認することの大切さを痛感しました。

この記事が、どなたかのお役に立てば幸いです。それでは!