話題の記事

VSCode拡張機能『Infracost』を使って TerraformテンプレートからAWS利用費を試算してみた

VSCode拡張機能版Infracostを利用するとTerraformテンプレートを書いているだけで簡易的なAWS利用費の見積もりができます。無料で始められるのでまずはインストールしてみてください。
2023.11.25

あしざわです。

皆さんは、これから作成するAWS環境の利用費の見積もり、どうやっていますか?

最近アップロードされたAWS Dev Day 2023 Tokyoのアーカイブ動画を見ていたところ、『Infracost』というIaCテンプレートベースでAM利用費の見積もりができるツールの存在を知りました。

主にTerraformユーザーの方向けになりますが、誰でも無料で始められ導入も簡単かつ便利なツールなのでぜひ皆さんにも使ってほしいと思いブログを書きました。

まとめ

  • InfracostはTerraformテンプレート(.tfファイル)からインフラコストを試算できるツール
    • 無料のInfracost CLIおよびVSCode拡張機能、有料版のInfracost Cloudがある
  • VSCode拡張機能のInfracostを利用すると、VSCodeエディタ上でTerraformリソース単位のコストを計算したり、プロジェクト単位・.tfファイル単位でコスト見積もりできる
  • Infracostがサポートするリソースは公式ドキュメントに記載がある
    • ドキュメントに記載がないリソースでも利用できることもあるが、サポートしていないリソースを見つけたらGitHub ISSUEに上げてみましょう

Infracostとは?

Terraformデプロイのためのテンプレートである.tfファイルからインフラコストを試算できるツールです。

CLI機能のみをサポートするOSS版と、GUI機能を有する有料版のInfracost Cloudが提供されています。

InfracostにはVSCode拡張機能版のものがあり、VSCodeのエディタ上で想定コストが表示できるので大変使いやすいです。

ここからは、VSCode拡張機能版のInfracostのセットアップから使ってみた様子をお届けします。

初期セットアップ

VSCodeの拡張機能でInfracostと検索し、Installします。

画面左のアクティビティバーにInfracostのロゴが表示されるようになります。

Infracostバーから諸々の情報を確認することになるのですが、画面に表示される通りまずはVSCodeとInfracostを接続するための認証を行う必要があります。

Connect VSCode to Infracostをクリックすると、ブラウザが自動で開きInfracostアカウントでのログインを求められます。これはVSCode側にAPIキーを登録し、クラウドのコストに関する最新情報を取得するため必要なようです。

ログインした後に、再度Connect VSCode to Infracostをクリックすると、Authenticatedと表示されました。無事接続できたようです。

この時点でVSCodeを開いているディレクトリに.tf群を置いていない場合、Infracostバーには$0.00と表示されていました。

初期セットアップはここまでです。

基本的な機能と動作の前提

VSCode版 Infracostは以下の単位でコスト見積もりできます。

  1. ディレクトリ(プロジェクト)
  2. .tfファイル
  3. Terraformリソース

VSCodeのアクティビティバー(拡張機能やファイル検索、置換など選べるところ)のInfracostバーで1、2、3すべての情報を確認できます。

以下のようにディレクトリ単位のコスト見積もり(プロジェクト)は雲のマークで、.tfファイル単位の見積もりはTerraformロゴで表示されます。Terraformリソース単位の情報は四角いマークで表現されていますね。

プロジェクト全体のコストやファイル単位のコスト、Terraformリソース単位のその内訳など全体を俯瞰して確認したいときはアクティビティバーから確認すると良さそうです。

VSCodeのテキストエディタ上では、3のみ確認できます。

テキストエディタ上のコスト見積もりはファイルの保存時に動的に変更されるので、コードを書きながらそのリソースが発生するコストを意識でき、かなり効率的にテンプレートを作成できそうです。

これらを動作させる前提として、リソースが定義されている.tfファイルを配置するディレクトリと同じ階層で以下のようなリージョンを指定するprovider "aws"の定義が必須です。

provider "aws" {
  region = "ap-northeast-1"
}

provider "aws"provider.tfで指定しても、各リソースの.tfファイル内で定義しても問題ないです。

使ってみた

ここまでの準備でInfracostを使える状態になっているので、手を動かしながら機能を確認していきます。

今回はすべての検証にて、provider "aws"にて東京リージョン(ap-northeast-1)を指定して検証しています。

