リザーブドインスタンス(RI)を間違わずに購入したい! それなら AWS CLI を活用してみよう。 〜オペ部だより〜

こんにちは、札幌の池田です。リザーブドインスタンス(RI)の購入を検討する段階で「あると便利な情報」や「知っておきたい情報」がいくつかあります。また、RI は比較的金額の大きな買い物となるケースが多く誤購入は防止したいものです。私たちオペ部にも「RI を購入したいけれど不安があって」といった様々なご相談が寄せられています。
RI の仕組みやマネジメントコンソールでの購入手順は以前にご紹介していますので、末尾に記載しているリンクより該当するブログ記事をご参照いただければと思います。
本記事では、間違いを防止しつつ購入対象を選定していくために AWS CLI を活用する方法をご紹介します。

はじめに

本記事では EC2 に対して RI の購入を初めて検討する想定でご紹介していきます。他のサービスにおける RI についても概ね同様ですので割愛します。

最低限必要な情報

現在オンデマンドで利用中の各インスタンスに RI を購入し割引を受けたい場合、対象のオンデマンドインスタンスに関する情報のうち購入すべき RI を決定する際に必要となる項目は以下です。

  • OS(プラットフォーム):ProductDescription
  • インスタンスファミリーとインスタンスサイズ:InstanceType
  • テナンシー:InstanceTenancy

このほかに、RI の購入手続きを進めるうえで次の情報も確定させる必要があります。これらはそれぞれにおける料金を確認して予算等も含めて検討しても良いでしょう。

  • 支払い方法:OfferingType
  • 期間:Duration
  • 有効期限:End
  • 提供クラス:OfferingClass
  • スコープ:Scope
  • 数量:InstanceCount

また、RI 購入時の前払い料金も知っておきたいですね。

  • 前払い金:FixedPrice

情報を取得する

最低限必要な情報を整理しましたので、それらをどのように確かめれば良いかおさらいしてみます。
まず、オンデマンドで利用中の各インスタンスに関する情報は、EC2 ダッシュボードの「インスタンス」メニューより一覧で確認できます。が、WEB ブラウザで表示した内容をそのままコピー&ペーストしても RI の購入検討に利用するにはやや不便です。
では早速 AWS CLI を利用してこれらの情報を取得してみましょう。公式ドキュメントからそのコマンドを確認しようと思いましたが、その前に DevelopersIO の記事を検索しましたところ、やはりありました。

【小ネタ】aws-cliでEC2マネージメントコンソールの内容をCSVに出力する

2014年の記事ですから、コマンドそのものやオプションなどに変更があるかもしれません。念のためコマンドリファレンスで確認したうえで実際に検証用アカウントで実行してみましたところ以下のように問題なく利用できました。
これで、現在利用中のインスタンスに関する情報の一覧を取得することができます。あとは jq で必要な項目のみを抽出して csv 形式で出力させておきます。

aws ec2 describe-instances | jq -r '.Reservations[].Instances[] |
  [
    ( .Tags[]| select(.Key == "Name") | .Value ) // "",
    .InstanceId,
    .InstanceType,
    .Placement.AvailabilityZone,
    .State.Name,
    .Platform,
    .Placement.Tenancy
  ] | @csv' > ec2.csv
cat ec2.csv
"Verification-01","i-********","m5.large","ap-northeast-1a","running",,"default"
"Verification-02","i-********","c5.large","ap-northeast-1c","running",,"default"

次に RI の購入を検討する上で知りたいものといえば、対象となる RI の価格情報ではないでしょうか。既存インスタンスの情報に加えて RI を購入する際の料金が同じ資料上で確認・比較できれば部署や社内での検討、調整もスムーズに進められそうです。
これも AWS 料金ページへ WEB ブラウザでアクセスすることによって閲覧は可能ですが、種類が非常に多いためできれば現在利用中または購入を検討したいインスタンスの料金だけに絞り込んだり、せっかく先の手順で用意したオンデマンドインスタンス一覧と組み合わせるなど、検討用資料に流用しやすい形式で取得したいところです。というわけで AWS CLI による価格情報の取得を行ってみます。

aws ec2 describe-reserved-instances-offerings --instance-type t2.large --offering-class standard --product-description "Linux/UNIX" --instance-tenancy default --filters Name=duration,Values=31536000 Name=scope,Values=Region  

参考: リザーブドインスタンス の購入

