Auto ScalingのTermination Policyを使いこなそう

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、虎塚です。

先日、「Auto Scalingがスケールインする時には、最も古いインスタンスから削除されますよね?」というお問合せをいただきました。じつは、スケールイン時にどのインスタンスが終了されるかは、Auto ScalingのTermination Policyをどのように設定したかによって変わります。

今回は、Termination Protectionの種類と動作についてご紹介します。

Auto ScalingのTermination Policyとは

Termination Policyとは、Auto Scalingでスケールインが発生した時に、どのインスタンスを終了させるかを決めるものです。Termination Policyを明示的に指定しない場合は、デフォルトのTermination Policyが使われます。

どのインスタンスを残して、どのインスタンスを消すかは、スケールアウト/スケールインの利用目的によって異なります。Termination Policyを使うと、終了させるインスタンスを柔軟に選定できるので、Auto Scalingをさらに便利に使えるでしょう。

デフォルトのTermination Policy

デフォルトのTermination Policyで終了するインスタンスがどのように選ばれるかを、次の図に示します。

デフォルトTermination Policyの動作

  1. インスタンスが複数のAvailability Zone (以下、AZ) にある場合、より多くのインスタンスがあり、スケールインから保護されていないインスタンス1が1個以上あるAZを選びます。もし当てはまるAZが複数あったり、インスタンスが単独のAZにあったりする場合は、最も古いLaunch Configurationを使用しているインスタンスがあるAZを選びます。
  2. 1で選んだAZの中で、スケールインから保護されていなくて、最も古いLaunch Configurationを使用しているインスタンスが1個かを確認します。もしそうなら、そのインスタンスを終了します。
  3. スケールインから保護されていなくて、最も古いLaunch Configurationを使用しているインスタンスが複数ある場合は、次回の請求時間に最も近いインスタンスを選びます(この方針で選択した場合、ユーザのインスタンス使用期間を最大化しつつ、請求対象になる利用時間を最小化できます)。当てはまるインスタンスが1個であれば、そのインスタンスを終了します。
  4. スケールインから保護されていなくて、最も古いLaunch Configurationを使用していて、かつ次の請求開始時間まで最も近いインスタンスが2個以上ある場合は、ランダムに1個のインスタンスを終了します。

カスタムのTermination Policy

サポートされているTermination Policyを、AWS CLIで取得できます。

aws autoscaling describe-termination-policy-types
{
    "TerminationPolicyTypes": [
        "ClosestToNextInstanceHour",
        "Default",
        "NewestInstance",
        "OldestInstance",
        "OldestLaunchConfiguration"
    ]
}

上の実行結果は、2016年7月7日時点のものです。それぞれのTermination Policyの詳細を次の表に示します。

ポリシー 振る舞い どんな時に便利か
OldestInstance 最も古いインスタンスを終了する インスタンスタイプを変更する時
NewestInstance 最も新しいインスタンスを終了する 新しいlaunch configurationをテストしたい(が本番環境として使い続けたくはない)時
OldestLaunchConfiguration 最も古いlaunch configurationを使用しているインスタンスを終了する Auto Scaling groupをアップデートして、以前のlaunch configurationを利用するインスタンスを置き換えたい時
ClosestToNextInstanceHour 次の請求時間に最も近いインスタンスを終了する インスタンスの利用量を最大化しつつコストを抑えたい時
Default 上の図を参照 Auto Scaling groupに1個以上のスケーリングポリシーを関連づけている時

カスタムTermination Policyを使用した場合も、最初に評価されるのはAZ間の均衡であることに注意してください。ほかのAZよりもインスタンス数が多いAZがある場合、カスタムのTermination Policyは、まずそのAZに対して適用されます。

実験: インスタンス数が均衡/不均衡な状態でNewestInstanceポリシーを適用

少し長くなりますが、カスタムTermination Policyを適用した時の動作を確認してみましょう。

1. Launch Configurationの作成

t2.microのAmazon Linuxを起動するLaunch Configuration (lc20160707) を作成します。