まずは以下のAWS構成図および.tfファイル構成のコスト試算を行いました。

./
└── ec2-private
    ├── provider.tf
    ├── ec2.tf
    └── vpc.tf

.tfファイルの内訳です。

* provider.tf
terraform {
  required_version = "1.4.5"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.23.1"
    }
  }
}

variable "aws_region" {
  default = "ap-northeast-1"
}

provider "aws" {
  region = var.aws_region
}

* vpc.tf
### VPC
resource "aws_vpc" "example" {
  cidr_block           = "10.0.0.0/16"
  instance_tenancy     = "default"
  enable_dns_hostnames = true
  enable_dns_support   = true
  tags = {
    Name = "terraform-vpc"
  }
}

### Subnet
#### Public Subnet 
resource "aws_subnet" "public" {
  vpc_id                  = aws_vpc.example.id
  cidr_block              = "10.0.1.0/24"
  map_public_ip_on_launch = true
  availability_zone       = "ap-northeast-1a"
  tags = {
    Name = "terraform-public-subnet-1a"
  }
}

#### Private Subnet
resource "aws_subnet" "private" {
  vpc_id                  = aws_vpc.example.id
  cidr_block              = "10.0.2.0/24"
  map_public_ip_on_launch = false
  availability_zone       = "ap-northeast-1a"
  tags = {
    Name = "terraform-private-subnet-1a"
  }
}

### Internet Gateway
resource "aws_internet_gateway" "example" {
  vpc_id = aws_vpc.example.id
  tags = {
    Name = "terraform-igw"
  }
}

### NAT Gateway
resource "aws_eip" "nat_gateway" {
  domain = "vpc"
  tags = {
    Name = "terraform-eip"
  }
}

resource "aws_nat_gateway" "public" {
  allocation_id = aws_eip.nat_gateway.id
  subnet_id     = aws_subnet.public.id

  tags = {
    Name = "terraform-ngw"
  }
}

### Route Table
#### Public
resource "aws_route_table" "public" {
  vpc_id = aws_vpc.example.id
  tags = {
    Name = "terraform-public-rtb"
  }
}

resource "aws_route" "public" {
  route_table_id         = aws_route_table.public.id
  gateway_id             = aws_internet_gateway.example.id
  destination_cidr_block = "0.0.0.0/0"
}

resource "aws_route_table_association" "public_a" {
  subnet_id      = aws_subnet.public.id
  route_table_id = aws_route_table.public.id
}

#### Private
resource "aws_route_table" "private" {
  vpc_id = aws_vpc.example.id
  tags = {
    Name = "terraform-private-rtb"
  }
}

resource "aws_route" "private" {
  route_table_id         = aws_route_table.private.id
  nat_gateway_id         = aws_nat_gateway.public.id
  destination_cidr_block = "0.0.0.0/0"
}

resource "aws_route_table_association" "private_a" {
  subnet_id      = aws_subnet.private.id
  route_table_id = aws_route_table.private.id
}

* ec2.tf
data "aws_ssm_parameter" "amazonlinux_2023" {
  name = "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64" # x86_64
}

### EC2 Instance
resource "aws_instance" "private" {
  ami                    = data.aws_ssm_parameter.amazonlinux_2023.id # Amazon Linux 2023
  vpc_security_group_ids = [aws_security_group.ec2.id]
  instance_type          = "t2.micro"
  subnet_id              = aws_subnet.private.id
  depends_on             = [aws_route.private]

  tags = {
    Name = "terraform-private-ec2-1a"
  }
}

Infracostバーに表示される結果がこちらで、プロジェクト単位(親ディレクトリ)、.tfファイル単位、リソース単位(aws_〜)でそれぞれコストが計算できていることがわかります。

まずvpc.tfにフォーカスして確認していきます。

このファイルでコストが発生していたのはaws_nat_gateway.publicのみで、$45.26のコストが発生すると表示されています。

Total monthly costの箇所をクリックすると、別タブで発生コストの内訳が表示できます。月に730h稼働したとみなして$45.26だと計算されているようです。

東京リージョンのNAT Gatewayのコストは0.062USD/1hなので、0.062*730=45.26ですね。もちろんですが合っている。

InfracostはAWSの各リソースをTerraformのリソースで判定し、課金されるPaid Resourcesと課金されないFree Resourcesに分類します。

