★★ 中級

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

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]

  iam_instance_profile {
    name = aws_iam_instance_profile.ec2.name
  }

  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" }
  }

  metadata_options {
    http_tokens                 = "required"   # IMDSv2 強制
    http_put_response_hop_limit = 1
  }

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

aws_autoscaling_group

resource "aws_autoscaling_group" "web" {
  name_prefix         = "web-"
  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 のヘルスチェックを基準に
  health_check_grace_period = 300

  launch_template {
    id      = aws_launch_template.web.id
    version = "$Latest"
  }

  target_group_arns = [aws_lb_target_group.web.arn]

  tag {
    key                 = "ManagedBy"
    value               = "Terraform"
    propagate_at_launch = true
  }

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

スケーリングポリシー

Target Tracking(推奨)

「平均 CPU 50% を維持して」のように 目標値 を伝えるだけ。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"
    }
    target_value = 50.0
  }
}

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"

  step_adjustment {
    metric_interval_lower_bound = 0
    metric_interval_upper_bound = 20
    scaling_adjustment          = 1
  }
  step_adjustment {
    metric_interval_lower_bound = 20
    scaling_adjustment          = 3
  }
}

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
  }

  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 時に自動で発火させられます。

resource "aws_autoscaling_group" "web" {
  # ...

  instance_refresh {
    strategy = "Rolling"
    preferences {
      min_healthy_percentage = 90
      instance_warmup        = 300
    }
    triggers = ["tag", "launch_template"]
  }
}
tip "$Latest""$Default" ではなく 具体的な version 番号を指定 すると、apply 時の差分が明確になり、誤って即時新版にロールアウトする事故を防げます。