aws autoscaling create-launch-configuration --cli-input-json file://lc20160707.json
{
    "LaunchConfigurationName": "lc20160707",
    "ImageId": "ami-374db956",
    "KeyName": "sample-key",
    "SecurityGroups": [
        "sg-00000000", "sg-11111111"
    ],
    "InstanceType": "t2.micro",
    "BlockDeviceMappings": [
        {
            "DeviceName": "/dev/xvda",
            "Ebs": {
                "VolumeSize": 8,
                "VolumeType": "gp2",
                "DeleteOnTermination": true
            }
        }
    ],
    "InstanceMonitoring": {
        "Enabled": false
    },
    "IamInstanceProfile": "sample-role",
    "EbsOptimized": false,
    "AssociatePublicIpAddress": true
}

2. Auto Scaling groupの作成

ステップ1で作成したLaunch Configurationを使って、VPC内で最大3台・最小3台のインスタンスをMuti-AZで起動するAuto Scaling group (asg20160707) を作成します。

aws autoscaling create-auto-scaling-group --cli-input-json file://asg20160707.json
{
    "AutoScalingGroupName": "asg20160707",
    "LaunchConfigurationName": "lc20160707",
    "MinSize": 3,
    "MaxSize": 3,
    "AvailabilityZones": [
        "ap-northeast-1a", "ap-northeast-1c"
    ],
    "HealthCheckType": "EC2",
    "HealthCheckGracePeriod": 180,
    "VPCZoneIdentifier": "subnet-00000000,subnet-11111111",
    "NewInstancesProtectedFromScaleIn": false,
    "Tags": [
        {
            "ResourceId": "asg20160707",
            "ResourceType": "auto-scaling-group",
            "Key": "Name",
            "Value": "termination-policy-test",
            "PropagateAtLaunch": true
        }
    ]
}

上では、Auto Scaling groupを作る際に、Termination Policyを明示的に与えていません。DefaultのTermination Policyが使われていることを確認しておきます。

aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names asg20160707 | jq '.AutoScalingGroups[].TerminationPolicies'
[
  "Default"
]

3. 起動したインスタンスの確認

ステップ2で作ったAuto Scaling group内で、インスタンスが自動的に起動します。起動したインスタンスがどのAZにあるかを確認します。

aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names asg20160707 | jq '.AutoScalingGroups[].Instances[] | .AvailabilityZone, .InstanceId'
"ap-northeast-1a"
"i-0d5f1992"
"ap-northeast-1a"
"i-0e5f1991"
"ap-northeast-1c"
"i-91fdc11e"

ap-northeast-1aに2台、ap-northeast-1cに1台のインスタンスがあります。

4. インスタンス1台を入れ替え

以降の検証の準備として、インスタンスが1台だけあるAZで、インスタンスを停止します。

aws ec2 stop-instances --instance-ids i-91fdc11e

Auto Scalingのアクティビティを確認します。

aws autoscaling describe-scaling-activities --auto-scaling-group-name asg20160707 | jq '.Activities[].Description'
"Launching a new EC2 instance: i-30fcc0bf"
"Terminating EC2 instance: i-91fdc11e"
"Launching a new EC2 instance: i-0e5f1991"
"Launching a new EC2 instance: i-0d5f1992"
"Launching a new EC2 instance: i-91fdc11e"

インスタンス (i-91fdc11e) を停止したためにヘルスチェックが通らなくなり、対象インスタンスがAuto Scalingによって終了されました。代わりに、新しいインスタンス (i-30fcc0bf) が起動しました。

新しいインスタンスがどのAZにあるかを確認します。たった今起動したインスタンスは、インスタンスが1個のAZのほうにあります。

aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names asg20160707 | jq '.AutoScalingGroups[].Instances[] | .AvailabilityZone, .InstanceId'
"ap-northeast-1c"
"i-30fcc0bf"
"ap-northeast-1a"
"i-0d5f1992"
"ap-northeast-1a"
"i-0e5f1991"

5. Termination Policyの変更 (Default -> NewestInstance)

Termination PolicyをDefaultからNewestInstanceに変更します。NewestInstanceポリシーは、前掲の表のとおり最も新しいインスタンスを終了対象とします

Termination Policyを変更するには、Auto Scaling groupをアップデートします。

aws autoscaling update-auto-scaling-group --auto-scaling-group-name asg20160707 --termination-policies "NewestInstance"

新しいカスタムTermination Policyが適用されたことを確認します。

aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names asg20160707 | jq '.AutoScalingGroups[].TerminationPolicies'
[
  "NewestInstance"
]

6. インスタンス数が不均衡な状態でのスケールイン

