Terraformの便利ツールを使ってみよう(第二回)〜Infracost編〜

# はじめに
- 月に一回更新予定のTerraformの便利なツール紹介コーナー、第二回ではTerraformで作成されるリソースのコスト見積もりを提供してくれるツールであるInfracostをご紹介します
# Infracostとは
- Terraformの設定ファイル(.tfファイル)を読み込ませることで、作成予定のクラウドリソースのコストを試算してくれるツールです。
- 利用方法として、無償のInfracost CLI及びVSCode拡張機能、もしくは有償版のInfracost Cloudが用意されています。
  - 今回の記事では、無償版のInfracost CLIをご紹介します。
  - VSCode拡張機能もご紹介しようと思ったのですが、なぜか計算処理が動いてくれなかったので…｡ﾟ(ﾟ´Д｀ﾟ)ﾟ｡
- Infracost Cloudの料金体系
  - 最小で$1,000と、かなり費用がかかってしまう感が正直あります。
  - 14日間の無料トライアルが用意されていますので、まずは無償版で試してみつつ、Infracost Cloudの必要性を試してみるのが良いでしょう。
    - [How does the Infracost free trial work?](https://www.infracost.io/pricing/)
  - [Plans & Pricing](https://www.infracost.io/pricing/)
- GitHubでソースが公開されていますが、数か月から半年程度で1バージョンがリリースされているようです。
  - [Infracost リリースノート](https://github.com/infracost/infracost/releases)
  - 2025年3月22日現在、最新は **v0.10.41** とGAではないようです。
  - Previewリリースのようで、まだ本番利用…には厳しいかもしれないですね。
- 同じく2025年3月22日現在、AWS、Azure、Googleに対応しています。
  - OCI対応は…いずれあるのでしょうか。
# 紹介する構成
- 今回、静的な構成(利用料金が固定になる)と動的な構成(利用料に応じてリソース数の増減が発生する)の2パターンで構成し、それぞれどういった出力になるかを見てみます。
## 静的な構成
- 以下で紹介した、VPCにEC2を1台作成するという構成を用います。
  - [お試し環境](https://qiita.com/ec2_on_aws/items/3925fe5f1982ed99edbf#%E3%81%8A%E8%A9%A6%E3%81%97%E3%81%99%E3%82%8B%E6%A7%8B%E6%88%90)
- 構成図は以下です
  ![terraform_static.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276335/2b66f547-b291-423e-99bf-ed50d1917fa7.png)
  
- tfファイルは以下です。
    <details><summary>VPCにEC2を1台作成するTerraformコード</summary>
    
    ```hcl
    terraform {
        required_providers {
        aws = {
            source  = "hashicorp/aws"
            version = "5.91.0"
        }
        }

        # S3 Backendを設定
        backend "s3" {
        bucket = "terraform-backend-73m3j2gank8zpymc8yyn"
        key    = "terraform.tfstate"
        region = "ap-northeast-1"
        use_lockfile = true
        }
    }

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

    resource "aws_vpc" "main" {
        cidr_block           = "10.0.0.0/16"
        enable_dns_support   = true
        enable_dns_hostnames = true

        tags = {
        Name = "main-vpc"
        }
    }

    resource "aws_subnet" "private" {
        vpc_id            = aws_vpc.main.id
        cidr_block        = "10.0.1.0/24"
        availability_zone = "ap-northeast-1a"

        tags = {
        Name = "private-subnet"
        }
    }

    resource "aws_instance" "al2023" {
        ami           = "ami-0599b6e53ca798bb2"
        instance_type = "t2.micro"
        subnet_id     = aws_subnet.private.id
    }
    ```
    
    </details>

## 動的な構成
- 以下で紹介した、CloudFrontからVPC Originを用いてALBに到達する、という構成を用います。
  - [お試し環境](https://qiita.com/ec2_on_aws/items/45eb4d06e2642158c776#%E3%81%8A%E8%A9%A6%E3%81%97%E7%92%B0%E5%A2%83)
- 構成図は以下です
  ![VPC Origin環境](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276335/4f08e09a-5704-3b9e-5462-15e8c7bb7fd3.png)
- tfファイルは以下です。
    <details><summary>VPC originを用いたTerraformコード</summary>

    ```hcl
    terraform {
        required_providers {
            aws = {
            source  = "hashicorp/aws"
            version = "5.84.0"
            }
            random = {
            source  = "hashicorp/random"
            version = "~> 3.0"
            }
        }
        backend "s3" {
            bucket = "terraform-backend-73m3j2gank8zpymc8yyn"
            key    = "terraofrm-tool-pike/terraform.tfstate"
            region = "ap-northeast-1"
        }
    }

    provider "aws" {
        region = "ap-northeast-1"
        default_tags {
            tags = {
            Terraform = "true"
            }
        }
    }

    locals {
        availability_zones = [
            "ap-northeast-1a",
            "ap-northeast-1c",
            "ap-northeast-1d",
        ]
    }

    data "aws_ec2_managed_prefix_list" "cloudfront" {
        name = "com.amazonaws.global.cloudfront.origin-facing"
    }

    resource "aws_vpc" "this" {
        cidr_block = "10.0.0.0/16"
    }

    resource "aws_internet_gateway" "this" {
        vpc_id = aws_vpc.this.id
    }

    resource "aws_subnet" "this" {
        for_each = toset(local.availability_zones)

        vpc_id            = aws_vpc.this.id
        availability_zone = each.key
        cidr_block        = cidrsubnet(aws_vpc.this.cidr_block, 8, index(local.availability_zones, each.key))
    }

    resource "aws_security_group" "private_alb" {
        vpc_id = aws_vpc.this.id

        ingress {
            from_port       = 80
            to_port         = 80
            protocol        = "tcp"
            prefix_list_ids = [data.aws_ec2_managed_prefix_list.cloudfront.id]
        }
    }

    resource "aws_lb" "private_alb" {
        name               = "private-alb"
        internal           = true
        load_balancer_type = "application"
        security_groups    = [aws_security_group.private_alb.id]
        subnets            = [for subnet in aws_subnet.this : subnet.id]
        }

        resource "aws_lb_listener" "private_alb" {
        load_balancer_arn = aws_lb.private_alb.arn
        port              = 80
        protocol          = "HTTP"

        default_action {
            type = "fixed-response"

            fixed_response {
            content_type = "text/plain"
            message_body = "Hello"
            status_code  = "200"
            }
        }
    }

    resource "aws_cloudfront_vpc_origin" "private_alb" {
        vpc_origin_endpoint_config {
            name                   = "private-alb"
            arn                    = aws_lb.private_alb.arn
            http_port              = 80
            https_port             = 443
            origin_protocol_policy = "http-only"

            origin_ssl_protocols {
            quantity = 1
            items    = ["TLSv1.2"]
            }
        }
    }

    resource "aws_cloudfront_distribution" "private_alb" {
        origin {
            origin_id   = "private_alb"
            domain_name = aws_lb.private_alb.dns_name
            vpc_origin_config {
            vpc_origin_id = aws_cloudfront_vpc_origin.private_alb.id
            }
        }

        enabled = true

        default_cache_behavior {
            allowed_methods  = ["GET", "HEAD"]
            cached_methods   = ["GET", "HEAD"]
            target_origin_id = "private_alb"

            forwarded_values {
                query_string = false

                cookies {
                    forward = "none"
                }
            }
            viewer_protocol_policy = "redirect-to-https"
        }

        restrictions {
            geo_restriction {
            restriction_type = "none"
            }
        }

        viewer_certificate {
            cloudfront_default_certificate = true
        }

        logging_config {
            include_cookies = false
            bucket          = aws_s3_bucket.cloudfront_logs.bucket_domain_name
            prefix          = "cloudfront-logs/"
        }
    }

    # S3
    ## ランダム文字列を生成するリソース
    resource "random_string" "bucket_suffix" {
        length  = 16
        special = false
        upper   = false
    }

    resource "aws_s3_bucket" "cloudfront_logs" {
        bucket        = "my-cloudfront-logs-bucket-${random_string.bucket_suffix.result}"
        force_destroy = true
    }

    resource "aws_s3_bucket_ownership_controls" "cloudfront_logs" {
        bucket = aws_s3_bucket.cloudfront_logs.id

        rule {
            object_ownership = "ObjectWriter"
        }
    }

    resource "aws_s3_bucket_acl" "cloudfront_logs" {
        depends_on = [aws_s3_bucket_ownership_controls.cloudfront_logs]

        bucket = aws_s3_bucket.cloudfront_logs.id
        acl    = "private"
    }

    resource "aws_s3_bucket_acl" "cloudfront_logs_canonical" {
        depends_on = [aws_s3_bucket_ownership_controls.cloudfront_logs]

        bucket = aws_s3_bucket.cloudfront_logs.id

        access_control_policy {
            owner {
                id = data.aws_canonical_user_id.current.id
            }

            grant {
                grantee {
                    id   = data.aws_canonical_user_id.current.id
                    type = "CanonicalUser"
                }
                permission = "FULL_CONTROL"
            }

            grant {
                grantee {
                    id   = "c4c1ede66af53448b93c283ce9448c4ba468c9432aa01d700d3878632f77d2d0" # CloudFront Log Delivery のカノニカルユーザーID
                    type = "CanonicalUser"
                }
                permission = "WRITE"
            }
        }
    }

    data "aws_canonical_user_id" "current" {}

    output "cloudfront_url" {
        description = "URL of the CloudFront distribution"
        value       = "http://${aws_cloudfront_distribution.private_alb.domain_name}"
    }
    ```
    </details>

# 事前準備(アカウント作成)
- 以下にアクセスいただき、アカウントを作成してください。
  - [Log In/Sign Up画面](https://dashboard.infracost.io/)
- すでにアカウントをお持ちの方は"Log In"から、アカウントをまだお持ちでない方は"Sign Up"からアカウントを作成してください。
- Infracostに直接アカウントを作成する方法のほか、GitHub/Googleログインもサポートされています。
# Infracost CLI
## 導入手順
- 以下を参考にInfracostを導入していきます。
  - [Get started](https://www.infracost.io/docs/)
### macOS
- コマンド
    ```
    brew install infracost
    infracost --version
    ```
- 実行結果
    <details><summary>infracostのインストール</summary>

    ```
    % brew install infracost
    ==> Auto-updating Homebrew...
    Adjust how often this is run with HOMEBREW_AUTO_UPDATE_SECS or disable with
    HOMEBREW_NO_AUTO_UPDATE. Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
    ==> Auto-updated Homebrew!
    Updated 5 taps (derailed/k9s, hashicorp/tap, jameswoolfenden/tap, homebrew/core and homebrew/cask).
    ==> New Formulae
    adaptivecpp                         decompose                           gut                                 ra-multiplex
    alloy                               dockcheck                           icu4c@77                            rasterio
    anyquery                            excalidraw-converter                jaguar                              shuttle
    cargo-sort                          fabric-ai                           lume                                terraform-iam-policy-validator
    cargo-spellcheck                    fiona                               nmstatectl                          veccore
    cpp-lazy                            git-who                             projectable                         yutu
    darklua                             gtree                               protobuf@29                         zlib-rs
    ==> New Casks
    ace-studio                          coterm                              font-playpen-sans-arabic            k6-studio
    advanced-renamer                    font-maple-mono-normal              font-playpen-sans-hebrew            nethlink
    agent-tars                          font-maple-mono-normal-cn           font-pretendard-gov                 qobuz-downloader
    charles@4                           font-maple-mono-normal-nf           font-webdings                       thelowtechguys-cling
    chime@alpha                         font-maple-mono-normal-nf-cn        font-winky-rough

    You have 28 outdated formulae installed.

    ==> Downloading https://ghcr.io/v2/homebrew/core/infracost/manifests/0.10.41
    ####################################################################################################################################### 100.0%
    ==> Fetching infracost
    ==> Downloading https://ghcr.io/v2/homebrew/core/infracost/blobs/sha256:06de717bd785bcd624c997a14590ff47a188e31536d2fd5117b4d316c0dc6904
    ####################################################################################################################################### 100.0%
    ==> Pouring infracost--0.10.41.arm64_sequoia.bottle.tar.gz
    ==> Caveats
    zsh completions have been installed to:
    /opt/homebrew/share/zsh/site-functions
    ==> Summary
    🍺  /opt/homebrew/Cellar/infracost/0.10.41: 9 files, 104.4MB
    ==> Running `brew cleanup infracost`...
    Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
    Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
    %  infracost --version
    Infracost v0.10.41
    % 
    ```

    </details>

### Windows exe
1. 以下より最新リリースをDLし、解凍する。
   - [解凍フォルダ](https://github.com/infracost/infracost/releases/latest/download/infracost-windows-amd64.zip)
2. 解凍したフォルダにある"infracost.exe"をコマンドプロンプトやPowershellから実行する。
3. (オプション)Windowsの環境変数に設定する。
### まとめ
- 今回紹介するmacOS/Windows以外に、LinuxやDockerコンテナとしての利用もできます。
  - ご利用の環境に応じて導入してみてください。
- 個人的に、Windows用にわざわざインストールするためだけのツール(今回で言うとchoco)を用意せずとも利用可能なexeが用意されている、というのは親切でいいなぁ…と思いました。
## 初期設定
- 以下コマンドでAPIキーを登録する。
    ```
    infracost auth login
    ```
- ブラウザに飛ばされるので、InfracostにログインすればOK。
- 認証に成功すると、以下画面になる。
  ![Infracost_cli_login.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276335/f67d7460-2fb6-4d73-b898-a3fd3c4f1274.png)
- ターミナルは以下
    ```shell
    % infracost auth login
    We're redirecting you to our log in page, please complete that,
    and return here to continue using Infracost.

    If the redirect doesn't work, either:
    - Use this URL:
        https://dashboard.infracost.io/login?cli_port=59152&cli_state=xxxxxxxxxxxxxxxxxxxxxxx&cli_version=v0.10.41&os=darwin&utm_source=cli

    - Or log in/sign up at https://dashboard.infracost.io, copy your API key
        from Org Settings and run `infracost configure set api_key MY_KEY`

    Waiting...

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

    Your account has been authenticated. Run Infracost on your Terraform project by running:

    infracost breakdown --path=.

    % 
    ```
- 以下記載箇所のファイルを見ると、APIキーを見ることができます
    ```
    The API key was saved to /xxxxxxxxxx/.config/infracost/credentials.yml
    ```
## Infracostのヘルプをチェック
<details><summary>Infracostのヘルプ</summary>

```shell
% infracost --help
Infracost - cloud cost estimates for Terraform

DOCS
  Quick start: https://infracost.io/docs
  Add cost estimates to your pull requests: https://infracost.io/cicd

USAGE
  infracost [flags]
  infracost [command]

EXAMPLES
  Show cost diff from Terraform directory:

      infracost breakdown --path /code --format json --out-file infracost-base.json
      # Make Terraform code changes
      infracost diff --path /code --compare-to infracost-base.json

  Show cost breakdown from Terraform directory:

      infracost breakdown --path /code --terraform-var-file my.tfvars

AVAILABLE COMMANDS
  auth             Get a free API key, or log in to your existing account
  breakdown        Show breakdown of costs
  comment          Post an Infracost comment to GitHub, GitLab, Azure Repos or Bitbucket
  completion       Generate shell completion script
  configure        Display or change global configuration
  diff             Show diff of monthly costs between current and planned state
  generate         Generate configuration to help run Infracost
  help             Help about any command
  output           Combine and output Infracost JSON files in different formats
  upload           Upload an Infracost JSON file to Infracost Cloud

FLAGS
      --debug-report       Generate a debug report file which can be sent to Infracost team
  -h, --help               help for infracost
      --log-level string   Log level (trace, debug, info, warn, error, fatal)
      --no-color           Turn off colored output
  -v, --version            version for infracost

Use "infracost [command] --help" for more information about a command.
% 
```

</details>

## 基本コマンドをチェック
- 基本コマンドとしては以下が用意されています
```
infracost breakdown: コストの内訳を表示、ベースラインの生成にも使用可能
infracost diff: 現在のブランチとベースライン間の月額コストの差分を表示
infracost generate config: テンプレートファイルからInfracostの設定ファイルを生成
```
### infracost breakdownのヘルプをチェック
- メインとなるコマンドがbreakdownです
- このコマンドで"--path"オプションをつけ、読み込ませたいterraformの設定ファイルパスを指定することで、コスト算出させることができます。

<details><summary>infracost breakdownのヘルプ</summary>

```shell
% infracost breakdown --help
Show breakdown of costs

USAGE
  infracost breakdown [flags]

EXAMPLES
  Use Terraform directory:

      infracost breakdown --path /code --terraform-var-file my.tfvars

  Use Terraform plan JSON:

      terraform plan -out tfplan.binary
      terraform show -json tfplan.binary > plan.json
      infracost breakdown --path plan.json

FLAGS
      --config-file string           Path to Infracost config file. Cannot be used with path, terraform* or usage-file flags
      --exclude-path strings         Paths of directories to exclude, glob patterns need quotes
      --fields strings               Comma separated list of output fields: all,price,monthlyQuantity,unit,hourlyCost,monthlyCost.
                                     Supported by table and html output formats (default [monthlyQuantity,unit,monthlyCost])
      --format string                Output format: json, table, html (default "table")
  -h, --help                         help for breakdown
      --include-all-paths            Set project auto-detection to use all subdirectories in given path
      --no-cache                     Don't attempt to cache Terraform plans
      --out-file string              Save output to a file, helpful with format flag
  -p, --path string                  Path to the Terraform directory or JSON/plan file
      --project-name string          Name of project in the output. Defaults to path or git repo name
      --show-skipped                 List unsupported resources
      --sync-usage-file              Sync usage-file with missing resources, needs usage-file too (experimental)
      --terraform-var stringArray    Set value for an input variable, similar to Terraform's -var flag
      --terraform-var-file strings   Load variable files, similar to Terraform's -var-file flag. Provided files must be relative to the --path flag
      --terraform-workspace string   Terraform workspace to use. Applicable when path is a Terraform directory
      --usage-file string            Path to Infracost usage file that specifies values for usage-based resources

GLOBAL FLAGS
      --debug-report       Generate a debug report file which can be sent to Infracost team
      --log-level string   Log level (trace, debug, info, warn, error, fatal)
      --no-color           Turn off colored output
% 
```

</details>

### infracost diffのヘルプをチェック
- 以下がポイントですね
```
      infracost breakdown --path /code --format json --out-file infracost-base.json
      # Make Terraform code changes
      infracost diff --path /code --compare-to infracost-base.json
```
- まずbreakdownコマンドで今のterraformの設定ファイルのコストをjson形式で出力しておいて、その後設定ファイルを修正、その前後のコストを比較してくれます。

<details><summary>infracost diffのヘルプ</summary>

```shell
% infracost diff --help
Show diff of monthly costs between current and planned state

USAGE
  infracost diff [flags]

EXAMPLES
  Use Terraform directory:

      infracost breakdown --path /code --format json --out-file infracost-base.json
      # Make Terraform code changes
      infracost diff --path /code --compare-to infracost-base.json

  Use Terraform plan JSON:

      terraform plan -out tfplan.binary
      terraform show -json tfplan.binary > plan.json
      infracost diff --path plan.json

FLAGS
      --compare-to string            Path to Infracost JSON file to compare against
      --config-file string           Path to Infracost config file. Cannot be used with path, terraform* or usage-file flags
      --exclude-path strings         Paths of directories to exclude, glob patterns need quotes
      --format string                Output format: json, diff (default "diff")
  -h, --help                         help for diff
      --include-all-paths            Set project auto-detection to use all subdirectories in given path
      --no-cache                     Don't attempt to cache Terraform plans
      --out-file string              Save output to a file
  -p, --path string                  Path to the Terraform directory or JSON/plan file
      --project-name string          Name of project in the output. Defaults to path or git repo name
      --show-skipped                 List unsupported resources
      --sync-usage-file              Sync usage-file with missing resources, needs usage-file too (experimental)
      --terraform-var stringArray    Set value for an input variable, similar to Terraform's -var flag
      --terraform-var-file strings   Load variable files, similar to Terraform's -var-file flag. Provided files must be relative to the --path flag
      --terraform-workspace string   Terraform workspace to use. Applicable when path is a Terraform directory
      --usage-file string            Path to Infracost usage file that specifies values for usage-based resources

GLOBAL FLAGS
      --debug-report       Generate a debug report file which can be sent to Infracost team
      --log-level string   Log level (trace, debug, info, warn, error, fatal)
      --no-color           Turn off colored output
% 
```

</details>

- diffの実行例(EC2インスタンスを1台追加)

<details><summary>diffの実行例</summary>

```
% infracost breakdown --path . --format json --out-file infracost-base.json
INFO Autodetected 1 Terraform project across 1 root module
INFO Found Terraform project main at directory .
INFO Output saved to infracost-base.json
% 
% infracost diff --path . --compare-to infracost-base.json 
INFO Autodetected 1 Terraform project across 1 root module
INFO Found Terraform project main at directory .

Key: * usage cost, ~ changed, + added, - removed

──────────────────────────────────
Project: main

+ aws_instance.al2023-2
  +$12

    + Instance usage (Linux/UNIX, on-demand, t2.micro)
      +$11

    + root_block_device
    
        + Storage (general purpose SSD, gp2)
          +$0.96

Monthly cost change for .
Amount:  +$12 ($12 → $24)
Percent: +100%

──────────────────────────────────
Key: * usage cost, ~ changed, + added, - removed

*Usage costs can be estimated by updating Infracost Cloud settings, see docs for other options.

4 cloud resources were detected:
∙ 2 were estimated
∙ 2 were free

Infracost estimate: Monthly estimate increased by $12 ↑
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ Changed project                                    ┃ Baseline cost ┃ Usage cost* ┃ Total change ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━━━━━━━━┫
┃ .                                                  ┃          +$12 ┃           - ┃ +$12 (+100%) ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┛
% 
```

</details>

### infracost generate configのヘルプをチェック

<details><summary>infracost generate configのヘルプ</summary>

```
% infracost generate config --help
Generate Infracost config file from a template file. See docs for template examples and syntax:

  https://www.infracost.io/docs/features/config_file/#template-syntax

USAGE
  infracost generate config [flags]

EXAMPLES

      infracost generate config --repo-path . --template-path infracost.yml.tmpl --out-file infracost.yml
      

FLAGS
  -h, --help                   help for config
      --out-file string        Save output to a file
      --repo-path string       Path to the Terraform repo or directory you want to run the template file on (default ".")
      --template string        Infracost template string that will generate the config-file yaml output
      --template-path string   Path to the Infracost template file that will generate the config-file yaml output
      --tree-file string       Save a simplified tree of the detected projects and var files to a file

GLOBAL FLAGS
      --debug-report       Generate a debug report file which can be sent to Infracost team
      --log-level string   Log level (trace, debug, info, warn, error, fatal)
      --no-color           Turn off colored output
% 
```

</details>

## お試し
### 静的な環境
- breakdownコマンドを試してみた結果
    ```
    % infracost breakdown --path .
    INFO Autodetected 1 Terraform project across 1 root module
    INFO Found Terraform project main at directory .

    Project: main

    Name                                                   Monthly Qty  Unit   Monthly Cost   
                                                                                            
    aws_instance.al2023                                                                       
    ├─ Instance usage (Linux/UNIX, on-demand, t2.micro)          730  hours        $11.10   
    └─ root_block_device                                                                    
        └─ Storage (general purpose SSD, gp2)                       8  GB            $0.96   
                                                                                            
    OVERALL TOTAL                                                                   $12.06 

    *Usage costs can be estimated by updating Infracost Cloud settings, see docs for other options.

    ──────────────────────────────────
    3 cloud resources were detected:
    ∙ 1 was estimated
    ∙ 2 were free

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
    ┃ Project                                            ┃ Baseline cost ┃ Usage cost* ┃ Total cost ┃
    ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━━━━━━┫
    ┃ main                                               ┃           $12 ┃           - ┃        $12 ┃
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┻━━━━━━━━━━━━┛
    % 
    ```
- 読んでみると…
  - 費用がかかるのは、Instanceの箇所とEBSであること、それぞれがどういう属性を持っていてそれがどれくらい費用がかかるかがわかります。
  - どれがfreeリソースであるかも判別できています。
- 実際の費用と比較すると
  - AWS 料金見積りツールを用いて、al2023でt2.microを東京リージョンで作成、EBS(gp2)を8GBで作成すると$12.06と試算できました。
  - 正確ですね。
### 動的な環境
- breakdownコマンドを試してみた結果
    ```
    % infracost breakdown --path .
    INFO Autodetected 1 Terraform project across 1 root module
    INFO Found Terraform project main at directory .

    Project: main

    Name                                                      Monthly Qty  Unit                    Monthly Cost   
    
    aws_lb.private_alb                                                                                            
    ├─ Application load balancer                                    730  hours                         $17.74   
    └─ Load balancer capacity units                   Monthly cost depends on usage: $5.84 per LCU              
    
    aws_cloudfront_distribution.private_alb                                                                       
    ├─ Real-time log requests                         Monthly cost depends on usage: $0.01 per 1M lines         
    ├─ Invalidation requests (first 1k)               Monthly cost depends on usage: $0.00 per paths            
    └─ US, Mexico, Canada                                                                                       
        ├─ Data transfer out to internet (first 10TB)  Monthly cost depends on usage: $0.085 per GB              
        ├─ Data transfer out to origin                 Monthly cost depends on usage: $0.02 per GB               
        ├─ HTTP requests                               Monthly cost depends on usage: $0.0075 per 10k requests   
        └─ HTTPS requests                              Monthly cost depends on usage: $0.01 per 10k requests     
    
    aws_s3_bucket.cloudfront_logs                                                                                 
    └─ Standard                                                                                                 
        ├─ Storage                                     Monthly cost depends on usage: $0.025 per GB              
        ├─ PUT, COPY, POST, LIST requests              Monthly cost depends on usage: $0.0047 per 1k requests    
        ├─ GET, SELECT, and all other requests         Monthly cost depends on usage: $0.00037 per 1k requests   
        ├─ Select data scanned                         Monthly cost depends on usage: $0.00225 per GB            
        └─ Select data returned                        Monthly cost depends on usage: $0.0008 per GB             
    
    OVERALL TOTAL                                                                                       $17.74 

    *Usage costs can be estimated by updating Infracost Cloud settings, see docs for other options.

    ──────────────────────────────────
    14 cloud resources were detected:
    ∙ 3 were estimated
    ∙ 10 were free
    ∙ 1 is not supported yet, rerun with --show-skipped to see details

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
    ┃ Project                                            ┃ Baseline cost ┃ Usage cost* ┃ Total cost ┃
    ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━━━━━━┫
    ┃ main                                               ┃           $18 ┃           - ┃        $18 ┃
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┻━━━━━━━━━━━━┛
    % 
    ```
- 読んでみると…
  - 動的コストはどういう評価がされるのか？と思っていましたが、まさかのper GBやper requestといった形で、これは自分で計算しないといけない…という表現でした。
  - 今回の例で言うと、固定で費用が発生するALBのみ試算され、$17.74が四捨五入されて$18という計算になっているようです。
- ちなみに、"1 is not supported yet, rerun with --show-skipped to see details"を試してみると
  - 以下のように、何がskipされたかわかるようになりました。
  - 今回は"aws_cloudfront_vpc_origin"がInfracostにまだ対応していなかったため、skipされたようです。
    
    <details><summary>"--show-skipped"を付けてみた例</summary>

    ```
    % infracost breakdown --path . --show-skipped
    INFO Autodetected 1 Terraform project across 1 root module
    INFO Found Terraform project main at directory .

    Project: main

    Name                                                      Monthly Qty  Unit                    Monthly Cost   

    aws_lb.private_alb                                                                                            
    ├─ Application load balancer                                    730  hours                         $17.74   
    └─ Load balancer capacity units                   Monthly cost depends on usage: $5.84 per LCU              

    aws_cloudfront_distribution.private_alb                                                                       
    ├─ Real-time log requests                         Monthly cost depends on usage: $0.01 per 1M lines         
    ├─ Invalidation requests (first 1k)               Monthly cost depends on usage: $0.00 per paths            
    └─ US, Mexico, Canada                                                                                       
        ├─ Data transfer out to internet (first 10TB)  Monthly cost depends on usage: $0.085 per GB              
        ├─ Data transfer out to origin                 Monthly cost depends on usage: $0.02 per GB               
        ├─ HTTP requests                               Monthly cost depends on usage: $0.0075 per 10k requests   
        └─ HTTPS requests                              Monthly cost depends on usage: $0.01 per 10k requests     

    aws_s3_bucket.cloudfront_logs                                                                                 
    └─ Standard                                                                                                 
        ├─ Storage                                     Monthly cost depends on usage: $0.025 per GB              
        ├─ PUT, COPY, POST, LIST requests              Monthly cost depends on usage: $0.0047 per 1k requests    
        ├─ GET, SELECT, and all other requests         Monthly cost depends on usage: $0.00037 per 1k requests   
        ├─ Select data scanned                         Monthly cost depends on usage: $0.00225 per GB            
        └─ Select data returned                        Monthly cost depends on usage: $0.0008 per GB             

    OVERALL TOTAL                                                                                       $17.74 

    *Usage costs can be estimated by updating Infracost Cloud settings, see docs for other options.

    ──────────────────────────────────
    14 cloud resources were detected:
    ∙ 3 were estimated
    ∙ 10 were free
    ∙ 1 is not supported yet, see https://infracost.io/requested-resources:
        ∙ 1 x aws_cloudfront_vpc_origin

    ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
    ┃ Project                                            ┃ Baseline cost ┃ Usage cost* ┃ Total cost ┃
    ┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━╋━━━━━━━━━━━━┫
    ┃ main                                               ┃           $18 ┃           - ┃        $18 ┃
    ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┻━━━━━━━━━━━━┛
    % 
    ```

    </details>

- 実際の費用と比較すると
  - AWS 料金見積りツールを用いて、ALBを作成すると$17.74と試算できました。
  - ALBに関しては正確ですね。
# VSCode拡張機能
- 私の環境ではなぜか試算してくれなかったので、導入手順だけご紹介しておきます。
## VScodeの拡張機能のマーケットプレイスにて以下をインストール
- インストールするもの
  ![VScode_install.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276335/7b747bb1-3084-455b-b656-244100806a03.png)
- インストールが成功すると、アクティビティバーにInfracostのアイコンが追加されます
  ![VScode_installed.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1276335/6261ba7d-ea20-4080-9eeb-aa7eddefa3f2.png)
## 初期設定
- Infracostアイコンをクリックすると、「Connect VSCode to Infracost」というボタンがあるので、クリックしてブラウザでログインすると利用可能になります。
  - [参考 初期セットアップ](https://dev.classmethod.jp/articles/vscode-extension-infracost-aws-cost-estimation-iac-template/)
# おわりに
- 想像よりもしっかりと試算しようとする姿勢に、使いやすそうという感触を持ちました。
- また、動的リソースの試算ができないという点に関しては正直残念に思いましたが、どうやら **infracost-usage.yml**というファイルを"--usage-file"オプションで読み込ませることで、従量課金のレベルを指定することができるようです。
  - 今回は試しませんでしたが、この機能を用いることで、より正確なコストをInfracostだけで試算することができるかもしれません。
  - [Usage costs](https://www.infracost.io/docs/features/usage_based_resources/)
- 一方、新機能…といっても2024年12月リリースの機能であるVPC Originについては対象外と言われてしまいました。
  - これは頻繁にサービス/機能がリリースされるクラウドにおいて、追従できないという弱点と言えそうです。
  - ただ、適当に算出してしまうのではなく、これは対象外！とはっきり言ってくれること自体は非常に好感が持てました。
- 今回は試しませんでしたが、GitのCICDに巻き込むことができるようで、例えばGitHub Actionsでapplyする手前のレビューで、承認するしないを決める要素としてコストをみることができるというのは非常に有益だと思います。
- また、以下Infracost Cloudのデモビデオを見たのですが、GUIの設定の中でGUIならではの機能が紹介されていました。
  - 注目したのは、 **指定した以上の追加費用** が発生するTerraformの設定ファイルをapplyしようとした場合は、メールやslackでの通知はもちろん、applyをブロックすることができるという非常に興味深い機能が紹介されていました。
  - AWSでは、リソースが作成されてしまった後、事前に指定していた予算がover **された後** に初めてメールやslackの通知を送ることができる、という後対応のため、プロアクティブに止めることができるというのはInfracostを使用する理由の一つになりそうです。
  - [Infracost Cloud デモビデオ](https://www.youtube.com/watch?v=BQeO137DDo8)
# 参考
- [Infracost GitHub](https://github.com/infracost/infracost)
- [infracost を使って インフラコストの見える化をする](https://qiita.com/mziyut/items/4140880e2b4315b37089)
- [VSCode拡張機能『Infracost』を使って TerraformテンプレートからAWS利用費を試算してみた](https://dev.classmethod.jp/articles/vscode-extension-infracost-aws-cost-estimation-iac-template/)