Ga naar inhoud

Cost insights setup

Deze pagina is voor het platformteam. Ze beschrijft hoe je de kostenweergaven (Insights) voor een omgeving inschakelt. Het is een referentieontwerp: resourcenamen, scopes en instellingen kunnen in jouw deployment afwijken.

Dataflow

flowchart LR
    be[Portal backend<br/>scheduled tasks] -->|creates exports| cm[Cost Management]
    cm -->|FOCUS Parquet, Snappy| st[(Storage account<br/>billingdata container)]
    cm -->|FOCUS Parquet, Snappy| dl[(Data Lake Gen2 accounts<br/>optional)]
    st --> adf[Data Factory<br/>daily pipeline, 04:00]
    adf --> sql[(Azure SQL<br/>tables and views)]
    sql --> be2[Portal backend<br/>queries at runtime]
    dl -.-> pg[(PostgreSQL<br/>azure_storage extension)]

De portal maakt en onderhoudt de exports zelf. Een Data Factory-pipeline draait dagelijks (trigger om 04:00 W. Europe-tijd), laadt de Parquet-bestanden in Azure SQL en ververst de views die de portal bevraagt.

Stappen

Stap Wat
1 Voeg de module cost_insights toe aan de omgevingsroot en koppel de outputs aan de module backstage
2 Voeg private connections toe voor de SQL server, als de provider vanuit zijn eigen netwerk deployt
3 Stel de instellingen voor kostenexports in, zodat de portal de exports configureert
4 Deploy in twee rondes en controleer

1. De module

Voeg voor elke omgevingsroot de module cost_insights toe. De inputs komen uit outputs van bestaande modules (spoke canvas, Key Vault, naming en de module backstage).

module "cost_insights" {
  source = "../../modules/cost_insights"

  location                   = module.canvas.location
  environment                = module.canvas.environment
  workload_short_name        = module.canvas.workload_short_name
  subnets                    = module.canvas.subnets
  log_analytics_workspace_id = module.canvas.log_analytics_workspace_id
  key_vault_id               = module.key_vault.id
  data_factory_name          = module.naming.data_factory.name

  # One Data Lake Gen2 account per key. The key is part of the resource name,
  # so keep it stable: changing it recreates the account.
  datalake_storage_accounts = {
    default = {}
  }

  backstage_user_assigned_identity = {
    resource_name = module.backstage.user_assigned_identity.resource_name
    client_id     = module.backstage.user_assigned_identity.client_id
  }
}

De module maakt een eigen resource group aan met:

Resource Doel
Azure Data Factory Laadt de exportbestanden in SQL. Heeft een alert bij fouten.
Storage account Ontvangt exports in de container billingdata en bewaart de auditlogs van Data Factory
Data Lake Gen2 storage account Eén per sleutel in datalake_storage_accounts, met eigen exports
Azure SQL server en database Verwerkte billingdata. De standaard-SKU is S0 en de maximale grootte 150 GB.
User-assigned managed identities Toegang met minimale rechten tussen Data Factory, storage en SQL
Key Vault keys Customer-managed encryptie voor storage en SQL

Een entry in datalake_storage_accounts kan readers opsommen: een map met Entra object-ID's als sleutel. Elke reader krijgt Storage Blob Data Reader op dat account, zodat een ander team, zoals een dataplatform, de geëxporteerde bestanden kan lezen. De map is standaard leeg, dus niemand buiten de portal kan de exports lezen totdat je een reader toevoegt.

De module gebruikt de Terraform provider mssql om databasegebruikers te beheren, dus de omgevingsroot heeft dit providerblok nodig. De runner die Terraform toepast, heeft daarom een netwerkpad naar de SQL server nodig.

provider "mssql" {
  azure_auth = {}
  hostname   = module.cost_insights.database_server
  port       = module.cost_insights.database_port
}

Geef de outputs door aan de module backstage: de resource-ID's van de storage accounts, de SQL server, de poort en de databasenaam (als app settings die met APP_CONFIG_costInsights_database_ beginnen) en het voorvoegsel van de exportnaam.

module "backstage" {
  # ... existing configuration ...

  cost_exports_storage_account_resource_id = module.cost_insights.storage_account_resource_id
  cost_exports_datalake_storage_accounts = {
    default = {
      resource_id             = module.cost_insights.storage_account_datalake_resource_ids["default"]
      role_assignment_enabled = true
    }
  }

