Comment automatiser l'estimation de coût de votre infrastructure Azure via votre CI/CD

En utilisant Infracost avec Terraform pour Azure, vous pouvez facilement estimer les coûts d'utilisation de vos ressources Azure avant de les déployer. 🛠

Infracost

Présentation rapide

Infracost est un outil open-source qui permet de calculer les coûts de déploiement et d'exploitation d'une infrastructure cloud en utilisant Terraform. Il est conçu pour être utilisé avec une variété de fournisseurs de cloud, y compris Microsoft Azure.

En utilisant Infracost avec Terraform pour Azure, vous pouvez facilement estimer les coûts d'utilisation de vos ressources Azure avant de les déployer.

L'outil prend en compte une variété de facteurs de coût, y compris les frais de stockage, de mise en réseau et de traitement. Il fournit des informations détaillées sur les coûts pour chaque ressource Terraform que vous déployez. Il prend en charge la facturation à l'utilisation (pay-as-you-go) ainsi que les options d'abonnement Azure.

Infracost peut être facilement intégré à votre pipeline de déploiement en tant qu'outil de validation des coûts avant de déployer des ressources.

Enfin, l'outil est facile à installer et à utiliser, avec une documentation complète disponible pour vous aider à commencer, voici un lien : Get started | Infracost

Quels sont les avantages d'Infracost ?

  • Infracost prend, aujourd'hui, en charge plus de 230 ressources.

  • Infracost analyse directement le code HCL, ce qui le rend ultra-rapide car un plan Terraform n'est pas nécessaire.

  • Infracost peut être utilisé pour modéliser des ressources basées sur l'utilisation et effectuer une analyse de simulation.

  • Infracost dispose d'un outil CLI qui peut être utilisé dans votre terminal ou intégré à vos flux de travail, quel que soit le contrôle de source et le système CI/CD utilisés.

  • Infracost peut être utilisé avec Terragrunt.

  • Infracost peut être utilisé avec les modules Terraform.

  • Infracost peut produire du JSON et être utilisé pour créer des politiques de coûts avec Open Policy Agent, Conftest et HashiCorp Sentinel.

Quelles données sont transmises à l'API ?

Aucun identifiant ou secret cloud n'est envoyé à l'API Cloud Pricing. Infracost n'apporte aucune modification à votre état Terraform ou à vos ressources cloud.

L'API Cloud Pricing a besoin des données pertinentes pour renvoyer un prix cloud unique. Le code Terraform HCL est analysé par l'interface de ligne de commande Infracost pour extraire les données pertinentes afin de faire des demandes à l'API Cloud Pricing.

Nous envoyons également le nombre de types de ressources Terraform à l'API Cloud Pricing pour nous permettre de mieux hiérarchiser la prise en charge des nouvelles ressources. Des contextes supplémentaires tels que le système d'exploitation, la version de Terraform, le type de système CI et la version d'Infracost sont également envoyés avec les événements de suivi des erreurs afin que nous puissions identifier et résoudre rapidement les problèmes.

Comment l'utiliser ?

Sous Windows via Chocolatey

choco install infracost
infracost --version

infracost auth login

# Pour récupérer une clé vous pouvez utiliser cette commande
infracost configure get api_key

# Par exemple: 
# git clone https://github.com/aloizeau/Clash-TerraformVsPulumi.git
cd ".\Clash-TerraformVsPulumi"

# Pour l'usage de variables: --terraform-var-file or --terraform-var
infracost breakdown --path .

Si vous souhaitez faire un diff entre deux modifications pour identifier l'évolution des coûts :

# Créer votre référence
infracost breakdown --path . --format json --out-file infracost-base.json

# Modifier votre infrastructure Terraform puis:
infracost diff --path . --compare-to infracost-base.json

Azure DevOps

# You can set up build triggers, as per the Quick Start guide to see comments on all pull
# requests to a specific branch.
# If you are seeing the build triggered twice you can try uncommenting the below line:
# trigger: none

variables:
  - name: TF_ROOT
    value: PATH/TO/TERRAFORM/CODE # Update this!
  # If you use private modules you'll need this env variable to use
  # the same ssh-agent socket value across all steps.
  - name: SSH_AUTH_SOCK
    value: /tmp/ssh_agent.sock
  # If you're using Terraform Cloud/Enterprise and have variables stored on there
  # you can specify the following to automatically retrieve the variables:
  # env:
  # - name: INFRACOST_TERRAFORM_CLOUD_TOKEN
  #   value: $(tfcToken)
  # - name: INFRACOST_TERRAFORM_CLOUD_HOST
  #   value: app.terraform.io # Change this if you're using Terraform Enterprise

