Terraform aws_launch_templateを使ったEC2自動化プログラミング例

2025-05-31

Terraform の aws_launch_template とは

aws_launch_template は、Terraform を使って AWS EC2 の起動テンプレート (Launch Template) を作成・管理するためのリソースです。

起動テンプレートとは、EC2 インスタンスを起動する際に使用する設定のテンプレートのことです。これには、AMI (Amazon Machine Image) ID、インスタンスタイプ、キーペア、セキュリティグループ、ユーザーデータ、ストレージ設定など、インスタンス起動に必要なあらゆる情報を含めることができます。

従来の「起動設定 (Launch Configuration)」に代わるもので、より柔軟で高機能な設定が可能です。特に、バージョン管理ができる点が大きな特徴です。

aws_launch_template を使うメリット

  1. バージョン管理: 起動テンプレートはバージョン管理が可能です。これにより、設定変更があった場合でも、以前のバージョンに簡単にロールバックしたり、新しい設定を段階的に導入したりすることができます。Terraform でも default_versionupdate_default_version などの引数を使ってバージョンを管理できます。
  2. 柔軟性: 起動設定よりも多くの設定項目(例えば、複数のネットワークインターフェース、スポットインスタンスのオプション、Dedicated Host のオプションなど)をサポートしており、より詳細なインスタンス設定が可能です。
  3. Auto Scaling Group との連携: Auto Scaling Group (ASG) は、起動テンプレートを参照して新しいインスタンスを起動します。これにより、ASG で起動するインスタンスの設定を簡単に変更・管理できます。
  4. EC2 Fleet との連携: EC2 Fleet も起動テンプレートを使用して、複数のインスタンスタイプや購入オプションを組み合わせたインスタンス群をプロビジョニングできます。

aws_launch_template の主な引数 (Arguments)

aws_launch_template リソースには、EC2 インスタンスのさまざまな側面を設定するための多くの引数があります。代表的なものをいくつかご紹介します。

  • disable_api_termination: APIからのインスタンス終了保護を有効にするかどうか。
  • ebs_optimized: EBS最適化インスタンスを有効にするかどうか。
  • tag_specifications: 起動テンプレートから作成されるリソース(EC2インスタンス、EBSボリューム、ネットワークインターフェースなど)に適用されるタグのリストです。
  • tags: 起動テンプレート自体に付与するタグです。
  • placement: インスタンスの配置設定(アベイラビリティゾーン、プレイスメントグループなど)です。
  • iam_instance_profile: インスタンスに割り当てるIAMインスタンスプロファイルのARNまたは名前です。これにより、EC2インスタンスが他のAWSサービスにアクセスするための権限を得られます。
  • network_interfaces: 複数のネットワークインターフェースを定義し、それぞれにIPアドレス、セキュリティグループ、パブリックIPの割り当てなどを設定できます。
  • block_device_mappings: インスタンスにアタッチするEBSボリュームやエフェメラルディスクの設定です。ボリュームサイズ、タイプ、暗号化などの設定が可能です。
  • user_data: インスタンスの初回起動時に実行されるスクリプトや設定(Base64 エンコードされたもの)です。Cloud-init などと組み合わせて使われることが多いです。
  • vpc_security_group_ids / security_group_names: インスタンスに関連付けるセキュリティグループの ID または名前のリストです。VPC 環境では vpc_security_group_ids を使うのが一般的です。
  • key_name: インスタンスに接続するためのキーペアの名前です。
  • instance_type: 起動するインスタンスのタイプ(例: t3.micro)です。
  • image_id: インスタンスの起動に使用する AMI の ID です。
  • description: 起動テンプレートの説明です。
  • name / name_prefix: 起動テンプレートの名前を指定します。name_prefix を使うと、Terraform がユニークな名前を自動生成します。

以下は、aws_launch_template を使って基本的な起動テンプレートを作成する Terraform のコード例です。

resource "aws_launch_template" "example" {
  name_prefix   = "my-web-app-lt-"
  image_id      = "ami-0abcdef1234567890" # 適切なAMI IDに置き換えてください
  instance_type = "t3.micro"
  key_name      = "my-ec2-keypair"      # 適切なキーペア名に置き換えてください

  network_interfaces {
    associate_public_ip_address = true
    security_groups             = [aws_security_group.web.id]
  }

  block_device_mappings {
    device_name = "/dev/sda1"
    ebs {
      volume_size = 30
      volume_type = "gp2"
    }
  }

  user_data = base64encode(<<EOF
#!/bin/bash
sudo yum update -y
sudo yum install -y httpd
sudo systemctl start httpd
sudo systemctl enable httpd
echo "<h1>Hello from Terraform Launch Template!</h1>" > /var/www/html/index.html
EOF
  )

  tags = {
    Name        = "MyWebAppLaunchTemplate"
    Environment = "Development"
  }
}