  additional_app_settings = {
    APP_CONFIG_costInsights_database_server   = module.cost_insights.database_server
    APP_CONFIG_costInsights_database_port     = module.cost_insights.database_port
    APP_CONFIG_costInsights_database_database = module.cost_insights.database_name
    APP_CONFIG_cost_exports_exportNamePrefix  = "<prefix>_"
  }
}

Gebruik de module-inputs, niet de losse app settings

Het instellen van de storage-inputs van de module backstage maakt de role assignments op elk storage account aan. De gelijkwaardige app settings alleen doen dat niet.

De portal laadt de kostenbackend alleen als costInsights.database.server is ingesteld. Zonder die instelling zijn de kostenpagina's niet beschikbaar.

2. Private connections

Als de provider vanuit zijn eigen netwerk deployt, voeg dan een private connection voor de SQL server (subresource sqlServer) toe in de platformroot, keur die goed aan de kant van de klant en registreer de DNS-entry. Zie Een klant onboarden.

Kostenexports die de portal configureert

Met de bovenstaande instellingen draait de kostenbackend geplande taken die per subscription binnen de scope één FOCUS-schema Parquet-export (Snappy) aanmaken. Elke export dekt de data van de maand tot nu toe.

Taak Doel
configure-azure-cost-exports cost.exports: het storage account dat Data Factory leest
configure-azure-cost-exports-datalake-<prefix> Eén taak per entry in cost.dataLakeExports: een eigen Data Lake-account
Gedrag Detail
Batch Elke run behandelt een kleine batch subscriptions (standaard 25)
Venster Draait alleen in een venster buiten kantooruren en gaat over meerdere runs door tot alle subscriptions zijn geconfigureerd
Bestaande exports Worden herkend en blijven staan
Herverwerkingsinterval Standaard één dag
Dry run Een instelling dryRun logt wat zou veranderen zonder exports aan te maken
Prefix Het voorvoegsel van de exportnaam is standaard de naam van het storage account plus _
State Elk doel houdt zijn eigen state bij, zodat taken elkaar niet storen

Beperk de scope van de subscriptions als "elke subscription die de identity kan zien" te breed is:

cost:
  exports:
    includeManagementGroups: ['<management-group>']
  dataLakeExports:
    default:
      includeManagementGroups: ['<management-group>']

Vereisten aan de Azure-kant:

  • De managed identity van de portal heeft Cost Management Contributor nodig op de management group binnen de scope en leestoegang tot beide storage accounts (Prerequisites).
  • Microsoft.CostManagement moet zijn geregistreerd op elke subscription binnen de scope. Zo niet, dan logt de portal een waarschuwing en probeert het bij de volgende run opnieuw.

Directe ingestie in PostgreSQL

De portal kan de Parquet-bestanden uit de Data Lake-accounts importeren in zijn eigen PostgreSQL-database. De module postgresql bereidt de server voor: die heeft een system-assigned managed identity, de module backstage geeft die Storage Blob Data Reader op elk Data Lake-account en de extensie azure_storage is toegestaan en vooraf geladen. Pas de wijziging die de identity aanmaakt toe vóór de wijziging die de rol toewijst, omdat Terraform geen role assignment voor een onbekende principal kan plannen. Het wijzigen van shared_preload_libraries herstart de server.

De bron beschrijft dit pad als voorbereiding op een toekomstige fase waarin de portal kostendata zelf inleest en combineert met catalogdata.

Migreren vanaf een eerdere exportpipeline

Als een klant nog een eerdere, scriptgebaseerde exportpipeline draait:

  1. Deploy deze versie met hetzelfde voorvoegsel van de exportnaam dat de pipeline per omgeving gebruikt, zodat beide dezelfde export als doel hebben.
  2. Controleer de backendlogs op de taak configure-azure-cost-exports en bevestig in de Azure portal dat de exports bestaan.
  3. Schakel de oude pipeline uit en verwijder hem.

Deployen en controleren

  1. Deploy de eerste omgeving. De eerste run slaat het aanmaken van databasetabellen en privileges over, omdat de resource group van Data Factory nog niet bestaat, dus doe een tweede deployment.
  2. Keur de private endpoint connections goed en werk DNS bij.
  3. Deploy de volgende omgeving op dezelfde manier.
  4. Bevestig dat de portal de exports heeft geconfigureerd en dat er minstens één bestand in de container billingdata is aangekomen. Exports draaien meestal binnen 24 uur en de ingestie 's nachts, dus het kan één tot twee dagen duren voordat er data verschijnt.