aks

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 10, 2024 License: Apache-2.0 Imports: 17 Imported by: 0

README

AKS Module

This module is responsible for collecting pricing information for AKS clusters.

Pricing Map

Because Azure has not yet implemented the pricing API into it's SDK :shame:, this package uses the 3rd party Azure Retail Prices SDK to grab the prices.

This is based on Azure's pricing model, where different prices are determined by a combination of those factors.

Price Stratification

The PricingMap is built out with the following structure:

root -> {
  regionName -> {
    machinePriority -> {
      operatingSystem -> {
        skuName -> information
      }
    }
  }
}

That way, in order to uniquely identify a price, we will have to have the following attributes of any VM:

  • the region it is deployed into
  • it's priority (spot or on-demand)
  • the operating system it is running
  • it's SKU (e.g. E8-4as_v4)

Machine Map

In order to collect the VMs that are relevant for AKS, this package grabs a list of relevant machines in the following way:

  • A list of AKS clusters for the subscription are obtained
  • Each VMSS (Virtual Machine Scale Set) that creates worker nodes is collected for the resource groups that Azure uses to provision VMs
  • Each VM for the VMSS is collected
  • VMSS and their metadata (namely their pricing SKU) is stored in a map with the following structure:
root -> {
  vmUniqueName -> information
}

The information contained on the VM Information is enough to uniquely identify both the machine itself and the price that accompanies it.

Future Work

  • (Pricing Map) - implement background job to populate pricing map every 24 hours
  • (Pricing Map) - implement retry mechanism to pricing map, crash program if it doesn't populate after 5 tries
  • Prometheus metrics - CPU and Memory

Documentation

Index

Constants

View Source
const (
	AzurePriceSearchFilter = `serviceName eq 'Virtual Machines' and priceType eq 'Consumption'`
	AzureMeterRegion       = `'primary'`
	DefaultInstanceFamily  = "General purpose"

	MiBsToGiB = 1024
)
View Source
const (
	AZ_API_VERSION string = "2023-01-01-preview" // using latest API Version https://learn.microsoft.com/en-us/rest/api/cost-management/retail-prices/azure-retail-prices

)
View Source
const (
	ConcurrentGoroutineLimit = 10
)

Variables

View Source
var (
	ErrClientCreationFailure         = errors.New("failed to create client")
	ErrPageAdvanceFailure            = errors.New("failed to advance page")
	ErrPriceStorePopulationFailure   = errors.New("failed to populate price store")
	ErrMachineStorePopulationFailure = errors.New("failed to populate machine store")
	ErrVmPriceRetrievalFailure       = errors.New("failed to retrieve price info for VM")
)

Errors

View Source
var (
	InstanceCPUHourlyCostDesc = prometheus.NewDesc(
		prometheus.BuildFQName(cloudcost_exporter.MetricPrefix, subsystem, "instance_cpu_usd_per_core_hour"),
		"The cpu cost a compute instance in USD/(core*h)",
		[]string{"instance", "region", "machine_type", "family", "cluster_name", "price_tier", "operating_system"},
		nil,
	)
	InstanceMemoryHourlyCostDesc = prometheus.NewDesc(
		prometheus.BuildFQName(cloudcost_exporter.MetricPrefix, subsystem, "instance_memory_usd_per_gib_hour"),
		"The memory cost of a compute instance in USD/(GiB*h)",
		[]string{"instance", "region", "machine_type", "family", "cluster_name", "price_tier", "operating_system"},
		nil,
	)
	InstanceTotalHourlyCostDesc = prometheus.NewDesc(
		prometheus.BuildFQName(cloudcost_exporter.MetricPrefix, subsystem, "instance_total_usd_per_hour"),
		"The total cost of an compute instance in USD/h",
		[]string{"instance", "region", "machine_type", "family", "cluster_name", "price_tier", "operating_system"},
		nil,
	)
)

Prometheus Metrics

View Source
var (
	ErrMachineNotFound       = errors.New("machine not found in map")
	ErrMachineFamilyNotFound = errors.New("machine family not able to be determined by SKU")
	ErrMachineTierNotFound   = errors.New("machine tier not found in VMSS object")

	// As annoying as this is, I am unable to find an API call for this
	// and performance of a map lookup will be quite faster
	// than maintaining lists of each family
	//
	// Based on this logic https://learn.microsoft.com/en-us/azure/virtual-machines/vm-naming-conventions
	MachineFamilyTypeMap map[byte]string = map[byte]string{
		'A': "General purpose",
		'B': "General purpose",
		'D': "General purpose",
		'F': "Compute optimized",
		'E': "Memory optimized",
		'M': "Memory optimized",
		'L': "Storage optimized",
		'N': "GPU accelerated",
		'H': "High performance compute",
	}
)
View Source
var (
	ErrPriceInformationNotFound = errors.New("price information not found in map")
)

