boto3を使ってEC2のCPUクレジットを取得する

EC2を使っていて、動作が重いなーって感じた時にCPUクレジットの状況を確認することがあります。AWSのコンソールにログインしたら見れはするのですが2要素認証も使っていてやや面倒なので、boto3で確認する方法を調べました。
(※ 個人利用しているAWSの話です。普段jupyterlabで触っていて何かしらの作業をインタラクティブに行っています。業務におけるWebサービスの運用等であればそのインスタンスにログインするのもコンソールに入るのも手間は変わらないと思います。)

僕がクラウドウォッチに詳しくなくて、あまり詳細な説明ができないというのもあるのですが、いろいろ試した結果、以下のコードで取得できることが確認できたのでそのまま掲載します。

import boto3
import requests
import datetime


# EC2メタデータからインスタンスIDを取得
def get_instance_id():
    url = "http://169.254.169.254/latest/meta-data/instance-id"
    response = requests.get(url)
    return response.text

# インスタンスIDを取得
instance_id = get_instance_id()

# CloudWatch クライアントを作成
cloudwatch = boto3.client('cloudwatch')

# 現在の UTC 時刻を取得
end_time = datetime.datetime.utcnow()
# 過去 5 分間のデータを取得
start_time = end_time - datetime.timedelta(minutes=5)

# CPUCreditBalance メトリクスを取得
response = cloudwatch.get_metric_statistics(
    Namespace='AWS/EC2',
    MetricName='CPUCreditBalance',
    Dimensions=[
        {
            'Name': 'InstanceId',
            'Value': instance_id
        },
    ],
    StartTime=start_time,
    EndTime=end_time,
    Period=300,  # 5 分間隔
    Statistics=['Average']
)

# データポイントを取得
data_points = response['Datapoints']
if data_points:
    # 最新のデータポイントを取得
    cpu_credit_balance = data_points[0]['Average']
    print(f'インスタンスID: {instance_id}')
    print(f'CPUクレジット残高: {cpu_credit_balance}')
else:
    print('CPUクレジット残高のデータが見つかりませんでした。')

これで現在のCPUクレジット残高が取得できます。
CPUクレジッド残高はインスタンスサイズによって初期値や上限値が異なるので、別途最大値を確認しておくと参考になると思います。

参考: バーストパフォーマンスインスタンスに関する主要な概念 – Amazon Elastic Compute Cloud

EC2の内部からそのインスタンスのidなどのメタデータを取得する

EC2で作業をしていて今使っているそのインスタンスのidをコードで取得したい、った場面があったのでその方法を紹介します。

最初はてっきり、環境変数か何かに入っててそこから使えるだろう、とか思っていたのですが予想に反する場所にメタデータの格納場所がありました。

インスタンスidなどのメタデータにはインスタンス内部から特定のURLにアクセスするとで取得できます。

この辺りが参考になります。
EC2 インスタンスのインスタンスメタデータにアクセスする – Amazon Elastic Compute Cloud
インスタンスメタデータを使用して EC2 インスタンスを管理する – Amazon Elastic Compute Cloud

アクセスするURLは以下です。
http://169.254.169.254/latest/meta-data/
これは情報を取得したいインスタンス内部からしかアクセスできないので気をつけてください。同じAWSアカウントであっても別のインスタンスの情報は取れないので取得したい場合はboto3などの別の手段を使う必要があります。

実際にcurlでアクセスすると、次のような情報が返ってきます。

!curl http://169.254.169.254/latest/meta-data/
ami-id
ami-launch-index
ami-manifest-path
block-device-mapping/
events/
hostname
iam/
identity-credentials/
instance-action
instance-id
instance-life-cycle
instance-type
local-hostname
local-ipv4
mac
metrics/
network/
placement/
profile
public-hostname
public-ipv4
public-keys/
reservation-id
security-groups
services/
system

これらは取得可能な情報の一覧ですね。
/で終わってるやつはまだ配下に階層が続くのでそれを手がかりに深掘りしていくことになりますが、instance-id は直下にあるようです。先ほどのURLに取得したい情報のpathを追加して実行すると欲しい情報が取れます。

!curl http://169.254.169.254/latest/meta-data/instance-id
i-*****************

Pythonでやる場合は次のようにして簡単に取得できます。

import requests


metadata_url = "http://169.254.169.254/latest/meta-data/instance-id"
print(requests.get(metadata_url).text)

これでそのコードが動いているインスタンスのidが取得できました。
boto3等を使ったコードで、実行しているインスタンス自身に対して何かやりたいのでそのインスタンスのidの指定が必要、って場合に同一のコードを使いまわせるので便利になります。