EC2インスタンスをCPU使用率が高い順に表示する
- 性能テストなどを行っていて、ボトルネックとなっているインスタンスを探したい
- cloudwatchの結果をクエリして「当該時間帯にCPU使用率が高かったインスタンス」を探す
tabulate
を利用して良い感じに表示する
IAMロール、ポリシー
以下の2つのbuilt-inポリシーをアタッチしたロールを作成し、Lambdaにアタッチします。
- AWSLambdaExecute
- AmazonEC2ReadOnlyAccess
tabulate を使えるようにする
表示にはtabulate
を使いたいのですが、Lambdaではpipを利用することが出来ません。以下の記事に従って、tabulate
を利用できるようにします。
【AWS】Lambdaでpipしたいと思ったときにすべきこと - Qiita
テストイベントの設定
引数には調査対象の環境(env
)と、時間帯(timebox
)を渡します。timeboxにはISOフォーマットを利用し、timezoneを設定することも可能です。以下のサンプルではJST(+09:00)でtimebox
を指定しています。
{ "env": "test1", "timebox":{ "start": "2018-02-23T12:30:00+09:00", "end":"2018-02-23T13:00:00+09:00" } }
コード
Python 3.6 で書きます。
import datetime import boto3 import dateutil.parser as parser from tabulate import tabulate def lambda_handler(event, context): ec2_client = boto3.client('ec2') full_info = ec2_client.describe_instances( Filters=[ { 'Name': 'tag:env', 'Values': [event.get('env')] } ] ) instances = [] for r in full_info['Reservations']: for i in r['Instances']: instances.append(i) cw_client = boto3.client('cloudwatch') timebox = event.get('timebox', {}) if not timebox: now = datetime.datetime.utcnow() timebox['start'] = now - datetime.timedelta(seconds=600) timebox['end'] = now else: timebox['start'] = parser.parse(timebox['start']) timebox['end'] = parser.parse(timebox['end']) ret = [] for ins in instances: metrics = cw_client.get_metric_statistics( Namespace='AWS/EC2', MetricName='CPUUtilization', Dimensions=[{'Name': 'InstanceId', 'Value': ins['InstanceId']}], StartTime=timebox['start'], EndTime=timebox['end'], Period=60, Statistics=['Average'] ) # get latest data latest = None for d in metrics['Datapoints']: if not latest: latest = d else: if latest['Timestamp'] < d['Timestamp']: latest = d if not latest: continue ret.append({ 'name': [t['Value'] for t in ins['Tags'] if t['Key'] == 'Name'][0], 'instance_id': ins.get('InstanceId', ''), 'private_ip': ins.get('PrivateIpAddress', ''), 'CPU_usage': latest['Average'], 'timestamp': latest['Timestamp'].isoformat() }) ret.sort(key=lambda d: d['CPU_usage'], reverse=True) print(tabulate(ret, headers="keys")) return ret
補足と解説
dateutil.parser
を利用してISOフォーマットの時刻文字列をdatetime
に変換できます。
timebox = event.get('timebox', {}) if not timebox: now = datetime.datetime.utcnow() timebox['start'] = now - datetime.timedelta(seconds=600) timebox['end'] = now else: timebox['start'] = parser.parse(timebox['start']) timebox['end'] = parser.parse(timebox['end'])
Dimensions
で InstanceId 、StartTime
、EndTime
で時間帯を指定してcloudwatch のデータをクエリします。
for ins in instances: metrics = cw_client.get_metric_statistics( Namespace='AWS/EC2', MetricName='CPUUtilization', Dimensions=[{'Name': 'InstanceId', 'Value': ins['InstanceId']}], StartTime=timebox['start'], EndTime=timebox['end'], Period=60, Statistics=['Average'] )
CPU使用率が高い順にデータをソートして、tabulate
で綺麗にprintします。headerにはデータのkeyを指定します。
ret.sort(key=lambda d: d['CPU_usage'], reverse=True) print(tabulate(ret, headers="keys"))
出力結果
tabulate
を利用することで、綺麗に表示されます。(サーバー名、instance_idなどはマスクしました)
name instance_id private_ip CPU_usage timestamp --------- ------------------- ------------ ----------- ------------------------- server1 i-1a1a1a1a1a1a1a1a1 111.1.1.11 13.234 2018-02-23T04:28:00+00:00 server2 i-2b2b2b2b2b2b2b2b2 111.1.2.22 7.854 2018-02-23T04:27:00+00:00 server3 i-3c3c3c3c3c3c3c3c3 111.1.3.33 5.342 2018-02-23T04:28:00+00:00 server4 i-4d4d4d4d4d4d4d4d4 111.1.4.44 3.47458 2018-02-23T04:29:00+00:00 server5 i-5e5e5e5e5e5e5e5e5 111.1.5.55 1.208 2018-02-23T04:28:00+00:00 server6 i-6f6f6f6f6f6f6f6f6 111.1.6.66 0.95 2018-02-23T04:28:00+00:00 server7 i-7g7g7g7g7g7g7g7g7 111.1.7.77 0.758 2018-02-23T04:27:00+00:00 server8 i-8h8h8h8h8h8h8h8h8 111.1.8.88 0.738 2018-02-23T04:27:00+00:00 server9 i-9i9i9i9i9i9i9i9i9 111.1.9.99 0.730958 2018-02-23T04:29:00+00:00 server10 i-10j10j10j10j10j10 111.1.10.110 0.6 2018-02-23T04:29:00+00:00 server11 i-11k11k11k11k11k11 111.1.11.121 0.4 2018-02-23T04:29:00+00:00 server12 i-12l12l12l12l12l12 111.1.12.132 0.38337 2018-02-23T04:26:00+00:00 server13 i-13m13m13m13m13m13 111.1.13.143 0.36428 2018-02-23T04:29:00+00:00 server14 i-14n14n14n14n14n14 111.1.14.154 0.35 2018-02-23T04:26:00+00:00 server15 i-15o15o15o15o15o15 111.1.15.165 0.324 2018-02-23T04:29:00+00:00