はじめに
r4からr5など、XenベースからNitroベースの最新世代へのEC2インスタンスタイプの変更時には
ドライバーのアップグレード等ダウンタイムが生じるOS内部作業が伴います。
必然的にダウンタイムが長くなるため平日日中帯を避けたいケースも多いのではないでしょうか。
Lambda(python)で自動スケジューリング化に挑戦してみました。
環境
EC2インスタンスタイプ:r4.largeからr5.largeへ変更
EC2のOS:Windows server 2012 R2
Lambdaで使うランタイム:Python3.9
#作業全体像
今回の作業は以下ドキュメントに沿って行います。
- AWS PV ドライバーのインストールとアップグレード
- ENA のインストールとアップグレード
- AWS NVMe ドライバーをアップグレード
- EC2Config および EC2Launch の更新
- ベアメタルインスタンスのシリアルポートドライバーのインストール
- 電源管理設定の更新
- 新しいインスタンスタイプ用のインテルチップセットドライバーの更新
上記のうちパート1〜3はSSMオートメーションの AWSSupport-UpgradeWindowsAWSDrivers
を使用することで自動化可能です。
AWSSupport-UpgradeWindowsAWSDrivers
はドライバインストール作業前に変更前AMIを取得してくれる事もありがたいです。
多くの場合パート5、パート7は不要になります。パート4、パート6はSSMのRun Commandから実行可能です。
EC2LaunchはWindows Server 2016 および 2019向けの為、今回はEC2Configの更新になります。
以下の流れをLambdaで実行することでWindows インスタンスの Nitro 世代移行を自動スケジューリング化できます。
- SSM オートメーションで
AWSSupport-UpgradeWindowsAWSDrivers
を実行 - EC2を停止⇨タイプ変更⇨起動
- SSM Run CommandでEC2Configの更新、電源管理設定の更新を実行
#作業前確認
現在のバージョンや設定内容を確認します
AWS PV ドライバー
PS C:\Users\Administrator> Get-ItemProperty HKLM:\SOFTWARE\Amazon\PVDriver | Select-Object Version
Version
-------
8.4.0
ENAサポートを確認
aws ec2 describe-instances --instance-ids インスタンスID --query "Reservations[].Instances[].EnaSupport"
[
true
]
電源設定
PS C:\Users\Administrator> powercfg -q 381b4222-f694-41f0-9685-ff5bb260df2e 7516b95f-f776-4464-8c53-06167f40cc99
電源設定の GUID: 381b4222-f694-41f0-9685-ff5bb260df2e (バランス)
GUID エイリアス: SCHEME_BALANCED
サブグループの GUID: 7516b95f-f776-4464-8c53-06167f40cc99 (ディスプレイ)
GUID エイリアス: SUB_VIDEO
電源設定の GUID: 3c0bc021-c8a8-4e07-a973-6b14cbcb2b7e (次の時間が経過後ディスプレイの電源を切る)
GUID エイリアス: VIDEOIDLE
利用可能な設定の最小値: 0x00000000
利用可能な設定の最大値: 0xffffffff
利用可能な設定の増分: 0x00000001
利用可能な設定の単位: 秒
現在の AC 電源設定のインデックス: 0x00000258
現在の DC 電源設定のインデックス: 0x0000012c
#IAMロール、Lambdaの設定
作業対象のEC2にSSMから操作できるようにIAMロールを付与します。
ロールに付与する権限はAmazonSSMManagedInstanceCoreを使用しました
ここからはLambda関数の作成です
ランタイムはpython3.9を使用しました
実行ロール作成後に作成したロールがSSMを利用可能なように権限を修正します
設定>アクセス権限から作成したロール名がリンクになっているのでクリックします
IAMロールにAmazonEC2FullAccess,AmazonSSMFullAccessを付与します
Lambdaはデフォルトのタイムアウト時間が3秒です。
今回は10分以上かかる見込みのため最大値の15分に設定します
#実装
Lambda関数のコードには以下を記述します
今回の作業ではAWSSupport-UpgradeWindowsAWSDriversの実行に8分程度かかった為、
AWSSupport-UpgradeWindowsAWSDriversの実行ステータスを確認して終了次第、次のStepに進むようにしています
EC2のスペック変更も停止状態のステータスを確認後に実施するようにしています
作業を自動化する場合、特に失敗時には通知が欲しいのでSNSに通知するようにしました。
import boto3
import os
import time
ssm = boto3.client('ssm')
sns = boto3.client('sns')
ec2 = boto3.client('ec2')
#変更対象のEC2
Instance = 'インスタンスID'
disired_type = '変更後のインスタンスタイプ'
def lambda_handler(event, context):
try:
upgrade_drivers()
except:
sns.publish(
TopicArn='通知先SNSのARN',
Subject=os.environ['AWS_LAMBDA_FUNCTION_NAME'] + "のエラーが発生しました",
Message='詳細はCloudwatch logsを参照'
)
def ssm_hundler():
ec2_ssm_response = ssm.describe_instance_information(
InstanceInformationFilterList=[
{
'key': 'InstanceIds',
'valueSet': [
Instance,]},
])
if any(ec2_ssm_response['InstanceInformationList']):
update_config()
update_power_settings()
else:
print('SSMが実行可能な状態まで待機します')
time.sleep(30)
ssm_hundler()
def update_config():
ec2_config_response = ssm.send_command(
InstanceIds=[f'{Instance}'],
DocumentName='AWS-UpdateEC2Config',
DocumentVersion='1'
)
def update_power_settings():
ec2_config_response = ssm.send_command(
InstanceIds=[f'{Instance}'],
DocumentName='AWS-RunPowerShellScript',
DocumentVersion='1',
Parameters={
'commands': [
'powercfg /setacvalueindex 381b4222-f694-41f0-9685-ff5bb260df2e 7516b95f-f776-4464-8c53-06167f40cc99 3c0bc021-c8a8-4e07-a973-6b14cbcb2b7e 0',
'powercfg /setacvalueindex 8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c 7516b95f-f776-4464-8c53-06167f40cc99 3c0bc021-c8a8-4e07-a973-6b14cbcb2b7e 0',
'powercfg /setacvalueindex a1841308-3541-4fab-bc81-f71556f20b4a 7516b95f-f776-4464-8c53-06167f40cc99 3c0bc021-c8a8-4e07-a973-6b14cbcb2b7e 0'
] } )
def change_instance_type():
ec2_stop_responce = ec2.stop_instances(
InstanceIds=[Instance,])
time.sleep(90)
ec2_stop_status = ec2_stop_responce['StoppingInstances'][0]['CurrentState']['Name']
while ec2_stop_status == 'stopping' or ec2_stop_status == 'pending':
time.sleep(30)
ec2_current_response = ec2.describe_instances(InstanceIds=[Instance,])
ec2_stop_status = ec2_current_response['Reservations'][0]['Instances'][0]['State']['Name']
print('EC2の状態は'+ec2_stop_status)
if ec2_stop_status == 'stopped':
ec2_modify_response = ec2.modify_instance_attribute(
InstanceId=Instance,
InstanceType={'Value': disired_type})
time.sleep(10)
ec2_start_responce = ec2.start_instances(
InstanceIds=[Instance])
time.sleep(30)
print('SSMコマンドに移ります')
ssm_hundler()
def upgrade_drivers():
automation_response = ssm.start_automation_execution(
DocumentName='AWSSupport-UpgradeWindowsAWSDrivers',
DocumentVersion='$DEFAULT',
Parameters={
'InstanceId': [Instance]
}
)
automation_id = automation_response['ResponseMetadata']['RequestId']
automation_check = ssm.describe_automation_executions(
Filters=[
{
'Key': 'ExecutionId',
'Values': [
automation_id
]},
]
)
automation_status = automation_check['AutomationExecutionMetadataList'][0]['AutomationExecutionStatus']
while automation_status == 'Pending' or automation_status == 'InProgress':
time.sleep(60)
automation_check = ssm.describe_automation_executions(
Filters=[
{
'Key': 'ExecutionId',
'Values': [
automation_id
]},
])
automation_status = automation_check['AutomationExecutionMetadataList'][0]['AutomationExecutionStatus']
print(automation_status)
if automation_status == 'Success':
change_instance_type()
Event Bridge(Cloudwatch Events)を選びます
選んだ後にcron方式などで日時のスケジューリングができます。
ここまでで設定は完了です!
#作業後確認
作業後のバージョンや設定内容を確認します
NVMEドライバー
AWS PV ドライバー
PS C:\Users\Administrator> Get-ItemProperty HKLM:\SOFTWARE\Amazon\PVDriver | Select-Object Version
Version
-------
8.4.0
ENAサポートを確認
aws ec2 describe-instances --instance-ids インスタンスID --query "Reservations[].Instances[].EnaSupport"
[
true
]
電源設定
PS C:\Users\Administrator> powercfg -q 381b4222-f694-41f0-9685-ff5bb260df2e 7516b95f-f776-4464-8c53-06167f40cc99
電源設定の GUID: 381b4222-f694-41f0-9685-ff5bb260df2e (バランス)
GUID エイリアス: SCHEME_BALANCED
サブグループの GUID: 7516b95f-f776-4464-8c53-06167f40cc99 (ディスプレイ)
GUID エイリアス: SUB_VIDEO
電源設定の GUID: 3c0bc021-c8a8-4e07-a973-6b14cbcb2b7e (次の時間が経過後ディスプレイの電源を切る)
GUID エイリアス: VIDEOIDLE
利用可能な設定の最小値: 0x00000000
利用可能な設定の最大値: 0xffffffff
利用可能な設定の増分: 0x00000001
利用可能な設定の単位: 秒
現在の AC 電源設定のインデックス: 0x00000000
現在の DC 電源設定のインデックス: 0x00000000
#おわりに
普段の業務ではプログラミングを使わないのですが、自己学習していたPythonを活用したい!と思い挑戦してみました。
boto3のレスポンスは多次元配列になっていて、最初は初心者の自分には取扱が難しかったです。
根気強く取り組む内にboto3のDocumentのレスポンスシンタックスから取得したい値を抽出できるようになってきました。
今後もSSMやLambdaをうまく使って作業の自動化を進めていきたいと思います。