★★ 中級

16. Auto Scaling Group / Launch Template

EC2 を自動で増減させる仕組み。トラフィック変動への対応、健全性ベースの自動入れ替え、ローリングデプロイ等の基盤。

登場人物

用語役割
Launch Template「どのインスタンスをどう起動するか」のテンプレート(AMI、type、user_data 等)
Auto Scaling Group (ASG)「N 台を維持」「死んだら作り直す」「需要に応じて増減する」を司る
Scaling Policy「いつ何台に増減するか」のルール(CPU 70% で +1 など)
Target GroupALB / NLB がトラフィックを送る先プール。ASG がここに自動登録

aws_launch_template

# Launch Template:起動時のスペック雛形
resource "aws_launch_template" "web" {
  name_prefix   = "web-"
  image_id      = data.aws_ami.al2023.id
  instance_type = "t3.micro"
  key_name      = aws_key_pair.deployer.key_name

  vpc_security_group_ids = [aws_security_group.app.id]

  # EC2 が AWS API を叩くためのロール(instance_profile 経由)
  iam_instance_profile {
    name = aws_iam_instance_profile.ec2.name
  }

  # 起動時に走るスクリプト(user_data は base64 必須)
  user_data = base64encode(<<-EOT
    #!/bin/bash
    dnf install -y nginx
    systemctl enable --now nginx
    echo "Hello from $(hostname)" > /usr/share/nginx/html/index.html
  EOT
  )

  # ルートディスク設定
  block_device_mappings {
    device_name = "/dev/xvda"
    ebs {
      volume_size           = 20
      volume_type           = "gp3"
      encrypted             = true
      delete_on_termination = true   # インスタンス終了でボリュームも削除
    }
  }

  # 起動するインスタンスにタグを付与
  tag_specifications {
    resource_type = "instance"
    tags          = { Name = "web", Tier = "frontend" }
  }

  # IMDS(メタデータサービス)の設定
  metadata_options {
    http_tokens                 = "required"   # IMDSv2 強制(v1 拒否、セキュリティ向上)
    http_put_response_hop_limit = 1            # コンテナからメタデータ取得を防ぐ
  }

  lifecycle {
    create_before_destroy = true   # 更新時に新版を先に作成
  }
}

aws_autoscaling_group

# Auto Scaling Group:N 台維持と自動増減を担うマネージャ
resource "aws_autoscaling_group" "web" {
  name_prefix         = "web-"
  # 配置する subnet(複数 AZ にまたがると高可用性)
  vpc_zone_identifier = [for s in aws_subnet.private : s.id]

  min_size         = 2     # 最低キープする台数
  desired_capacity = 3     # 平常時の希望台数
  max_size         = 10    # スケール上限

  health_check_type         = "ELB"   # ALB のヘルスチェックを基準に(EC2 単体より厳密)
  health_check_grace_period = 300     # 起動から N 秒は失敗を無視(起動完了待ち)

  # 上で作った Launch Template を参照("$Latest" は最新版、版番号も可)
  launch_template {
    id      = aws_launch_template.web.id
    version = "$Latest"
  }

  # ALB の Target Group に自動登録(起動時 attach、終了時 detach)
  target_group_arns = [aws_lb_target_group.web.arn]

  # ASG 自身のタグ(インスタンスにも伝播)
  tag {
    key                 = "ManagedBy"
    value               = "Terraform"
    propagate_at_launch = true
  }

  lifecycle {
    create_before_destroy = true
    ignore_changes        = [desired_capacity]   # スケーリングポリシーが管理する
  }
}

スケーリングポリシー

Target Tracking(推奨)

「平均 CPU 50% を維持して」のように 目標値 を伝えるだけ。AWS が自動で増減を計算。

# Target Tracking:目標値だけ伝えれば AWS が自動計算
resource "aws_autoscaling_policy" "cpu" {
  name                   = "target-cpu"
  autoscaling_group_name = aws_autoscaling_group.web.name
  policy_type            = "TargetTrackingScaling"

  target_tracking_configuration {
    predefined_metric_specification {
      predefined_metric_type = "ASGAverageCPUUtilization"   # 平均 CPU
    }
    target_value = 50.0     # 50% を維持するように増減
  }
}

Step Scaling(細かく制御したい時)

# Step Scaling:「閾値超過量に応じて何台増やすか」を段階的に指定
resource "aws_autoscaling_policy" "scale_out" {
  name                   = "scale-out"
  autoscaling_group_name = aws_autoscaling_group.web.name
  policy_type            = "StepScaling"
  adjustment_type        = "ChangeInCapacity"     # 台数で増減(PercentChange も可)

  # 閾値から +0〜+20 超過なら +1 台
  step_adjustment {
    metric_interval_lower_bound = 0
    metric_interval_upper_bound = 20
    scaling_adjustment          = 1
  }
  # +20 超過なら +3 台(急増対応)
  step_adjustment {
    metric_interval_lower_bound = 20
    scaling_adjustment          = 3
  }
}

# Step Scaling は alarm が発火しないと動かない。アラームを別途定義
resource "aws_cloudwatch_metric_alarm" "cpu_high" {
  alarm_name          = "asg-cpu-high"
  comparison_operator = "GreaterThanThreshold"
  evaluation_periods  = 2
  metric_name         = "CPUUtilization"
  namespace           = "AWS/EC2"
  period              = 60
  statistic           = "Average"
  threshold           = 70

  dimensions = {
    AutoScalingGroupName = aws_autoscaling_group.web.name
  }

  # アラーム発火時に scale_out ポリシーを発動
  alarm_actions = [aws_autoscaling_policy.scale_out.arn]
}

ALB と連携

resource "aws_lb_target_group" "web" {
  name     = "web"
  port     = 80
  protocol = "HTTP"
  vpc_id   = aws_vpc.main.id

  health_check {
    path                = "/health"
    healthy_threshold   = 2
    unhealthy_threshold = 3
    interval            = 30
    timeout             = 5
    matcher             = "200"
  }
}

# Listener は 10 章 (ALB) を参照
# ASG の target_group_arns に ARN を渡せば自動登録

Instance refresh(ローリング更新)

Launch Template を新版に更新した後、既存インスタンスを ローリングで入れ替え る機能。Terraform からは Apply 時に自動で発火させられます。

# 既存 ASG に instance_refresh ブロックを追加(Rolling 更新を有効化)
resource "aws_autoscaling_group" "web" {
  # ...

  instance_refresh {
    strategy = "Rolling"
    preferences {
      min_healthy_percentage = 90       # 入れ替え中も 90% 以上の台数を維持
      instance_warmup        = 300      # 新インスタンスを healthy 判定するまでの秒
    }
    # tag/launch_template が変更されたら自動で refresh を発火
    triggers = ["tag", "launch_template"]
  }
}
tip "$Latest""$Default" ではなく 具体的な version 番号を指定 すると、apply 時の差分が明確になり、誤って即時新版にロールアウトする事故を防げます。