resource "aws_security_group" "web" {
  name        = "web-security-group"
  description = "Allow HTTP inbound traffic"
  vpc_id      = "vpc-0abcdef1234567890" # 適切なVPC IDに置き換えてください

  ingress {
    description = "HTTP from VPC"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

この例では、以下の設定を含む起動テンプレートを作成しています。

  • 起動テンプレート自体と、それを使って起動されるインスタンスにタグを設定
  • WebサーバーをインストールしてHTMLページをデプロイするユーザーデータ
  • 30GBのgp2タイプのEBSボリュームを/dev/sda1にアタッチ
  • 作成されるインスタンスにパブリックIPを割り当て、webセキュリティグループに関連付け
  • my-ec2-keypair というキーペア
  • 指定されたAMI IDとt3.microインスタンスタイプ
  • my-web-app-lt- で始まる名前

この aws_launch_template リソースは、AWS Auto Scaling Group や EC2 Fleet などの他のリソースから参照して、インスタンスをプロビジョニングするために利用されます。



Terraform aws_launch_template の一般的なエラーとトラブルシューティング

aws_launch_template は EC2 インスタンスの起動設定を細かく定義できるため、その分設定ミスによるエラーも発生しやすいです。ここでは、よくあるエラーパターンとその対処法を説明します。

不足している、または無効な引数 (Missing or Invalid Argument)

エラー例
Error: Invalid or unknown key: image_id Error: The argument "instance_type" is required but no definition was found.

原因
aws_launch_template に必須の引数(image_idinstance_type など)が指定されていない、またはスペルミスがある場合に発生します。また、存在しない値(例えば、無効な AMI ID やキーペア名)を指定した場合も同様のエラーが発生します。

トラブルシューティング

  • 値の検証
    指定した AMI ID、インスタンスタイプ、キーペア、セキュリティグループなどが実際に AWS アカウントとリージョンに存在し、アクセス可能であることを確認してください。例えば、AMI ID は ami-xxxxxxxxxxxxxxxxx の形式であるか、キーペア名が正確であるかなど。
  • スペルミスの確認
    引数名にスペルミスがないか、慎重に確認してください。
  • Terraform ドキュメントの確認
    aws_launch_template の公式ドキュメントで、必須の引数と許容される値の形式を確認してください。

権限不足 (Insufficient Permissions)

エラー例
Error: UnauthorizedOperation: You are not authorized to perform this operation. User: arn:aws:iam::xxxxxxxxxxxx:user/terraform-user is not authorized to perform: ec2:CreateLaunchTemplate on resource: arn:aws:ec2:ap-northeast-1:xxxxxxxxxxxx:launch-template/* Error: AccessDeniedException: User is not authorized to perform: ec2:DescribeImages

原因
Terraform を実行している IAM ユーザーまたはロールに、起動テンプレートの作成、変更、削除、または起動テンプレート内で参照されるリソース(AMI、セキュリティグループ、IAM インスタンスプロファイルなど)を操作するための適切な権限がない場合に発生します。

トラブルシューティング

  • 最小限の権限原則
    必要な権限のみを付与し、過剰な権限を与えないように注意してください。
  • 参照リソースの権限
    起動テンプレート内で参照している AMI、セキュリティグループ、IAM インスタンスプロファイルなどに対して、ec2:DescribeImages, ec2:DescribeSecurityGroups, iam:PassRole などの権限が付与されているかも確認が必要です。特に iam_instance_profile を使用する場合は、EC2 がそのロールを引き受けるための iam:PassRole 権限が重要です。
  • IAM ポリシーの確認
    Terraform を実行している IAM ユーザー/ロールに、ec2:CreateLaunchTemplate, ec2:DeleteLaunchTemplate, ec2:DescribeLaunchTemplates などの ec2 関連の権限が付与されているか確認してください。

ユーザーデータの形式不正 (Invalid User Data Format)

エラー例
Error: InvalidUserData.Malformed: Invalid BASE64 encoding of user data.

原因
user_data 引数に Base64 エンコードされていないデータ、または不正な形式のデータが渡された場合に発生します。

トラブルシューティング

  • スクリプトの構文確認
    ユーザーデータとして渡すシェルスクリプトや PowerShell スクリプト自体の構文に誤りがないか確認してください。EC2 インスタンス起動後にスクリプトが正しく実行されるか、手動でテストしてみるのも有効です。
  • base64encode() 関数の使用
    user_data には必ず base64encode() 関数を使用して Base64 エンコードされた文字列を渡す必要があります。
    user_data = base64encode(<<EOF
    #!/bin/bash
    echo "Hello World"
    EOF
    )
    

リソース間の依存関係エラー (Dependency Cycle Errors)

エラー例
Error: Cycle: aws_launch_template.example, aws_security_group.web

原因
Terraform ではリソース間の依存関係を自動的に解決しますが、循環参照(AがBに依存し、BがAに依存する)が発生するとこのエラーになります。例えば、起動テンプレートがセキュリティグループを参照し、そのセキュリティグループが起動テンプレートから作成されるリソースを参照しようとする場合など。

トラブルシューティング

  • アーキテクチャの見直し
    循環参照が発生している場合は、リソースの設計自体を見直す必要があるかもしれません。
  • aws_security_group_rule の利用
    セキュリティグループのルールをingressegressブロック内に直接記述するのではなく、aws_security_group_rule リソースとして分離することで、循環参照を回避できる場合があります。
    resource "aws_security_group" "web" {
      name        = "web-security-group"
      description = "Allow HTTP inbound traffic"
      vpc_id      = "vpc-xxxxxxxxxxxxxxxxx"
    }
    
    resource "aws_security_group_rule" "allow_http" {
      type              = "ingress"
      from_port         = 80
      to_port           = 80
      protocol          = "tcp"
      cidr_blocks       = ["0.0.0.0/0"]
      security_group_id = aws_security_group.web.id
    }
    
    resource "aws_launch_template" "example" {
      # ...
      network_interfaces {
        security_groups = [aws_security_group.web.id]
      }
      # ...
    }
    

重複する名前 (Duplicate Name)

エラー例
Error: A launch template with the name 'my-web-app-lt' already exists.

原因
同じ名前の起動テンプレートが既に存在する場合に発生します。aws_launch_templatename または name_prefix を必須とします。

トラブルシューティング

  • 既存リソースのインポートまたは削除
    もし手動で作成された同名の起動テンプレートがある場合、Terraform の状態にインポートするか、手動で削除することを検討してください。
  • name_prefix の利用
    name_prefix を使用すると、Terraform がユニークなサフィックスを自動で付与してくれるため、重複エラーを避けることができます。
  • ユニークな名前の指定
    name を使用している場合は、既存の起動テンプレートと重複しないユニークな名前を指定してください。

プロバイダのバージョン不整合 (Provider Version Mismatch)

エラー例
Error: Incompatible provider version! The plugin encountered an error, and failed to respond to the plugin.(*GRPCProvider).ApplyResourceChange call. (Provider Panicの場合)

原因
Terraform のバージョンや AWS プロバイダのバージョンが古すぎたり、構成と互換性がない場合に発生することがあります。特定の機能が新しいプロバイダバージョンでのみサポートされている場合や、古いバージョンではバグがある場合など。

  • AWS プロバイダの GitHub Issues を確認
    特定のエラーメッセージが出ている場合、AWS プロバイダの GitHub リポジトリの Issues を確認すると、同様の問題が報告されていないか、解決策が示されていないかを見つけられることがあります。
  • terraform init -upgrade の実行
    プロバイダを最新バージョンにアップグレードしてみてください。ただし、破壊的な変更がある場合はコードの修正が必要になることがあります。
  • プロバイダのバージョン固定
    required_providers ブロックで AWS プロバイダのバージョンを固定することをお勧めします。
    terraform {
      required_providers {
        aws = {
          source  = "hashicorp/aws"
          version = "~> 5.0" # または特定のバージョン(例: "5.31.0")
        }
      }
    }
    
  • Terraform のデバッグログ (TF_LOG)
    より詳細な情報を得るために、Terraform のログレベルを上げて実行することができます。
    TF_LOG=DEBUG terraform apply
    
    これにより、Terraform が AWS API とどのように通信しているか、詳細なリクエスト/レスポンス、エラーメッセージなどを確認できます。
  • AWS CloudTrail の利用
    Terraform が AWS API を呼び出す際に権限エラーなどが発生している場合、CloudTrail のイベント履歴を確認すると、どの API コールが失敗したか、どのようなエラーメッセージが返されたかなどの詳細な情報が得られます。
  • AWS コンソールでの確認
    エラーメッセージに記載されているリソース(AMI、セキュリティグループ、VPCなど)が、AWS コンソールで実際に存在し、設定が正しいかを確認します。
  • terraform plan の詳細確認
    terraform plan を実行し、Terraform が実際に何をしようとしているのか(作成、変更、削除されるリソースやそのプロパティ)を注意深く確認します。意図しない変更がないか、特に注意が必要です。
  • terraform validate の実行
    terraform apply の前に terraform validate を実行して、HCL (HashiCorp Configuration Language) の構文エラーや、プロバイダのスキーマに合致しない設定がないかを確認します。これにより、多くの初歩的なエラーを事前に検出できます。


aws_launch_template は EC2 インスタンスの起動設定を柔軟に定義できる強力なリソースです。ここでは、基本的な利用方法から、より実践的なシナリオでの使用例まで、いくつかご紹介します。

基本的な起動テンプレートの作成

最もシンプルな起動テンプレートの例です。必要なのは AMI ID とインスタンスタイプ、そしてユニークな名前だけです。

# main.tf

# AWS プロバイダの設定
provider "aws" {
  region = "ap-northeast-1" # 東京リージョンを使用
}

# (オプション) AMI ID を動的に取得
# 最新の Amazon Linux 2 AMI を取得する例
data "aws_ami" "amazon_linux_2" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["amzn2-ami-hvm-*-x86_64-gp2"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }
}

# 起動テンプレートの作成
resource "aws_launch_template" "basic_web_server" {
  name_prefix   = "web-server-template-" # ユニークな名前を生成するためにプレフィックスを使用
  image_id      = data.aws_ami.amazon_linux_2.id
  instance_type = "t3.micro"
  key_name      = "my-ec2-keypair" # 既存のEC2キーペア名を指定

  tags = {
    Name        = "BasicWebServerLaunchTemplate"
    Environment = "Development"
  }
}

output "launch_template_id" {
  description = "The ID of the created launch template"
  value       = aws_launch_template.basic_web_server.id
}

output "launch_template_latest_version" {
  description = "The latest version of the created launch template"
  value       = aws_launch_template.basic_web_server.latest_version
}

解説

  • resource "aws_launch_template" "basic_web_server": 起動テンプレートを作成します。
    • name_prefix: 起動テンプレートのユニークな名前を生成するためのプレフィックスです。Terraform が実行時にランダムなサフィックスを追加します。
    • image_id: インスタンスのベースとなる AMI の ID を指定します。ここでは data.aws_ami.amazon_linux_2.id を使って動的に取得しています。
    • instance_type: 起動する EC2 インスタンスのタイプを指定します。
    • key_name: EC2 インスタンスへの SSH 接続に使用するキーペアの名前を指定します。事前に作成しておく必要があります。
    • tags: 起動テンプレート自体に付与するタグです。
  • data "aws_ami": most_recent = true とフィルターを使って、常に最新の Amazon Linux 2 AMI を取得します。これにより、AMI ID をハードコードする手間が省け、AMI の更新にも対応しやすくなります。
  • provider "aws": AWS プロバイダを設定し、リージョンを指定します。

ユーザーデータとセキュリティグループを含む起動テンプレート

インスタンス起動時にスクリプトを実行したり、特定のセキュリティグループを割り当てたりする例です。

# main.tf (続き)

# Webサーバー用セキュリティグループの作成
resource "aws_security_group" "web_sg" {
  name        = "web-server-security-group"
  description = "Allow HTTP and SSH inbound traffic"
  vpc_id      = "vpc-0abcdef1234567890" # ご自身のVPC IDに置き換えてください

  ingress {
    description = "Allow HTTP from anywhere"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    description = "Allow SSH from anywhere"
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "WebServerSG"
  }
}

# ユーザーデータを含む起動テンプレートの作成
resource "aws_launch_template" "web_server_with_user_data" {
  name_prefix   = "web-server-user-data-lt-"
  image_id      = data.aws_ami.amazon_linux_2.id
  instance_type = "t3.small"
  key_name      = "my-ec2-keypair"

  # セキュリティグループの関連付け
  network_interfaces {
    associate_public_ip_address = true # パブリックIPを割り当てる
    security_groups             = [aws_security_group.web_sg.id]
  }

  # ユーザーデータ(Base64エンコード必須)
  user_data = base64encode(<<EOF
#!/bin/bash
echo "Hello, this is a web server instance!" > /var/www/html/index.html
sudo yum update -y
sudo yum install -y httpd
sudo systemctl start httpd
sudo systemctl enable httpd
echo "<h1>Deployed by Terraform Launch Template!</h1>" | sudo tee /var/www/html/index.html
EOF
  )

  tags = {
    Name = "WebServerUserDataLaunchTemplate"
  }
}

解説

  • user_data: インスタンスが初めて起動する際に実行されるスクリプトです。Apache HTTP サーバーをインストールし、簡単なHTMLページを配置しています。base64encode() 関数で Base64 エンコードする必要があります。
    • <<EOF ... EOF: ヒアドキュメント構文を使用しており、複数行のスクリプトを記述するのに便利です。
  • network_interfaces: 起動テンプレートでネットワークインターフェースの設定を定義します。
    • associate_public_ip_address = true: インスタンスにパブリック IP アドレスを自動割り当てします。
    • security_groups: 上で作成した web_sg の ID を指定し、この起動テンプレートから起動されるインスタンスに適用します。
  • aws_security_group "web_sg": HTTP (80番ポート) と SSH (22番ポート) を許可するセキュリティグループを作成します。

Auto Scaling Group と連携する起動テンプレート

aws_launch_template の最も一般的なユースケースの一つは、Auto Scaling Group (ASG) との連携です。

# main.tf (続き)

# (既存のサブネットを使用する場合)
data "aws_subnet_ids" "public" {
  vpc_id = "vpc-0abcdef1234567890" # ご自身のVPC IDに置き換えてください

  tags = {
    Name = "*-public-*" # 例: 名前に "public" を含むサブネットを取得
  }
}

# Auto Scaling Group 用のIAMロールとインスタンスプロファイル
resource "aws_iam_role" "asg_role" {
  name = "asg-role-for-launch-template"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "ec2.amazonaws.com"
        }
      },
    ]
  })
}

resource "aws_iam_role_policy_attachment" "s3_read_only" {
  policy_arn = "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess" # 例: S3への読み取り権限
  role       = aws_iam_role.asg_role.name
}

resource "aws_iam_instance_profile" "asg_profile" {
  name = "asg-instance-profile-for-launch-template"
  role = aws_iam_role.asg_role.name
}

# ASG と連携する起動テンプレート
resource "aws_launch_template" "asg_web_template" {
  name_prefix   = "asg-web-lt-"
  image_id      = data.aws_ami.amazon_linux_2.id
  instance_type = "t3.medium"
  key_name      = "my-ec2-keypair"

  iam_instance_profile {
    arn = aws_iam_instance_profile.asg_profile.arn
  }

  network_interfaces {
    associate_public_ip_address = true
    security_groups             = [aws_security_group.web_sg.id]
  }

  user_data = base64encode(<<EOF
#!/bin/bash
sudo yum update -y
sudo yum install -y httpd
sudo systemctl start httpd
sudo systemctl enable httpd
echo "<h1>Hello from ASG Instance!</h1>" | sudo tee /var/www/html/index.html
EOF
  )

  tag_specifications {
    resource_type = "instance"
    tags = {
      Name = "ASG-Instance"
      ManagedBy = "Terraform"
    }
  }

  tag_specifications {
    resource_type = "volume"
    tags = {
      Name = "ASG-Instance-Volume"
      ManagedBy = "Terraform"
    }
  }
}

# Auto Scaling Group の作成
resource "aws_autoscaling_group" "web_asg" {
  name                = "my-web-autoscaling-group"
  desired_capacity    = 2
  max_size            = 5
  min_size            = 1
  vpc_zone_identifier = data.aws_subnet_ids.public.ids # パブリックサブネットを指定

  # 起動テンプレートの指定
  launch_template {
    id      = aws_launch_template.asg_web_template.id
    version = "$$Latest$$" # 常に最新バージョンを使用
  }

  tags_as_map = { # ASG自体に適用されるタグ
    Name = "MyWebASG"
    Environment = "Production"
  }

  health_check_type          = "EC2"
  health_check_grace_period  = 300 # 秒
  target_group_arns          = [] # ALBのターゲットグループと連携する場合に指定
  force_delete               = true # ASGを削除する際に、内部のインスタンスも強制終了させる

  lifecycle {
    create_before_destroy = true # 既存のASGが削除される前に新しいASGを作成
  }
}

解説

  • aws_autoscaling_group "web_asg": Auto Scaling Group を作成します。
    • desired_capacity, max_size, min_size: ASG のスケーリング設定を定義します。
    • vpc_zone_identifier: インスタンスを起動するサブネットのリストを指定します。
    • launch_template: ここで上で定義した起動テンプレートを参照します。
      • id: 起動テンプレートの ID を指定します。
      • version: 使用する起動テンプレートのバージョンを指定します。$$Latest$$ と指定することで、常に最新のバージョンを使用するように設定できます。これにより、起動テンプレートを更新しても ASG が自動的に最新の設定を適用するようになります。
    • tags_as_map: ASG リソース自体に付与するタグです。tag_specifications とは異なり、ASG から起動されるインスタンスには適用されません。
  • aws_launch_template "asg_web_template": ASG 用の起動テンプレートを作成します。
    • iam_instance_profile: 作成した IAM インスタンスプロファイルを指定します。
    • tag_specifications: ここが重要です。インスタンス起動時にインスタンスとボリュームに特定のタグを自動で付与します。resource_type でタグを適用するリソースタイプを指定します。
  • aws_iam_role & aws_iam_instance_profile: EC2 インスタンスが AWS サービス(この例では S3)にアクセスするための IAM ロールとインスタンスプロファイルを作成します。iam_instance_profile は起動テンプレートで参照されます。
  • data "aws_subnet_ids": ASG がインスタンスを起動するサブネットを指定するために、既存のパブリックサブネットの ID を取得します。

起動テンプレートのバージョン管理と更新

aws_launch_template はバージョン管理機能を持ち、既存の起動テンプレートを更新する際に新しいバージョンを作成します。

# main.tf (続き)

# (上記で作成した aws_launch_template.asg_web_template を前提とします)

# 起動テンプレートの更新(新しいバージョンが作成される)
# インスタンスタイプを t3.medium から t3.large に変更する場合
resource "aws_launch_template" "asg_web_template_v2" {
  # 既存の起動テンプレート名を指定 (name_prefix で作成した場合は正確な名前を指定)
  # name が変わると別のリソースと認識されるため注意
  name = aws_launch_template.asg_web_template.name # 既存のテンプレートの名前を参照

  # 変更したい設定のみ記述 (ここではインスタンスタイプとユーザーデータ)
  image_id      = data.aws_ami.amazon_linux_2.id
  instance_type = "t3.large" # インスタンスタイプを変更
  key_name      = "my-ec2-keypair"

  iam_instance_profile {
    arn = aws_iam_instance_profile.asg_profile.arn
  }

  network_interfaces {
    associate_public_ip_address = true
    security_groups             = [aws_security_group.web_sg.id]
  }

  user_data = base64encode(<<EOF
#!/bin/bash
sudo yum update -y
sudo yum install -y httpd
sudo systemctl start httpd
sudo systemctl enable httpd
echo "<h1>Hello from ASG Instance (Updated Version)!</h1>" | sudo tee /var/www/html/index.html
EOF
  )

  # `update_default_version = true` を指定すると、Terraform が
  # このリソースの変更で作成された最新バージョンをデフォルトに設定します。
  # これにより、ASGが$$Latest$$を参照している場合に自動的に新しいバージョンが適用されます。
  update_default_version = true

  tag_specifications {
    resource_type = "instance"
    tags = {
      Name = "ASG-Instance-Updated"
      ManagedBy = "Terraform"
      Version = "2.0" # タグでバージョンを識別
    }
  }

  tag_specifications {
    resource_type = "volume"
    tags = {
      Name = "ASG-Instance-Volume-Updated"
      ManagedBy = "Terraform"
    }
  }

  tags = {
    Name = "ASGWebLaunchTemplate" # テンプレート自体のタグも更新
  }
}

# Auto Scaling Group は、launch_template の version = "$$Latest$$" の設定により、
# 上記の変更で新しいバージョンがデフォルトになった際に自動的に新しいバージョンを使用します。
# ASG のインスタンスを更新するには、インスタンスの「リフレッシュ」操作(ローリングアップデート)が必要です。
# これは、ASG の `desired_capacity` を一時的に変更したり、
# `aws_autoscaling_group` リソースの `triggers` や外部スクリプトなどで行います。
  • 重要な注意点
    aws_launch_template リソースの属性を変更すると、新しい起動テンプレートのバージョンが作成されます。aws_autoscaling_group がその新しいバージョンを使用するためには、launch_template ブロックの version$$Latest$$ に設定しておくことが一般的です。しかし、ASG が新しい起動テンプレートバージョンを適用するのは、既存のインスタンスが置き換えられる際(スケーリングイベント、ヘルスチェックの失敗、手動のインスタンス終了、または ASG のインスタンスリフレッシュ)です。既存のインスタンスを直ちに更新したい場合は、ASG のインスタンスリフレッシュ機能を使用するか、ローリングアップデートのトリガーを検討する必要があります。
  • aws_launch_template "asg_web_template_v2": 既存の起動テンプレートを更新する際に、同じ name を指定することで、新しいバージョンが作成されます。
    • name = aws_launch_template.asg_web_template.name: 既に存在する起動テンプレートの名前を正確に指定することが重要です。name_prefix を使用して作成した場合は、terraform state show などで正確な名前を確認する必要があります。
    • update_default_version = true: このオプションを true に設定すると、Terraform がこのリソースに変更を適用するたびに、新しく作成された起動テンプレートのバージョンがそのテンプレートのデフォルトバージョンとして設定されます。ASGが version = "$$Latest$$" を参照している場合、ASG は自動的にこの新しいデフォルトバージョンを使用するようになります。
    • ユーザーデータやタグなど、変更したい属性を記述します。


aws_launch_configuration (旧来の方法、非推奨)

  • Terraform コード例 (非推奨)

    resource "aws_launch_configuration" "deprecated_lc" {
      name_prefix          = "deprecated-lc-"
      image_id             = "ami-0abcdef1234567890" # 適切なAMI IDに置き換えてください
      instance_type        = "t2.micro"
      security_groups      = [aws_security_group.web_sg_lc.id]
      key_name             = "my-ec2-keypair"
      associate_public_ip_address = true
      user_data            = base64encode("echo 'Hello from deprecated Launch Configuration!'")
    
      lifecycle {
        create_before_destroy = true # 変更時に新しいLCを作成してから古いLCを削除
      }
    }
    
    resource "aws_security_group" "web_sg_lc" {
      name        = "deprecated-lc-sg"
      description = "Security group for deprecated LC"
      vpc_id      = "vpc-0abcdef1234567890" # ご自身のVPC IDに置き換えてください
    
      ingress {
        from_port   = 80
        to_port     = 80
        protocol    = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
      }
    }
    
    # ASG との連携 (launch_configuration を使用)
    resource "aws_autoscaling_group" "asg_with_lc" {
      name                = "my-deprecated-asg"
      desired_capacity    = 1
      max_size            = 3
      min_size            = 1
      vpc_zone_identifier = ["subnet-0a1b2c3d4e5f6g7h8"] # 適切なサブネットIDに置き換えてください
    
      launch_configuration = aws_launch_configuration.deprecated_lc.name
    
      tag {
        key                 = "Name"
        value               = "DeprecatedASGInstance"
        propagate_at_launch = true
      }
    }
    

    注意点
    現在新規プロジェクトで aws_launch_configuration を使用することは強く推奨されません。既存のシステムからの移行時のみ検討されるべきです。

    • 不変性 (Immutability)
      aws_launch_configuration は作成後に変更できません。設定を変更するには、新しい起動設定を作成し、ASG を新しい設定に更新する必要がありました。これは管理が煩雑になる原因でした。
    • バージョン管理の欠如
      起動テンプレートとは異なり、起動設定にはバージョン管理の概念がありません。
    • 機能の制限
      起動テンプレートがサポートする多くの新しい EC2 機能(例: T2/T3 Unlimited, Dedicated Hosts, EC2 Fleet、複数のインスタンスタイプ、高度なネットワーク設定、インスタンス属性ベースの選択など)をサポートしていません。
    • AWS による非推奨化
      AWS は2022年12月31日以降にリリースされた新しい EC2 インスタンスタイプへのサポートを起動設定に追加しておらず、将来的には新しい AWS アカウントでの起動設定の作成が制限される予定です。

aws_instance リソースの直接利用

  • Terraform コード例

    resource "aws_instance" "single_instance" {
      ami           = "ami-0abcdef1234567890" # 適切なAMI IDに置き換えてください
      instance_type = "t3.micro"
      key_name      = "my-ec2-keypair"
      subnet_id     = "subnet-0a1b2c3d4e5f6g7h8" # 適切なサブネットIDに置き換えてください
      vpc_security_group_ids = [aws_security_group.single_instance_sg.id]
    
      user_data = base64encode(<<EOF
    
  • いつ使うか

    • ASG を必要としない、独立した単一のインスタンス(例: 踏み台サーバー、開発用インスタンス、特定の固定IPが必要なサーバー)。
    • Auto Scaling や負荷分散を目的としない場合。

#!/bin/bash echo "Hello from a single Terraform-managed instance!" > /var/www/html/index.html sudo yum update -y sudo yum install -y httpd sudo systemctl start httpd sudo systemctl enable httpd EOF )

  tags = {
    Name = "MySingleEC2Instance"
    ManagedBy = "Terraform"
  }
}

resource "aws_security_group" "single_instance_sg" {
  name        = "single-instance-sg"
  description = "Security group for single EC2 instance"
  vpc_id      = "vpc-0abcdef1234567890" # ご自身のVPC IDに置き換えてください

  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
```
  • Cons
    自動スケーリングやインスタンスの自己修復機能が必要な場合は、ASG と aws_launch_template の組み合わせが必須です。
  • Pros
    シンプルなインスタンス管理に適しています。

aws_autoscaling_group 内での mixed_instances_policy の利用

  • Terraform コード例

    # main.tf (続き)
    
    # 起動テンプレート (基本設定用)
    resource "aws_launch_template" "base_template" {
      name_prefix   = "mixed-instances-base-"
      image_id      = data.aws_ami.amazon_linux_2.id
      key_name      = "my-ec2-keypair"
    
      network_interfaces {
        associate_public_ip_address = true
        security_groups             = [aws_security_group.web_sg_lc.id] # 既存のSGを使用
      }
    
      user_data = base64encode(<<EOF
    
  • いつ使うか

    • ASG で複数種類のインスタンスタイプを使用したい場合(例: t3.medium がなければ t3.large も使う)。
    • オンデマンドとスポットインスタンスを組み合わせてコストを削減したい場合。
    • 柔軟なキャパシティ管理が必要な場合。

#!/bin/bash echo "Hello from a mixed instance policy ASG!" EOF )

  tags = {
    Name = "MixedInstancesBaseLT"
  }
}

# Auto Scaling Group で mixed_instances_policy を使用
resource "aws_autoscaling_group" "mixed_asg" {
  name                = "my-mixed-instances-asg"
  desired_capacity    = 2
  max_size            = 5
  min_size            = 1
  vpc_zone_identifier = data.aws_subnet_ids.public.ids

  # mixed_instances_policy を定義
  mixed_instances_policy {
    launch_template {
      launch_template_id = aws_launch_template.base_template.id
      version            = "$$Latest$$" # 最新バージョンを使用

      # ここでインスタンスタイプをオーバーライド
      override {
        instance_type = "t3.medium"
      }
      override {
        instance_type = "t3.large"
        weighted_capacity = "2" # t3.large は t3.medium の2倍のキャパシティとみなす
      }
      override {
        instance_type = "c5.large"
        lifecycle = "SPOT" # このインスタンスタイプはスポットで購入
      }
    }

    instances_distribution {
      on_demand_base_capacity                  = 1 # 最小1インスタンスはオンデマンド
      on_demand_percentage_above_base_capacity = 50 # 残りのキャパシティの50%をオンデマンド
      spot_allocation_strategy                 = "capacity-optimized" # スポットはキャパシティ最適化戦略
    }
  }

  tags_as_map = {
    Name        = "MixedInstancesASG"
    Environment = "Production"
  }

  health_check_type          = "EC2"
  health_check_grace_period  = 300
}
```
  • Cons
    設定がより複雑になります。
  • Pros
    高度なスケーリング戦略、コスト最適化、可用性の向上。

AWS CloudFormation / CDK

  • Cons
    • AWS 以外のクラウドプロバイダには対応していません。
    • 既存のインフラストラクチャをインポートする機能が Terraform ほど柔軟でない場合があります。
    • 学習曲線が Terraform とは異なります。
  • Pros
    • AWS の新機能への対応が早い。
    • AWS サービスとの深い統合。
    • CDK を使うことで、プログラミング言語の論理的構造を利用できる。
  • いつ使うか
    • AWS エコシステムに完全にロックインされることを許容できる場合。
    • AWS のネイティブなサービスとのより深い統合を優先する場合。
    • 開発チームが特定のプログラミング言語に習熟している場合(CDK)。

Packer + Ansible/Chef/Puppet (AMI 生成 + プロビジョニング)

  • Cons
    • ビルドパイプラインが複雑になる。
    • AMI の生成と管理にオーバーヘッドが生じる。
  • Pros
    • インスタンス起動時間が短縮される(必要なソフトウェアが AMI に含まれるため)。
    • 変更管理が容易になる(AMI バージョンで管理)。
    • 一貫性のある環境を確保できる。
  • いつ使うか
    • AMI をより頻繁に更新し、管理したい場合(Golden AMI の作成)。
    • EC2 インスタンス起動時のユーザーデータスクリプトが複雑になりすぎるのを避けたい場合。
    • コンプライアンス要件やセキュリティポリシーを AMI に組み込みたい場合。

aws_launch_template は、特に Auto Scaling Group と連携して EC2 インスタンスを柔軟かつ効率的に管理するための 現在推奨されるベストプラクティス です。そのバージョン管理機能と豊富な設定オプションにより、ほとんどのシナリオで最適な選択肢となります。

しかし、以下のような場合は代替方法も検討できます。

  • インスタンス起動後の詳細な構成管理
    Packer と構成管理ツールを組み合わせて Golden AMI を作成し、それを aws_launch_template で利用する。
  • AWS 専用環境での IaC 統一
    CloudFormation / CDK を検討。
  • 古い ASG 構成の移行
    aws_launch_configuration から aws_launch_template への移行。
  • 単一の独立したインスタンス
    aws_instance を直接使用。