VPC(aws_vpc)やサブネット(aws_subnet)はFree Resourcesで、NAT Gateway(aws_nat_gateway)はPaid Resourcesです。

色々触っていくと、PaidなのかFreeなのかについてはTerraformリソースだけを単にみているのではなくそのリソースの状態も考慮されていることがわかりました。

NAT Gatewayに関連づけられているElastic IP(aws_eip)は以下画像の通り、Paid Resourceだと見なされていません。

ですが、テンプレートからNAT Gateway(aws_nat_gateway)を削除すると、Elastic IPがPaid Resourceであると判定されました。

みなさんご存知の通り、EIPは他のリソースに関連付けされないときに1時間単位の従量課金コストが発生します。上記でその通りに表示されているように、InfracostではTerraformリソースだけでなくリソースの状態も認識できるようです。

続いて、ec2.tfについて見ていきます。

この.tfファイルでは、t2.microのEC2インスタンス(Amazon Linux 2023)をオンデマンドで起動させています。Total monthly costは$12.06です。

内訳を確認すると、Linux系のt2.microのインスタンスをオンデマンドで730時間稼働させる分のコストが$11.10、RootボリュームのEBS(8GB)が$0.96の合計で$12.06とのことでした。今回のテンプレートでは明示的にEBSを定義してませんでしたが、起動のために最低限必要なものはあると判断してくれるようですね。

ここで試しにインスタンスタイプをu-12tb1.112xlargeに変更してみました。ざっと確認した限り、最も料金が高いインスタンスタイプの1つです。

更新差分をec2.tfのファイルを保存したタイミングで内訳と同時にリロードされ、Total monthly costが$96,166.05に更新されました(高い…)

Infracostバーに表示されるコストはこの時点では更新されていませんが、右上の更新ボタンをクリックすると変更が反映されます。

ここまでみていただいた通り、Infracostで試算できるコスト見積もりにはデフォルトではアウトバウンド通信費用やリージョン間通信コストなどが含まれないため、計算される利用費はあくまで簡易的なものとなります。

使用量に応じて変動するコストまで見積もりたい場合は、Usage-based resourcesを活用してみてください。

一般的に通信量によって変動するようなコストを事前に見積もることは難しいため、既存環境である程度通信量が見積もれているケースにマッチしそうです。

個人的には、EC2インスタンスなどのリソースの個数や利用した時間に応じて変動するリソースだけでも簡単にコストを見積もれるだけ大変ありがたいです。

VSCode拡張の検証については以上になりますが、Infracostとしてはその他の機能が存在します。

Infracost CLIを使うと、コスト見積もりの出力や複数プロジェクトの差分比較機能が利用できます。これらはVSCode拡張と同様に無償で利用できます。

Infracost Cloud(有料)を利用すると、マルチクラウドGitHubなどのソース管理ツールと連携してCI/CDプロセスにコスト見積もり機能を挿入したり、ダッシュボード機能、マルチクラウド管理機能など様々な機能が活用できます。

※↑画像は公式ドキュメントからの引用

これらの機能は今回あまり触れられなかったので、また機会があればぜひ触ってみたいです。

参考: 非対応リソースについて

InfracostはすべてのTerraformリソースをサポートしているわけではなく、一部のリソースのみをサポートしてます。

現時点でInfracostがサポートするリソースは先述した公式ドキュメントのPaid Resources および Free Resourcesに記載されています。

例えば、公式ドキュメント上ではaws_elasticsearch_domainをサポートしていますが、名称変更後の後継の同サービスであるaws_opensearch_domainのサポートは明示的に記載されていません。

試しにaws_elasticsearch_domainaws_opensearch_domainの両方のリソースを同じテンプレート上に作成してみました。

どちらもコスト計算できていますね。

どうやら以下PRでマージされていたようです。

その他、InfracostのGitHub ISSUEにて現在進行形で複数のISSUEが挙げられており対応が進められています(例えば、CloudHSM、App Runner、Route 53 Resolver DNS Firewall)

このリソースをサポートしてほしい!というものがあればGitHub ISSUEをあげてみてはいかがでしょうか?

参考

最後に

VSCode拡張機能『Infracost』について調査・検証してみました。

誰でも無料で気軽に利用できるので、Terraformを普段使うエンジニアの方にはぜひインストールしていただきたいです。

以上です。