Skip to main content

OpenCost on Microsoft Azure

Use this guide to deploy OpenCost components for Kubernetes Billing exports to Azure Blob Storage.

Prerequisites

Before you begin, make sure you have:

  • Infrastructure & permissions
    • An AKS cluster
    • Cluster administrator access
  • Required cloud permissions
    • Contributor role at the subscription or resource group level
    • User Access Administrator role (required to manage service principals)
  • Required tools
    • Azure CLI (az)
    • kubectl
    • Helm (v3.x or later)

Set Up a Service Principal

Create a Service Principal

  1. In the Azure portal, navigate to Microsoft Entra ID.
  2. Under Manage, select App registrations and click + New registration.
  3. Set:
    • Name: opencost-sp
    • Supported account types: Single tenant
  4. After creating the application, note:
    • Application (client) ID
    • Directory (tenant) ID

Create a Client Secret

  1. Open the newly created application.
  2. Under Manage, select Certificates & secrets and click + New client secret.
  3. Set a description and select an expiry period.
  4. Copy and save the generated secret value. This value cannot be retrieved later.

Assign Permissions

  1. Navigate to the subscription that contains the AKS cluster.
  2. Open Access control (IAM).
  3. Click + AddAdd role assignment.
  4. Assign the following roles to the service principal:
    • Reader (required for cost metrics).
    • Storage Blob Data Contributor (required for Parquet exports).

Set Up the Storage Account

  1. In the Azure portal, navigate to Storage accounts.
  2. Click Create and configure:
    • Name: for example, opencost-reports (must be globally unique, only lowercase letters and numbers).
    • Performance: leave the default value.
    • Redundancy: leave the default value.
  3. Create the storage account.
note

Use the storage account name consistently in the later steps.

Configure Access for Cloudaware

  1. Open the newly created storage account.
  2. Go to Access control (IAM).
  3. Assign the Storage Blob Data Reader role to the service principal used for Cloudaware access:
    • Assign access to: User, group, or service principal.
    • Members: click + Select members and select the Cloudaware application (for example, cloudaware-api-access).

Create a Container for Exports

  1. Navigate to Containers and click + Container.
  2. Set:
    • Name: for example, opencost-exports.
    • Public access level: Private.

Connect to the AKS Cluster

  1. In the Azure portal, go to Kubernetes services.
  2. Select the target cluster.
  3. Click Connect and copy the credentials command.
  4. Run the az aks get-credentials command locally to merge cluster credentials into your kubeconfig.

Deploy Prometheus

tip

If you use an external Prometheus instance, skip this step and review the Configuration notes (1) for external Prometheus below.

  1. Add the Prometheus Helm repository:

    helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
  2. Create the Prometheus namespace:

    kubectl create namespace prometheus-system
  3. Install Prometheus:

    helm install prometheus prometheus-community/prometheus \
    --namespace prometheus-system \
    --set prometheus-pushgateway.enabled=false \
    --set alertmanager.enabled=false

Deploy OpenCost

  1. Add the OpenCost Helm repository:

    helm repo add opencost https://opencost.github.io/opencost-helm-chart
  2. Create the OpenCost namespace:

    kubectl create namespace opencost
  3. Create a Kubernetes secret for the service principal credentials. Replace {YOUR_CLIENT_SECRET} with the value created in Step 1:

    kubectl create secret generic azure-secret \
    --from-literal=password={YOUR_CLIENT_SECRET} \
    --namespace opencost
  4. Install OpenCost:

    helm --namespace opencost upgrade --install opencost opencost/opencost -f - <<EOF
    serviceAccount:
    create: true
    name: opencost-sa
    opencost:
    prometheus:
    namespaceName: prometheus-system
    podAnnotations:
    prometheus.io/path: /metrics
    prometheus.io/port: "9003"
    prometheus.io/scrape: "true"
    EOF
tip

The podAnnotations ensure that Prometheus scrapes metrics from the OpenCost pods, enabling label‑based cost attribution in reports.

Configuration Notes

Configure the following Helm values depending on your setup:

  1. If your cluster already has an external Prometheus, configure OpenCost to use the existing Prometheus instance. Replace {YOUR_PROMETHEUS_URL} with the correct endpoint:

    opencost:
    prometheus:
    external:
    enabled: true
    url: {YOUR_PROMETHEUS_URL}
  2. If your cluster uses prometheus-operator, enable ServiceMonitor; otherwise, OpenCost metrics will not be scraped automatically:

    opencost:
    metrics:
    serviceMonitor:
    enabled: true

Deploy the Parquet Exporter

