infracost: Infracost uses Premium disk for AKS even though it's not available for given VM family

Hi,

It looks like Infracost makes invalid assumptions regarding OS disks provisioned for AKS.

Infracost version: v0.10.19

Steps to reproduce:

terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "=3.0.0"
    }
  }
}

# Configure the Microsoft Azure Provider
provider "azurerm" {
  features {}
  skip_provider_registration = true
}

# Create a resource group
resource "azurerm_resource_group" "example" {
  name     = "example-resources"
  location = "West Europe"
}

resource "azurerm_kubernetes_cluster" "example" {
  name                = "example-aks1"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  dns_prefix          = "exampleaks1"

  default_node_pool {
    name       = "default"
    node_count = 1
    vm_size    = "Standard_D2_v2"
  }

  identity {
    type = "SystemAssigned"
  }

  tags = {
    Environment = "Production"
  }
}

Run infracost breakdown --path .

Result: image

Expected result

Standard_D2_v2 in Azure doesn’t support Premium SSD disks. Estimation value should be ~108.88 USD

EDIT: I checked that VM size from both Terraform and Azure Portal and it seems, that it actually creates a Standard HDD disk.

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 16 (13 by maintainers)

Commits related to this issue

Most upvoted comments

@kamil-mrzyglod this is now released in v0.10.25. Thanks @varshneydevansh for your contribution!

@varshneydevansh I checked the Azure APIs and these are the subfamily of instances that default to the premium storage:

[
  'DS1',    'DS11',   'DS11-1', 'DS12',
  'DS12-1', 'DS12-2', 'DS13',   'DS13-2',
  'DS13-4', 'DS14',   'DS14-4', 'DS14-8',
  'DS15',   'DS2',    'DS3',    'DS4',
  'DS5',    'GS1',    'GS2',    'GS3',
  'GS4',    'GS4-4',  'GS4-8',  'GS5',
  'GS5-16', 'GS5-8',  'M128',   'M128m',
  'M64',    'M64m'
]

So I think we can just add a check for DS, GS, and M prefixes for now, and if we find this changes more in the future we can introduce something like @kamil-mrzyglod suggested. Maybe a function like this would work?

func aksGetStorageType(instanceType string) string {
	parts := strings.Split(instanceType, "_")

	subfamily := ""
	if len(parts) > 1 {
		subfamily = parts[1]
	}
	
	// Check if the subfamily is a known premium type
	premiumPrefixes := []string{"ds", "gs", "m"}
	for _, p := premiumPrefixes {
		if strings.HasPrefix(strings.ToLower(subfamily), p) {
			return "Premium"
		}
	}

	// Otherwise check if it contains an s as an 'Additive Feature'
	// as per https://learn.microsoft.com/en-us/azure/virtual-machines/vm-naming-conventions
	re := regexp.MustCompile(`\d+[A-Za-z]*(s)`)
	matches := re.FindStringSubmatch(subfamily)

	if len(matches) > 0 {
		return "Premium"
	}
	
	return "Standard"
}

Let me know what you think.

I also wanted to know about this storageReplicationType := “LRS” is this always going to be LRS? Because, In the Azure documentation I read about other replication like GRS, RA-GRS etc.

From what I can tell AKS nodes defined in Terraform always use LRS type storage.

Regarding the PR, I did, make a new branch in my infracost clone repo where I commit the changes for this issue. Should I create a different PR for that? As this file is being already added to my previous https://github.com/infracost/infracost/pull/2534.

@varshneydevansh thank you! Yes please create a separate PR 🙏.

I’m doing a little more investigation into your other questions and will get back to you in the next day when I’ve had a chance to look.

Does this have any impact on the price calculation for the premium disk in the AKS?

I don’t think we have to worry about this just now.

and the regex could be somewhat like this -

Maybe something like this could work and be consistent with the naming conventions here. This makes sure we only search for the s in the part of the instance type that includes the “Additive features”.

	diskType := "Standard"

	parts := strings.Split(instanceType, "_")

	part := ""
	if len(parts) > 0 {
		part = parts[1]
	}

	re := regexp.MustCompile(`\d+[A-Za-z]*(s)`)
	matches := re.FindStringSubmatch(part)

	if len(matches) > 0 {
		diskType = "Premium"
	}

If I can suggest a solution (or something worth considering) - in my own tool for cost calculation, when challenged with that topic, I used VM capabilities API (see https://github.com/TheCloudTheory/arm-estimator/blob/main/arm-estimator/ResourceManager/CapabilitiesCache.cs). It’s much safer solution as you can ask Azure Resource Manager to tell you which VM families support Premium disks.

Thanks for the research @varshneydevansh! Looking at https://learn.microsoft.com/en-us/azure/virtual-machines/ I agree that the s means it uses a premium disk.

I don’t think if strings.Contains(instanceType, "s") { is quite safe enough though since the instance type might contain another lowercase s. I suggest parsing the instance type using a regex to extract the “Additive Features” part of the instance type and see if it contains an s.

@varshneydevansh, yes this issue is still pending.

We will probably need to update somewhere here to use different disk types depending on the instance type.