こしあん
2025-02-17

Auto Scaling Groupの「Stoppedウォームプール」を試す


8{icon} {views}


Auto Scaling GroupのStopped状態のウォームプールを利用することで、初回セットアップを終えたインスタンスを停止したまま待機させ、必要時に素早く起動できる。Activeよりはやや遅いものの、GPUなどランニングコストが高いケースではコスト削減と初期化時間短縮に有効である。

はじめに

  • DOPの勉強してたら出てきたAuto Scaling GroupのStoppedのウォームプールというのを試してみた
  • Auto Scaling Groupのウォームプールは通常Activeがよくある例で、事前にインスタンスを立ち上げていおくことで、スムーズにスケーリングをできる。しかし、立ち上げた分余計にコストがかかってしまう。
  • Stoppedのウォームプールは、ユーザーデータなどの初期設定を行ってから一度インスタンスを停止した状態で待機しておく。Activeよりは遅いが、スケールアウトするときにユーザーデータを実行するよりは速い。特にGPUインスタンスなどインスタンス自体のランニングコストが高いケースでは有効。課金はEBSなどの最小限の課金になる。

やり方

Auto Scaling Groupの定義を以下のように変更するだけ。Terraformでの例。

resource "aws_autoscaling_group" "asg" {
  name                = "example-asg"
  max_size            = 5
  min_size            = 1
  desired_capacity    = 1
  vpc_zone_identifier = var.private_subnet_ids

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

  tag {
    key                 = "Name"
    value               = "example-asg-instance"
    propagate_at_launch = true
  }

  warm_pool {
    min_size   = 1
    pool_state = "Stopped"
  }
}

マネジメントコンソールで見る

Auto Scaling Groupの定義は以下のようになっている。ウォームプールのインスタンス状態が「Stopped」、待機しているインスタンスが「停止」状態になっている。これは希望するキャパシティが1、スケーリング1-5で行っている例。ウォームプールのサイズは別途設定を追加すれば調整可能。

EC2のコンソールから。1個だけ実行中で、残りは停止済み

スケールアウトしてみる

希望するキャパシティを2にしてみる。ユーザーデータではpipでPyTorchをインストールしているので結構時間かかる(詳細は末尾のコードを参照してほしい)

terraform applydesired_capacityを2にすると、24秒でapplyが完了した(もう少し前に実行中のステータスに変わっていたので、実質15秒程度?)

aws_autoscaling_group.asg: Modifying... [id=example-asg]
aws_autoscaling_group.asg: Still modifying... [id=example-asg, 10s elapsed]
aws_autoscaling_group.asg: Still modifying... [id=example-asg, 20s elapsed]
aws_autoscaling_group.asg: Modifications complete after 24s [id=example-asg]

Apply complete! Resources: 0 added, 1 changed, 0 destroyed.

実行中が2、停止済みが3になった。

新しいインスタンスにSession Managerで潜り込んで、PyTorchがちゃんとインストールされているか確認してみる。

sh-5.2$ python3
Python 3.9.20 (main, Jan 25 2025, 00:00:00)
[GCC 11.4.1 20230605 (Red Hat 11.4.1-2)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import torch
>>> torch.__version__
'2.6.0+cpu'

見事にインストールされている🎉

コード

Terraformのコードは以下の通り

##########################
# セキュリティグループ(アウトバウンドは全許可、インバウンドはデフォルト拒否)
##########################
resource "aws_security_group" "asg_sg" {
  name        = "asg-sg"
  description = "Security group for EC2 within ASG (all outbound allowed)"
  vpc_id      = var.vpc_id

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

##########################
# Session Manager 利用用IAMロールとインスタンスプロファイル
##########################

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

resource "aws_iam_role_policy_attachment" "ssm_attach" {
  role       = aws_iam_role.ec2_ssm_role.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
}

resource "aws_iam_instance_profile" "ec2_instance_profile" {
  name = "ec2-instance-profile"
  role = aws_iam_role.ec2_ssm_role.name
}

##########################
# Launch Template(ユーザーデータにCloudFormationの初期化処理を記述)
##########################
# Amazon Linux 2023
data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["137112412989"] # AmazonのAMI所有者ID

  filter {
    name   = "name"
    # Amazon Linux 2023 AMIの名前パターン。minimumを除外する
    values = ["al2023-ami-2023*-kernel-*-x86_64"]
  }

  filter {
    name   = "architecture"
    values = ["x86_64"]
  }

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

resource "aws_launch_template" "asg_lt" {
  name_prefix   = "asg-lt-"
  image_id      = data.aws_ami.amazon_linux.id
  instance_type = "t3.medium"

  iam_instance_profile {
    name = aws_iam_instance_profile.ec2_instance_profile.name
  }

  vpc_security_group_ids = [aws_security_group.asg_sg.id]

  user_data = base64encode(<<EOF
#!/bin/bash
dnf update -y
dnf install -y python3-pip
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
EOF
  )
}

##########################
# Auto Scaling Group(希望するインスタンス数1、Min=1、Max=5)とウォームプール(Stopped状態)
##########################

resource "aws_autoscaling_group" "asg" {
  name                = "example-asg"
  max_size            = 5
  min_size            = 1
  desired_capacity    = 2
  vpc_zone_identifier = var.private_subnet_ids

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

  tag {
    key                 = "Name"
    value               = "example-asg-instance"
    propagate_at_launch = true
  }

  warm_pool {
    min_size   = 1
    pool_state = "Stopped"
  }
}

所感

  • このStoppedのウォームプールはAI/MLと結構相性良さそうな気がする。例えば、巨大モデルのダウンロードや、モデルのコンパイルのような明らかに長時間かかるような処理をこれに任せてしまう。カスタムAMIと迷うが、こっちのほうが柔軟性はありそう。
  • GPUインスタンスとも結構相性良さそう
  • ECSのようなDockerとの連携どうするんだ問題はまあ確かにある
  • Stoppedのウォームプールはあんまり調べても出てこないので知れて良かった


Shikoan's ML Blogの中の人が運営しているサークル「じゅ~しぃ~すくりぷと」の本のご案内

技術書コーナー

北海道の駅巡りコーナー


Add a Comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です