Auto Scaling groupをシュリンクさせて、どのインスタンスが終了されるかを確認しましょう。

aws autoscaling update-auto-scaling-group --auto-scaling-group-name asg20160707 --min-size 2 --max-size 2

NewestInstanceポリシーを適用したので、ap-northeast-1cの最も新しいインスタンス (i-30fcc0bf) が終了されるのでしょうか?

aws autoscaling describe-scaling-activities --auto-scaling-group-name asg20160707 | jq '.Activities[].Description'
"Terminating EC2 instance: i-0d5f1992"
"Launching a new EC2 instance: i-30fcc0bf"    # ap-northeast-1c
"Terminating EC2 instance: i-91fdc11e"
"Launching a new EC2 instance: i-0e5f1991"    # ap-northeast-1a
"Launching a new EC2 instance: i-0d5f1992"    # ap-northeast-1a
"Launching a new EC2 instance: i-91fdc11e"

もちろん、違います。複数AZ間でインスタンス数が不均衡な状態なので、台数が多いほうのAZ (ap-northeast-1a) で、最も新しいインスタンス (i-0d5f1992) が終了されました

7. Auto Scaling groupのキャパシティを4に変更

以降の検証にそなえて、Auto Scaling groupを最大4台・最小4台のキャパシティに変更します。

aws autoscaling update-auto-scaling-group --auto-scaling-group-name asg20160707 --min-size 4 --max-size 4

新しいインスタンスが自動的に起動します。Auto Scalingのアクティビティを確認しましょう。

aws autoscaling describe-scaling-activities --auto-scaling-group-name asg20160707 | jq '.Activities[].Description'
"Launching a new EC2 instance: i-2d5d1bb2"
"Launching a new EC2 instance: i-54fec2db"
"Terminating EC2 instance: i-0d5f1992"
"Launching a new EC2 instance: i-30fcc0bf"    # ap-northeast-1c
"Terminating EC2 instance: i-91fdc11e"
"Launching a new EC2 instance: i-0e5f1991"    # ap-northeast-1a
"Launching a new EC2 instance: i-0d5f1992"
"Launching a new EC2 instance: i-91fdc11e"

新しく起動したインスタンスとAZの関連を確認しておきます。

aws autoscaling describe-auto-scaling-groups --auto-scaling-group-names asg20160707 | jq '.AutoScalingGroups[].Instances[] | .AvailabilityZone, .InstanceId'
"ap-northeast-1a"
"i-0e5f1991"
"ap-northeast-1a"
"i-2d5d1bb2"
"ap-northeast-1c"
"i-30fcc0bf"
"ap-northeast-1c"
"i-54fec2db"

ap-northeast-1aに2台、ap-northeast-1cに2台、合計4台のインスタンスが起動しています。

8. インスタンス数が均衡している状態でのスケールイン

Auto Scaling groupをふたたび変更して、最大3台・最小3台の設定に戻します。つまり、現在起動しているインスタンスのうち、どれか1台が終了されることになります。

aws autoscaling update-auto-scaling-group --auto-scaling-group-name asg20160707 --min-size 3 --max-size 3

Auto Scalingのアクティビティで、どのインスタンスが終了されたかを確認しますしょう。

aws autoscaling describe-scaling-activities --auto-scaling-group-name asg20160707 | jq '.Activities[].Description'
"Terminating EC2 instance: i-2d5d1bb2"
"Launching a new EC2 instance: i-2d5d1bb2"    # ap-northeast-1a
"Launching a new EC2 instance: i-54fec2db"    # ap-northeast-1c
"Terminating EC2 instance: i-0d5f1992"
"Launching a new EC2 instance: i-30fcc0bf"    # ap-northeast-1c
"Terminating EC2 instance: i-91fdc11e"
"Launching a new EC2 instance: i-0e5f1991"    # ap-northeast-1a
"Launching a new EC2 instance: i-0d5f1992"
"Launching a new EC2 instance: i-91fdc11e"

AZ間でインスタンス数が均衡を保っている状態では、NewestInsntanceというポリシー名どおり、最も新しいインスタンス (i-2d5d1bb2) が削除されました

おわりに

カスタムTermination Policyの表にあるように、それぞれのポリシーには使いどころがあります。目的にあわせてTermination Policyを設定し、Auto Scalingをもっと便利に使いましょう。

それでは、また。