Install the OpenCost Parquet exporter.

  • To store reports in subfolders or use a naming prefix, use the command below, replacing {YOUR_CLUSTER_PREFIX}, {YOUR_AKS_CLUSTER_ID}, {YOUR_OPENCOST_STORAGE}, {YOUR_OPENCOST_PARQUET_AZURE_CONTAINER__NAME}, {YOUR_TENANT_ID}, and {YOUR_CLIENT_ID} with the appropriate values:

    helm install parquet-exporter opencost/opencost-parquet-exporter \
    --namespace opencost \
    --set schedule="0 */12 * * *" \
    --set existingServiceAccount=opencost-sa \
    --values - <<EOF
    resources:
    limits:
    cpu: "1"
    memory: 1Gi
    requests:
    cpu: 100m
    memory: 100Mi
    securityContext: null
    env:
    - name: OPENCOST_PARQUET_SVC_HOSTNAME
    value: "opencost.opencost.svc.cluster.local"
    - name: OPENCOST_PARQUET_STORAGE_BACKEND
    value: "azure"
    - name: OPENCOST_PARQUET_FILE_KEY_PREFIX
    value: "{YOUR_CLUSTER_PREFIX}/{YOUR_AKS_CLUSTER_ID}/"
    - name: OPENCOST_PARQUET_JSON_SEPARATOR
    value: "_"
    - name: OPENCOST_PARQUET_AZURE_STORAGE_ACCOUNT_NAME
    value: "{YOUR_OPENCOST_STORAGE}"
    - name: OPENCOST_PARQUET_AZURE_CONTAINER_NAME
    value: "{YOUR_OPENCOST_PARQUET_AZURE_CONTAINER__NAME}"
    - name: OPENCOST_PARQUET_AZURE_TENANT
    value: "{YOUR_TENANT_ID}"
    - name: OPENCOST_PARQUET_AZURE_APPLICATION_ID
    value: "{YOUR_CLIENT_ID}"
    - name: OPENCOST_PARQUET_AZURE_APPLICATION_SECRET
    valueFrom:
    secretKeyRef:
    name: azure-secret
    key: password
    EOF
    note

    Use the AKS cluster ID without the leading forward slash (/) in OPENCOST_PARQUET_FILE_KEY_PREFIX. Example:

    - name: OPENCOST_PARQUET_FILE_KEY_PREFIX
    value: prodk8s/subscriptions/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/resourceGroups/opencost/providers/Microsoft.ContainerService/managedClusters/opencost-aks/
  • To store reports in the root folder, use the command below, replacing {YOUR_AKS_CLUSTER_ID}, {YOUR_OPENCOST_STORAGE}, {YOUR_TENANT_ID}, and {YOUR_CLIENT_ID}:

    helm install parquet-exporter opencost/opencost-parquet-exporter \
    --namespace opencost \
    --set schedule="0 */12 * * *" \
    --set existingServiceAccount=opencost-sa \
    --values - <<EOF
    resources:
    limits:
    cpu: "1"
    memory: 1Gi
    requests:
    cpu: 100m
    memory: 100Mi
    securityContext: null
    env:
    - name: OPENCOST_PARQUET_SVC_HOSTNAME
    value: "opencost.opencost.svc.cluster.local"
    - name: OPENCOST_PARQUET_STORAGE_BACKEND
    value: "azure"
    - name: OPENCOST_PARQUET_FILE_KEY_PREFIX
    value: "{YOUR_AKS_CLUSTER_ID}/"
    - name: OPENCOST_PARQUET_JSON_SEPARATOR
    value: "_"
    - name: OPENCOST_PARQUET_AZURE_STORAGE_ACCOUNT_NAME
    value: "{YOUR_OPENCOST_STORAGE}"
    - name: OPENCOST_PARQUET_AZURE_CONTAINER_NAME
    value: "{YOUR_OPENCOST_PARQUET_AZURE_CONTAINER__NAME}"
    - name: OPENCOST_PARQUET_AZURE_TENANT
    value: "{YOUR_TENANT_ID}"
    - name: OPENCOST_PARQUET_AZURE_APPLICATION_ID
    value: "{YOUR_CLIENT_ID}"
    - name: OPENCOST_PARQUET_AZURE_APPLICATION_SECRET
    valueFrom:
    secretKeyRef:
    name: azure-secret
    key: password
    EOF
    note

    Use the AKS cluster ID without the leading forward slash (/) in OPENCOST_PARQUET_FILE_KEY_PREFIX.

    Example:

    - name: OPENCOST_PARQUET_FILE_KEY_PREFIX
    value: subscriptions/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee/resourceGroups/opencost/providers/Microsoft.ContainerService/managedClusters/opencost-aks/
warning

For multi‑cluster environments, deploy the Parquet exporter separately on each cluster.

Verify the Deployment

  1. Check that all pods are running:

    kubectl get pods -n prometheus-system
    kubectl get pods -n opencost
  2. Access the OpenCost UI:

    kubectl port-forward -n opencost service/opencost 9090:9090

Then open http://localhost:9090 in your browser.

note

The first Parquet export may take up to 24 hours. To verify the export, check your Azure Storage container for newly created files.

Next Steps

Return to the parent guide Kubernetes Billing (OpenCost) to proceed with the Kubernetes Billing setup in Cloudaware.