Functions

This section is empty.

Types

type Collector

type Collector struct {
	PriceStore *PriceStore

	MachineStore *MachineStore
	// contains filtered or unexported fields
}

Collector is a prometheus collector that collects metrics from AKS clusters.

func New

func New(ctx context.Context, cfg *Config) (*Collector, error)

func (*Collector) CheckReadiness added in v0.3.0

func (c *Collector) CheckReadiness() bool

func (*Collector) Collect

func (c *Collector) Collect(ch chan<- prometheus.Metric) error

Collect satisfies the provider.Collector interface.

func (*Collector) CollectMetrics

func (c *Collector) CollectMetrics(_ chan<- prometheus.Metric) float64

CollectMetrics is a no-op function that satisfies the provider.Collector interface. Deprecated: CollectMetrics is deprecated and will be removed in a future release.

func (*Collector) Describe

func (c *Collector) Describe(ch chan<- *prometheus.Desc) error

func (*Collector) Name

func (c *Collector) Name() string

func (*Collector) Register

func (c *Collector) Register(_ provider.Registry) error

type Config

type Config struct {
	Logger      *slog.Logger
	Credentials *azidentity.DefaultAzureCredential

	SubscriptionId string
}

type MachineOperatingSystem added in v0.1.6

type MachineOperatingSystem int
const (
	Linux MachineOperatingSystem = iota
	Windows
)

func (MachineOperatingSystem) String added in v0.1.6

func (mo MachineOperatingSystem) String() string

type MachinePrices added in v0.3.0

type MachinePrices struct {
	PricePerCore float64
	PricePerGiB  float64
}

type MachinePriority added in v0.1.6

type MachinePriority int
const (
	OnDemand MachinePriority = iota
	Spot
)

func (MachinePriority) String added in v0.1.6

func (mp MachinePriority) String() string

type MachineSku added in v0.3.0

type MachineSku struct {
	RetailPrice float64

	MachinePricesBreakdown *MachinePrices
}

type MachineStore added in v0.2.2

type MachineStore struct {
	MachineSizeMap map[string]map[string]*armcompute.VirtualMachineSize

	MachineMap map[string]*VirtualMachineInfo
	// contains filtered or unexported fields
}

func NewMachineStore added in v0.2.2

func NewMachineStore(parentCtx context.Context, parentLogger *slog.Logger, subscriptionId string, credentials *azidentity.DefaultAzureCredential) (*MachineStore, error)

func (*MachineStore) CheckReadiness added in v0.3.0

func (m *MachineStore) CheckReadiness() bool

func (*MachineStore) PopulateMachineStore added in v0.2.2

func (m *MachineStore) PopulateMachineStore(ctx context.Context) error

type PriceByOperatingSystem added in v0.1.6

type PriceByOperatingSystem map[MachineOperatingSystem]PriceBySku

type PriceByPriority added in v0.1.6

type PriceByPriority map[MachinePriority]PriceByOperatingSystem

type PriceBySku added in v0.1.6

type PriceBySku map[string]*MachineSku

type PriceStore added in v0.1.6

type PriceStore struct {
	RegionMap map[string]PriceByPriority
	// contains filtered or unexported fields
}

func NewPricingStore added in v0.1.6

func NewPricingStore(parentContext context.Context, parentLogger *slog.Logger, subId string) (*PriceStore, error)

func (*PriceStore) CheckReadiness added in v0.3.0

func (p *PriceStore) CheckReadiness() bool

func (*PriceStore) PopulatePriceStore added in v0.1.6

func (p *PriceStore) PopulatePriceStore(ctx context.Context) error

type VirtualMachineInfo added in v0.2.2

type VirtualMachineInfo struct {
	Name            string
	Id              string
	Region          string
	OwningVMSS      string
	OwningCluster   string
	MachineTypeSku  string
	MachineFamily   string
	OperatingSystem MachineOperatingSystem
	Priority        MachinePriority

	NumOfCores     float64
	MemoryInMiB    float64 // Note, the Azure Docs say MiB, the golang docs say MB, we're going with the Azure Docs :nervous:
	OsDiskSizeInMB float64
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL