[Terraform] Infracostでコスト監視!見積もりをもっと簡単に

10月 11, 2023

どもども、お元気でしょうか。私は変わらずSREエンジニアとして日々業務をこなしております。


さて、我々SREエンジニア、あるいはクラウドインフラエンジニアなどサービスを稼働ているインフラを管理している者たちにとって避けられないの業務としてコスト管理があります。


日々運用しているインフラコストを監視しますし、新しく環境を構築する際、または拡張する際など新たにインフラリソースが作成される際には必ずと言っていいほど発生する料金を計算します。


地味に面倒くさく感じるこの料金見積もりをもっと楽にしたいということで、今回はInfracostを試してみたいと思います。

Infracostとは

Infracostとはterraformで作成されるリソースに対し1ヶ月あたりでどれほどの料金が発生するかを見積もってくれるオープンソースツールです。


今回は試してみるだけなのでターミナル上で使用しますが、公式ページにデカデカと書いている通り

Cloud cost estimates for Terraform in pull requests

本来はGitHubのPRやGitLabのMRの際、ワークフローに仕込んでおくことで随時作成されるリソースの内容に加え料金も確認することを目的に作られているようです。


実際にGithub Actionsを利用してワークフローを構築している例は以下の記事を参照ください。

AWSのコストをInfracost+Github Actionsでいい感じに把握する。


それでは実際にどのように料金が表示されるのか、またその精度など検証してみましょう!

準備

必要な事前準備の全貌はこちらのページで確認できます。以下に記載しているのはMacOSの場合の準備手順ですので状況に合わせてそちらを確認してください。


まずはInfracostをインストールしましょう。ちゃんとインストールできているかをバージョンも含めて確認することもお忘れなく。

$ brew install infracost
$ infracost --version
Infracost v0.10.17

今回はbrewでインストールしているのでバージョンアップが必要になった際は以下のようにどうぞ

$ brew upgrade infracost

infracostを利用するには APIキーを取得する必要があるため、以下のコマンドで登録を済ませてキーをゲットしましょう。

$ infracost auth login

ログインページに飛ばされるかと思うので"Log in"をクリックし"Sign Up"をタブからGitHubかGoogleのアカウント、あるいはメールアドレスとパスワードを利用してユーザー登録を行います。

登録が完了したら上記画像のページに戻りますがWeb上での操作は以上です。

ターミナルに戻るとキーを取得できていることがわかります。

The API key was saved to /Users/tanakasaiki/.config/infracost/credentials.yml

もし下記のようなエラーが出た場合は"infracost auth login“コマンドを実行し再度ログインしてみてください。

Error: Authentication failed. Please check your API token on https://infracost.io

取得したAPIキーの値は下記コマンドで確認できるのでワークフローに盛り込む時は事前に確認しておきましょう。

$ infracost configure get api_key

これで準備は完了です。簡単なTerraformファイルを作成し、料金を確認してみましょう!

実践

今回は以下のような構成をサンプルとして用意しました。

<my-first-infracost>
.
├── backend.tf
├── ec2.tf
├── locals.tf
└── rds.tf

もちろんすでに用意しているterraform構成などがありましたらそちらをご利用ください!一応上記構成を利用する方に向けて各ファイルの内容を記載しておきます。Terraformファイルの中身は公式のサンプルから引っ張り出してきたものです。

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 3.0"
    }
  }
}

provider "aws" {
  region  = local.region
  profile = local.profile # Profileを利用しない場合はコメントアウトしてください
}
locals {
    region           = "ap-northeast-1"
    profile          = "<利用するProfile名>" # Profileを利用しない場合はコメントアウトしてください
}
data "aws_ami" "ubuntu" {
  most_recent = true

  filter {
    name   = "name"
    values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
  }

  filter {
    name   = "virtualization-type"
    values = ["hvm"]
  }

  owners = ["099720109477"] # Canonical
}

resource "aws_instance" "infracost" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = "t3.micro"

  tags = {
    Name = "infracost-test"
  }
}
resource "aws_db_instance" "infracost" {
  allocated_storage    = 10
  name                 = "mydb"
  engine               = "mysql"
  engine_version       = "5.7"
  instance_class       = "db.t3.micro"
  username             = "infracost_foobarbaz" # 実際の環境構築に用いる場合は変更してください
  password             = "infracost_foobarbaz" # 実際の環境構築に用いる場合は変更してください
  parameter_group_name = "default.mysql5.7"
  skip_final_snapshot  = true
}

ネットワークリソースなどを特に用意していないので実際に使用する環境としては不十分ですが、infracostを試す分には十分だと思います。