この情報もオンデマンドインスタンスの一覧同様にひとつの csv ファイルとして保存しておきます。利用中のオンデマンドインスタンスの種類が多い場合などは上記コマンドで一つひとつの情報を取得するのはなかなかの手間ですので、リージョンやプラットフォームだけを指定した全ての RI 価格情報を取得しておくのも良いかもしれません。
ただし、提供価格は予告なく変更されることがありますので、数ヶ月前などに取得した情報は使用せず最新の情報を利用するようにしてください。

今回は Linux/UNIX で稼働中のオンデマンドインスタンスが 2つでしたので、それぞれ以下のようにインスタンスタイプを指定した形でコマンドを実行し、csv 形式で出力しました。マネジメントコンソールで RI を購入する場合は不要ですが念のため ReservedInstancesOfferingId も取得しておきます。

aws ec2 describe-reserved-instances-offerings --instance-type m5.large --product-description "Linux/UNIX" --instance-tenancy default --no-include-marketplace --filters Name=scope,Values=Region |
 jq -r '.ReservedInstancesOfferings[] |
 [.OfferingClass, .ProductDescription, .InstanceType, .OfferingType, .FixedPrice, .Duration, .ReservedInstancesOfferingId] | @csv' > offerings.csv
aws ec2 describe-reserved-instances-offerings --instance-type c5.large --product-description "Linux/UNIX" --instance-tenancy default --no-include-marketplace --filters Name=scope,Values=Region |
 jq -r '.ReservedInstancesOfferings[] |
 [.OfferingClass, .ProductDescription, .InstanceType, .OfferingType, .FixedPrice, .Duration, .ReservedInstancesOfferingId] | @csv' >> offerings.csv
cat offerings.csv
"standard","Linux/UNIX","m5.large","All Upfront",706,31536000,"e5d9b188-7d36-4fb8-807d-ad59702f8cdf"
"convertible","Linux/UNIX","m5.large","All Upfront",812,31536000,"76cb4038-9a79-45cf-b90a-a2d3a7c888b3"
"standard","Linux/UNIX","m5.large","All Upfront",1430,94608000,"d1323103-f6c6-494b-be36-7cafe6dbc59a"
"convertible","Linux/UNIX","m5.large","All Upfront",1715,94608000,"95f10f42-10c3-416c-af75-cecc8568d2cd"
(以下省略)

情報を利用する

ここまでの作業で、現在利用中のオンデマンドインスタンスの一覧とそれらに適応した RI を購入する上で必要な情報と、RI の価格情報を用意することができました。次はこれらを利用しやすい状態になるよう表計算ソフトに取り込んでいくことにします。
ここからの手順は使い慣れたソフトや好みなどで大きく異なると思います。今回はオンデマンドで利用している 2種類の EC2 インスタンスについて RI を購入するときにどのタイプの RI を購入するか検討する。という想定でシンプルな手順を紹介します。

用意した csv ファイルをそれぞれ単純に表計算ソフトで開き、見出し行を追加してフィルター機能を有効にしたものが以下になります。オンデマンドインスタンスが少ないとこれでも十分なように思えますね。


稼働中のオンデマンドインスタンス一覧を取得した例。


購入を検討したい RI の料金情報を取得した例(列を追加して、Duration の値からわかりやすい 1年や 3年という表示をするよう手を加えてみました)。

もしもオンデマンドインスタンスをたくさん利用している場合は、取得した料金情報を新規シートに読み込んでおき、別シートの情報を参照する関数などを利用してひとつのシート上に表示させるようにするのも良いでしょう。


EXACT 関数や VLOOKUP 関数などを使用して購入対象とする印をつけると、選択した条件に対応した料金情報が別シートから読み込まれるようにしたり見出しに色をつけたりした例

このようにして購入対象を選定しておけば、あとはこの内容の通りに購入するだけとなりますが、マネジメントコンソールの操作ミスが不安ということもあるでしょう。そういう場合には、念のため取得しておいた ReservedInstancesOfferingId が役に立ちます。
ReservedInstancesOfferingId はマネジメントコンソールで購入操作を行う際には意識しないで良い仕組みになっているのですが、AWS CLI を利用して RI を購入する際に必要となる情報です。
具体的な購入手順は AWS ドキュメントや下記弊社ブログなどにありますので割愛しますが、次のようなコマンドになります。

aws ec2 purchase-reserved-instances-offering --reserved-instances-offering-id ec06327e-dd07-46ee-9398-75b5fexample --instance-count 1

リザーブドインスタンス の購入より

