Terraform moduleでEC2作成時のEBS追加を柔軟に制御する方法

Terraformを使ってインフラストラクチャをコード化する際、特定のリソースに対して柔軟に設定を適用したい場合があります。 しかし、全てのインスタンスに同じ設定を適用したいわけではない場合、どのように対処すればよいでしょうか。

課題

例えば、EC2インスタンスのモジュールを作成しているとします。
その中には追加のEBSが必要なインスタンスと、必要無いインスタンスが混在しています。
しかし、モジュールにEBSの設定を含めると全てのインスタンスにEBSが追加されてしまいます。

解決策

これに対する解決策として、Terraformにはdynamicブロックという便利な機能があります。
これを使うと、条件によってリソースのブロックを動的に生成することが可能になります。

TerraformのDynamicブロックとは

dynamicブロックは、Terraformでリソースやモジュールのブロック内にそのブロックのリストを動的に作成するために使用します。 dynamicブロックの内部ではcontentブロックを使用して、ブロックの内容を定義します。

EBSの有無を制御する

EC2インスタンスのモジュールでEBSの追加を制御したい場合、以下のように記述します。

variable "system" {}
variable "env" {}
variable "ami" {}
variable "instance_type" {}
variable "security_group" {}
variable "subnet" {}
variable "key_name" {}
variable "create_ebs" {
  default     = false
}
variable "ebs_size" {
  default     = 10
}

resource "aws_instance" "demo" {
  ami                         = var.ami
  instance_type               = var.instance_type
  vpc_security_group_ids      = var.security_group
  subnet_id                   = var.subnet
  associate_public_ip_address = "true"
  key_name                    = var.key_name
  tags = {
    Name = "${var.system}-${var.env}"
  }
  dynamic "ebs_block_device" {
    for_each = var.create_ebs ? [1] : []
    content {
      device_name           = "/dev/sdf"
      volume_type           = "gp2"
      volume_size           = var.ebs_size
      delete_on_termination = true
    }
  }
}

ここでは、for_eachに条件を指定し、その結果に応じてEBSのブロックを作成するかどうかを制御しています。var.create_ebstrueの場合、for_each[1]を返し、1つのEBSブロックが作成されます。falseの場合、for_eachは空のリストを返し、EBSブロックは作成されません。

このように、dynamicブロックを利用することで、EBSの有無を柔軟に制御することが可能になります。これにより、同一のモジュールを使用して、EBSの有無が異なるEC2インスタンスを効率的に作成できます。

参考:moduleの呼び出し元
moduleにcreate_ebs = trueを渡すかどうかでEBSの追加を制御していることが分かります。

module "ec2_with_ebs" {
  source         = "/home/ec2-user/terraform/module/"
  system         = "demo"
  env            = "prd"
  ami            = "ami-xxxx"
  instance_type  = "t2.micro"
  security_group = ["xxxx", "sg-xxxx"]
  subnet         = "subnet-xxxx"
  key_name       = "xxxx"
  create_ebs = true #ここ!
  ebs_size   = 20
}

module "ec2_without_ebs" {
  source         = "/home/ec2-user/terraform/module/"
  system         = "demo"
  env            = "stg"
  ami            = "ami-xxxx"
  instance_type  = "t2.micro"
  security_group = ["sg-xxxx", "sg-xxxx"]
  subnet         = "subnet-xxxx"
  key_name       = "xxxx"
}

まとめ

dynamicブロックを利用することで、リソースの設定を動的に制御することが可能なことが分かりました。
これにより同一のモジュールを使用しつつ、インスタンスの特性に応じて設定を変更することが可能になります。
ただし、全てをdynamicで制御するとコードが複雑になってしまうため注意が必要です。
皆様の選択肢の一つとしてお役に立てれば幸いです。