terraformファイルの用意ができたら必ず“terraform plan"が通ることを確認しておきましょう!planが通らない状態では全てのリソースに対する料金が$0.00と表示されてしまうためです。

ここまで準備できたら早速料金を表示してみましょう!

Name                                                        Monthly Qty  Unit   Monthly Cost 
                                                                                              
 aws_db_instance.infracost                                                                    
 ├─ Database instance (on-demand, Single-AZ, db.t3.micro)          730  hours        $18.98 
 └─ Storage (general purpose SSD, gp2)                              10  GB            $1.38 
                                                                                              
 aws_instance.infracost                                                                       
 ├─ Instance usage (Linux/UNIX, on-demand, t3.micro)               730  hours         $9.93 
 └─ root_block_device                                                                       
    └─ Storage (general purpose SSD, gp2)                            8  GB            $0.96 
                                                                                              
 OVERALL TOTAL                                                                         $31.25 
──────────────────────────────────

おお!料金が表示されていますね!

さらに詳細な設定として使用料ベースの計算にも対応しています。下記コマンドを実行することで現在作成される予定のリソースに対してwhat-ifを設定するためのyamlファイルを生成、更新できます。

$ infracost breakdown --sync-usage-file --usage-file infracost-usage.yml --path .

例えば今回のEC2やRDSの場合リザーブドインスタンスを適用したケースの見積もりや、一定量のIO発生を予想した設定など使用ケースや量に応じて柔軟に設定できることがわかります。

試しにリザーブドインスタンスを適用するケースで料金を算出してみましょう。上記コマンドで生成されたyamlファイルのうち必要な設定の分だけコメントアウトを外し値を設定してみます。

...  
 aws_instance:
    # operating_system: linux # Override the operating system of the instance, can be: linux, windows, suse, rhel.
    reserved_instance_type: "standard" # Offering class for Reserved Instances, can be: convertible, standard.
    reserved_instance_term: "1_year" # Term for Reserved Instances, can be: 1_year, 3_year.
    reserved_instance_payment_option: "no_upfront" # Payment option for Reserved Instances, can be: no_upfront, partial_upfront, all_upfront.
...

上記yamlの設定を利用して料金を算出してみると

$ infracost breakdown --path . --usage-file infracost-usage.yml
...
Name                                                        Monthly Qty  Unit   Monthly Cost 
                                                                                              
 aws_db_instance.infracost                                                                    
 ├─ Database instance (on-demand, Single-AZ, db.t3.micro)          730  hours        $18.98 
 └─ Storage (general purpose SSD, gp2)                              10  GB            $1.38 
                                                                                              
 aws_instance.infracost                                                                       
 ├─ Instance usage (Linux/UNIX, reserved, t3.micro)                730  hours         $6.28 
 └─ root_block_device                                                                       
    └─ Storage (general purpose SSD, gp2)                            8  GB            $0.96 
                                                                                              
 OVERALL TOTAL                                                                         $27.60 
──────────────────────────────────

リザーブドインスタンス分のコスト削減が行われていることができました!LambdaやS3など使用料ベースで料金が計算されるリソースに対しては特に有効であると言えます。


一通り料金が計算できましたらファイルにJSON形式で出力してみます。

$ infracost breakdown --path . --format json --out-file infracost-base.json

ファイルに出力しておくことでterraformの設定を変更した際に料金比較が可能となります。例えば

...
instance_class       = "db.t3.large"
...

このようにRDSのスペックを上げて料金比較をしてみましょう。

$ infracost diff --path . --compare-to infracost-base.json
...

~ aws_db_instance.infracost
  +$133 ($20.36 → $153)

    ~ Database instance (on-demand, Single-AZ, db.t3.micro → db.t3.large)
      +$133 ($18.98 → $152)

Monthly cost change for personal1379/my-first-infracost
Amount:  +$133 ($31.25 → $164)
Percent: +425%

──────────────────────────────────
Key: ~ changed, + added, - removed

前回のスペック(db.t3.micro)と比較し料金が$133(425%)上昇したことがわかりました!

まとめ

今回はinfracostを利用し、terraformでリソースを構築する前に料金を算出してみました。


非常にシンプルなため使いやすく、精度も細かくすることが出来るため料金見積もりには有効だとおもいます。CIに組み込むのにもそんなに手間はかからないでしょう。


日々様々な業務に追われる忙し屋さんの皆様、是非infracostを検討してみてはいかがでしょうか。


最後まで読んでいただきありがとうございました!

AWS,Terraform

Posted by CY