jobs:
  - job: infracost
    displayName: Run Infracost
    pool:
      vmImage: ubuntu-latest

    steps:
      # If you use private modules, add a base 64 encoded secret
      # called gitSshKeyBase64 with your private key, so Infracost can access
      # private repositories (similar to how Terraform/Terragrunt does).
      # - bash: |
      #     ssh-agent -a $(SSH_AUTH_SOCK)
      #     mkdir -p ~/.ssh
      #     echo "$(echo $GIT_SSH_KEY_BASE_64 | base64 -d)" | tr -d '\r' | ssh-add -
      #     # Update this to github.com, gitlab.com, bitbucket.org, ssh.dev.azure.com or your source control server's domain
      #     ssh-keyscan ssh.dev.azure.com >> ~/.ssh/known_hosts
      #   displayName: Add GIT_SSH_KEY
      #   env:
      #     GIT_SSH_KEY_BASE_64: $(gitSshKeyBase64)

      # Install the Infracost CLI, see https://github.com/infracost/infracost-azure-devops#infracostsetup
      # for other inputs such as version, and pricingApiEndpoint (for self-hosted users).
      - task: InfracostSetup@1
        displayName: Setup Infracost
        inputs:
          apiKey: $(infracostApiKey)

      # Clone the base branch of the pull request (e.g. main/master) into a temp directory.
      - bash: |
          branch=$(System.PullRequest.TargetBranch)
          branch=${branch#refs/heads/}
          # Try adding the following to git clone if you're having issues cloning a private repo: --config http.extraheader="AUTHORIZATION: bearer $(System.AccessToken)"
          git clone $(Build.Repository.Uri) --branch=${branch} --single-branch /tmp/base
        displayName: Checkout base branch

      # Generate an Infracost cost estimate baseline from the comparison branch, so that Infracost can compare the cost difference.
      - bash: |
          infracost breakdown --path=/tmp/base/$(TF_ROOT) \
                              --format=json \
                              --out-file=/tmp/infracost-base.json
        displayName: Generate Infracost cost estimate baseline

      # Generate an Infracost diff and save it to a JSON file.
      - bash: |
          infracost diff --path=$(TF_ROOT) \
                         --format=json \
                         --compare-to=/tmp/infracost-base.json \
                         --out-file=/tmp/infracost.json
        displayName: Generate Infracost diff

      # Posts a comment to the PR using the 'update' behavior.
      # This creates a single comment and updates it. The "quietest" option.
      # The other valid behaviors are:
      #   delete-and-new - Delete previous comments and create a new one.
      #   new - Create a new cost estimate comment on every push.
      # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options.
      - bash: |
           infracost comment azure-repos --path=/tmp/infracost.json \
                                         --azure-access-token=$(System.AccessToken) \
                                         --pull-request=$(System.PullRequest.PullRequestId) \
                                         --repo-url=$(Build.Repository.Uri) \
                                         --behavior=update
        displayName: Post Infracost comment

GitHub Actions

# The GitHub Actions docs (https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#on)
# describe other options for 'on', 'pull_request' is a good default.
on: [pull_request]
env:
  # If you use private modules you'll need this env variable to use
  # the same ssh-agent socket value across all jobs & steps.
  SSH_AUTH_SOCK: /tmp/ssh_agent.sock
jobs:
  infracost:
    name: Infracost
    runs-on: ubuntu-latest
    permissions:
      contents: read
      # Required to post comments
      pull-requests: write

    env:
      TF_ROOT: examples/terraform-project/code
      # If you're using Terraform Cloud/Enterprise and have variables or private modules stored
      # on there, specify the following to automatically retrieve the variables:
      #   INFRACOST_TERRAFORM_CLOUD_TOKEN: ${{ secrets.TFC_TOKEN }}
      #   INFRACOST_TERRAFORM_CLOUD_HOST: app.terraform.io # Change this if you're using Terraform Enterprise

    steps:
      # If you use private modules, add an environment variable or secret
      # called GIT_SSH_KEY with your private key, so Infracost can access
      # private repositories (similar to how Terraform/Terragrunt does).
      # - name: add GIT_SSH_KEY
      #   run: |
      #     ssh-agent -a $SSH_AUTH_SOCK
      #     mkdir -p ~/.ssh
      #     echo "${{ secrets.GIT_SSH_KEY }}" | tr -d '\r' | ssh-add -
      #     ssh-keyscan github.com >> ~/.ssh/known_hosts

      - name: Setup Infracost
        uses: infracost/actions/setup@v2
        # See https://github.com/infracost/actions/tree/master/setup for other inputs
        # If you can't use this action, see Docker images in https://infracost.io/cicd
        with:
          api-key: ${{ secrets.INFRACOST_API_KEY }}

      # Checkout the base branch of the pull request (e.g. main/master).
      - name: Checkout base branch
        uses: actions/checkout@v3
        with:
          ref: '${{ github.event.pull_request.base.ref }}'

      # Generate Infracost JSON file as the baseline.
      - name: Generate Infracost cost estimate baseline
        run: |
          infracost breakdown --path=${TF_ROOT} \
                              --format=json \
                              --out-file=/tmp/infracost-base.json

      # Checkout the current PR branch so we can create a diff.
      - name: Checkout PR branch
        uses: actions/checkout@v3

      # Generate an Infracost diff and save it to a JSON file.
      - name: Generate Infracost diff
        run: |
          infracost diff --path=${TF_ROOT} \
                          --format=json \
                          --compare-to=/tmp/infracost-base.json \
                          --out-file=/tmp/infracost.json

      # Posts a comment to the PR using the 'update' behavior.
      # This creates a single comment and updates it. The "quietest" option.
      # The other valid behaviors are:
      #   delete-and-new - Delete previous comments and create a new one.
      #   hide-and-new - Minimize previous comments and create a new one.
      #   new - Create a new cost estimate comment on every push.
      # See https://www.infracost.io/docs/features/cli_commands/#comment-on-pull-requests for other options.
      - name: Post Infracost comment
        run: |
            infracost comment github --path=/tmp/infracost.json \
                                     --repo=$GITHUB_REPOSITORY \
                                     --github-token=${{github.token}} \
                                     --pull-request=${{github.event.pull_request.number}} \
                                     --behavior=update

Did you find this article valuable?

Support Antoine LOIZEAU by becoming a sponsor. Any amount is appreciated!