リザーブドインスタンスをAWS CLIで購入する

なお、他の部門やチームによってもインスタンスタイプの変更や稼働数の増減が頻繁に行われるようなケースでは、RI の購入対象を選定することの周知と共に、選定期間中は各部門、チームからインスタンスタイプ変更等に関する情報の共有を依頼しておくといいでしょう。稼働中オンデマンドインスタンスの一覧を取得したあとにサイズ変更されるなどして「動いていると思って RI を購入したインスタンスが全く稼働していない」といったトラブルの予防にもなります。

購入済み RI のリストを取得する

初めて RI を購入する想定で必要な情報を収集して、購入対象を選定する流れをご紹介しました。ここからはせっかくなので「昨年 RI を購入したが、まもなく期限が切れるので同じ内容で再購入する」という場合に役立つ方法をご紹介します。

以下に例示するコマンドは、継続利用したい RI の有効期限が切れる前に実施する前提として、購入済み RI のうちアクティブな RI のみを対象として出力させています。

コマンドと実行結果(本題に不要な情報はマスクしています)

aws ec2 describe-reserved-instances | jq -r '.ReservedInstances[] | select(.State == "active")'  
  {
  "ReservedInstancesId": "********-****-****-****-************",
  "OfferingType": "*****",
  "FixedPrice": 0,
  "End": "20**-**-**T**:**:**.000Z",
  "Scope": "Region",
  "UsagePrice": 0,
  "RecurringCharges": [
    {
      "Amount": *****,
      "Frequency": "Hourly"
    }
  ],
  "OfferingClass": "convertible",
  "Start": "20**-**-**T**:**:**.000Z",
  "State": "active",
  "ProductDescription": "Linux/UNIX (Amazon VPC)",
  "CurrencyCode": "USD",
  "Duration": 31536000,
  "InstanceTenancy": "default",
  "InstanceType": "m5.large",
  "InstanceCount": 1
}
{
  "ReservedInstancesId": "********-****-****-****-************",
  "OfferingType": "*****",
  "AvailabilityZone": "ap-northeast-1a",
  "End": "20**-**-**T**:**:**.000Z",
  "ProductDescription": "Linux/UNIX (Amazon VPC)",
  "Scope": "Availability Zone",
  "UsagePrice": 0,
  "RecurringCharges": [
    {
      "Amount": *****,
      "Frequency": "Hourly"
    }
  ],
  "OfferingClass": "convertible",
  "Start": "20**-**-**T**:**:**.000Z",
  "State": "active",
  "FixedPrice": 0,
  "CurrencyCode": "USD",
  "Duration": 31536000,
  "InstanceTenancy": "default",
  "InstanceType": "c5.large",
  "InstanceCount": 1
}

csvへ出力させる際には必要な情報だけを抽出するようにしました。

aws ec2 describe-reserved-instances | jq -r '.ReservedInstances[] | select(.State == "active") | [.OfferingType, .AvailabilityZone, .End, .ProductDescription, .Scope, .OfferingClass, .Duration, .InstanceTenancy, .InstanceType, .InstanceCount] | @csv' > describe-reserved-instances.csv
cat describe-reserved-instances.csv
"*****",,"20**-**-**T**:**:**.000Z","Linux/UNIX (Amazon VPC)","Region","convertible",31536000,"default","m5.large",1
"*****","ap-northeast-1a","20**-**-**T**:**:**.000Z","Linux/UNIX (Amazon VPC)","Availability Zone","convertible",31536000,"default","c5.large",1

こちらも見出しをつけてわかりやすくしてみました。

* B 列 AZ の値が空欄のものは NULL が返ってきている(= E 列 Scope に記載があるように Region 指定)という意味です。

これら 2つの RI を継続して利用したい場合、同じものを既存 RI の期限切れ(C 列 End の日時)に合わせて購入すれば良いですが、例えば料金情報 csv は以下のようにフィルター機能を活用すると見やすくなります。

あとは先に紹介した aws ec2 purchase-reserved-instances-offering コマンドの引数に ReservedInstancesOfferingId の値を指定してあげれば良いことになります。

関連記事など

読まなきゃ損($∀$)リザーブドインスタンスのススメ -2019春-

AWS再入門2018 素朴な疑問 -リザーブドインスタンス – 編

AWS再入門2018 リザーブドインスタンス購入編

AWS再入門2018 リザーブドインスタンス購入編 その2

AWS再入門2018 プロマネや営業のためのAWS Monthly Calculator入門編