
Amazon EC2 Auto Scaling の新機能 Launch Before Terminate(終了前に起動)を試してみた
はじめに
2026年10月、Amazon EC2 Auto Scaling で Launch Before Terminate(終了前に起動)をアカウント単位の既定の置き換え動作に設定できるようになりました。
Launch Before Terminate を有効にすると、アカウント内のすべての ASG で、代替インスタンスを先に起動し、ヘルスチェックに通ってから置き換え対象のインスタンスを終了します。対象となるのは、インスタンスリフレッシュ、リバランス、ヘルスチェック、インスタンスの最大有効期間の経過による置き換えで、追加費用はかからないとされています。
今回、「終了前に起動」の有効時と無効時の動作の違いについて、東京リージョンの ASG で Preferences を指定しないインスタンスリフレッシュで確認しました。
アカウント設定
設定名は launchBeforeTerminate で、値は enabled と disabled です。
aws autoscaling describe-account-settings
{
"Settings": [
{
"Name": "launchBeforeTerminate",
"Value": "disabled",
"EnforcementType": "none"
}
]
}
有効にするコマンドと、無効に戻すコマンドです。
aws autoscaling put-account-setting --name launchBeforeTerminate --value enabled
aws autoscaling put-account-setting --name launchBeforeTerminate --value disabled
検証環境
東京リージョンの既定 VPC(公開サブネット3つ)に、ALB と ASG を CloudFormation で作成しました。
- インスタンス:t4g.nano、Amazon Linux 2023 arm64、Nginx を起動
- ASG: 最小4台、希望4台、最大8台。ヘルスチェックの種類は ELB、猶予は60秒。インスタンスメンテナンスポリシーなし
- ターゲットグループ:ヘルスチェックのパスは
/、間隔10秒、正常2回、異常2回。登録解除の遅延は30秒 - AWS CLI: aws-cli/2.38.6
テンプレート全文とデプロイコマンド
AWSTemplateFormatVersion: '2010-09-09'
Description: ASG Launch Before Terminate account setting verification (ALB + ASG of t4g.nano running Nginx). Delete the stack after the test.
Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
SubnetIds:
Type: List<AWS::EC2::Subnet::Id>
Description: Public subnets in at least two AZs (default VPC)
AmiId:
Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>
Default: /aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64
InstanceType:
Type: String
Default: t4g.nano
Resources:
AlbSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: ALB (test, HTTP from anywhere)
VpcId: !Ref VpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
InstanceSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: EC2 (HTTP from ALB only)
VpcId: !Ref VpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
SourceSecurityGroupId: !Ref AlbSecurityGroup
LoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Type: application
Scheme: internet-facing
Subnets: !Ref SubnetIds
SecurityGroups:
- !Ref AlbSecurityGroup
LoadBalancerAttributes:
- Key: deletion_protection.enabled
Value: 'false'
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
VpcId: !Ref VpcId
Protocol: HTTP
Port: 80
TargetType: instance
HealthCheckPath: /
HealthCheckIntervalSeconds: 10
HealthCheckTimeoutSeconds: 5
HealthyThresholdCount: 2
UnhealthyThresholdCount: 2
Matcher:
HttpCode: '200'
TargetGroupAttributes:
- Key: deregistration_delay.timeout_seconds
Value: '30'
Listener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
LoadBalancerArn: !Ref LoadBalancer
Protocol: HTTP
Port: 80
DefaultActions:
- Type: forward
TargetGroupArn: !Ref TargetGroup
LaunchTemplate:
Type: AWS::EC2::LaunchTemplate
Properties:
LaunchTemplateData:
ImageId: !Ref AmiId
InstanceType: !Ref InstanceType
SecurityGroupIds:
- !Ref InstanceSecurityGroup
MetadataOptions:
HttpTokens: required
UserData:
Fn::Base64: |
#!/bin/bash
# t4g.nano (0.5 GiB) gets OOM-killed during dnf, so add swap first
dd if=/dev/zero of=/swapfile bs=1M count=1024
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
dnf install -y nginx
TOKEN=$(curl -s -X PUT http://169.254.169.254/latest/api/token -H 'X-aws-ec2-metadata-token-ttl-seconds: 60')
IID=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/instance-id)
echo "instance-id: $IID" > /usr/share/nginx/html/index.html
systemctl enable --now nginx
AutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
Properties:
MinSize: '4'
DesiredCapacity: '4'
MaxSize: '8'
VPCZoneIdentifier: !Ref SubnetIds
LaunchTemplate:
LaunchTemplateId: !Ref LaunchTemplate
Version: !GetAtt LaunchTemplate.LatestVersionNumber
TargetGroupARNs:
- !Ref TargetGroup
HealthCheckType: ELB
HealthCheckGracePeriod: 60
Tags:
- Key: Name
Value: devio-asg-lbt
PropagateAtLaunch: true
- Key: Project
Value: devio-asg-lbt
PropagateAtLaunch: true
Outputs:
AlbDnsName:
Value: !GetAtt LoadBalancer.DNSName
AutoScalingGroupName:
Value: !Ref AutoScalingGroup
TargetGroupArn:
Value: !Ref TargetGroup
aws cloudformation deploy --stack-name devio-asg-lbt --template-file template.yaml --parameter-overrides VpcId=<vpc-id> SubnetIds=<subnet-id-1>\,<subnet-id-2>\,<subnet-id-3> --tags Project=devio-asg-lbt --no-fail-on-empty-changeset
計測結果
インスタンスリフレッシュを開始しました。
aws autoscaling start-instance-refresh --auto-scaling-group-name <asg-name>
台数は変化した行だけを示します。合計は終了処理中のインスタンスを含む ASG のインスタンス数です。イベントは describe-scaling-activities の出力から、インスタンスリフレッシュが原因の置き換え1台分を抜き出しました。時刻は JST です。
aws autoscaling describe-scaling-activities --auto-scaling-group-name <asg-name>
disabled
時刻 合計 InService healthy
13:16:32 4 4 4
13:16:36 ← 古いインスタンスを終了
13:16:38 4 3 3
13:16:38 ← 新しいインスタンスを起動
13:16:44 5 4 3
13:17:49 4 4 3
13:17:55 4 4 4
終了が先で、約2秒後に起動が始まりました。InService と healthy ターゲットは3台まで減りました。InService は6秒後に4台へ戻りましたが、healthy ターゲットは新しいインスタンスが healthy になる 13:17:55 まで、約77秒3台のままでした。
enabled
時刻 合計 InService healthy
12:58:05 5 4 4
12:58:06 ← 新しいインスタンスを起動
12:58:11 5 5 4
12:59:22 5 5 5
13:00:44 ← 古いインスタンスを終了
13:00:45 5 4 4
13:00:45 ← 次の新しいインスタンスを起動
13:00:51 6 5 4
起動が先で、約2分38秒後に終了が始まりました。終了が始まったのは、healthy ターゲットが5台になった 12:59:22 より後です。4台の置き換えのどれも、同じ順序でした。
コンソールの「終了前に起動を管理する」には、インスタンスメンテナンスポリシーが設定されていないグループには、最小正常率 100%、最大正常率 110% が適用されると書かれています。有効時の指定なしのリフレッシュの Preferences も、MinHealthyPercentage 100、MaxHealthyPercentage 110 でした。
リフレッシュ全体を通しても、enabled のときの InService と healthy ターゲットは4台を下回りませんでした。代わりに、置き換え中は合計が最大6台(InService は最大5台)まで増えました。ASG の最大台数は8にしてあり、最大台数を希望台数と同じにした ASG は試していません。
まとめ
EC2 Auto Scaling のアカウント設定で「終了前に起動」を有効にすると、インスタンスを交換するメンテナンスで、代替インスタンスの起動に失敗して有効な台数が減る事故を回避しやすくなります。
今回は1回の測定でしたが、指定なしのインスタンスリフレッシュで、新しいインスタンスが healthy になってから古いインスタンスが終了される動作を確認できました。
多数の ASG が存在するアカウントで、本番環境の保護対策としては有効と考えられる設定です。ただし、一時的に EC2 の稼働台数が増えるため、コストが増えたり、メンテナンスの所要時間が長くなったりする可能性があります。オンデマンドキャパシティ予約を使用している場合や、ライセンスを厳密に管理している場合は、予約枠が不足したり、ライセンス数を超過したりする可能性にも留意してご利用ください。








