Terraform で RI カバレッジの Budget を定義する

Posted on

AWS Budgets を使うとリザーブドインスタンス (RI) のカバレッジを監視することができ、閾値を下回ったらアラートを出すこともできます。 RI の活用はコストに大きく関係するので、サービスの成長に従って RI の利用率を維持したい場合に便利な機能です。

今回 Terraform の aws_budgets_budget を使って定義しようとしたのですが、ハマりどころが多かったので忘れないようにメモしておきます。

AWS CLI で設定する

どこでハマったのか説明しやすくするために、先に AWS CLI での設定を紹介します。 AWS CLI だと次のような JSON 形式でパラメータを渡します。

{
  "BudgetName": "EC2 RI Coverage",
  "BudgetType": "RI_COVERAGE",
  "CostFilters": {
    "Service": [
      "Amazon Elastic Compute Cloud - Compute"
    ]
  },
  "TimePeriod": {
    "Start": 1567263600
  },
  "TimeUnit": "MONTHLY"
}
$ aws budgets create-budget --account-id 112233445566 --budget file://budget.json

Terraform で定義する

上記のパラメータを Terraform で定義すると次のようなコードになります。違いは BudgetLimit (limit_amount, limit_unit) と CostTypes (cost_types) の指定です。

resource "aws_budgets_budget" "ri_coverage" {
  name              = "EC2 RI Coverage"
  budget_type       = "RI_COVERAGE"
  limit_amount      = "100.0"
  limit_unit        = "PERCENTAGE"
  time_period_start = "2019-09-01_00:00"
  time_unit         = "MONTHLY"

  cost_filters = {
    Service = "Amazon Elastic Compute Cloud - Compute"
  }

  cost_types {
    include_credit             = false
    include_discount           = false
    include_other_subscription = false
    include_recurring          = false
    include_refund             = false
    include_subscription       = true
    include_support            = false
    include_tax                = false
    include_upfront            = false
    use_amortized              = false
    use_blended                = false
  }
}

RI_COVERAGE を指定するとき、BudgetLimit はオプションです。 AWS のドキュメントには次のように書かれています。

BudgetLimit is required for cost or usage budgets, but optional for RI utilization or coverage budgets. RI utilization or coverage budgets default to 100, which is the only valid value for RI utilization or coverage budgets.

ですが、Terraform ではこのパラメータは必須となっているため省略できません。デフォルトが 100 でそれ以外の値は取らないとのことなので、次のように定義します。

limit_amount = "100.0"
limit_unit   = "PERCENTAGE"

次に CostTypes ですが、RI_COVERAGE には CostTypes はないと書かれています。

USAGE, RI_UTILIZATION, and RI_COVERAGE budgets do not have CostTypes.

ですが、Terraform だと明示的にパラメータを指定しない場合は、デフォルトの組み合わせが暗黙的に指定されてしまいます。実際に apply しようとすると InvalidParameterException でエラーになります。

Error: create budget failed: InvalidParameterException: [Exception=InvalidParameterException] Failed to call CreateBudget for [AccountId: 112233445566] - Unable to create/update budget - RI_COVERAGE budget type only supports the following costTypes combination: { includeSubscription: true, includeTax: false, useBlended: false, includeRefund: false, includeCredit: false, includeUpfront: false, includeRecurring: false, includeOtherSubscription: false, includeSupport: false, includeDiscount: false, useAmortized: false }

エラーメッセージをよく読むと、CostTypes が指定できないわけではなく、タイプの組み合わせに制限があるようです(ドキュメントと実際の API 仕様が異なっている)。エラーメッセージに書いてあるとおりに定義すると apply できました。

cost_types {
  include_credit             = false
  include_discount           = false
  include_other_subscription = false
  include_recurring          = false
  include_refund             = false
  include_subscription       = true
  include_support            = false
  include_tax                = false
  include_upfront            = false
  use_amortized              = false
  use_blended                = false
}

実際に AWS CLI で設定した Budget を import して tfstate を見てみると、上の組み合わせで CostTypes が指定されていました。

$ terraform import aws_budgets_budget.ri_coverage "112233445566:EC2 RI Coverage"
$ terraform state show aws_budgets_budget.ri_coverage