Orbtrace

Deploying on Azure (AKS)

Run Orbtrace on Azure Kubernetes Service the recommended way — Azure Database for PostgreSQL with the pgvector allowlist, a tunable Premium SSD v2 StorageClass, Doris via the operator or Azure VMs, AGIC ingress, and the Azure-specific gotchas.

This is the Kubernetes (Helm) path on Azure Kubernetes Service (AKS). The generic Helm mechanics — pull secret, my-values.yaml, helm install — are on Install with Helm; this page is the Azure-specific decisions, and it follows the same recommendation: run the stateful stores as managed services, let Helm deploy only the stateless app.

In AKS — Helm deploys

Orbtrace serverThe stateless app · replicas + HPA · AGIC ingress
ValkeyCache · bundled in-cluster (fine in prod)

Azure-managed / VMs — you run these

Apache DorisTelemetry store · operator on AKS, or Azure VMs
Postgres + pgvectorSettings + RCA vectors · Postgres Flexible Server
OTel CollectorTelemetry ingest · a container / your pipeline
Your appsOTLPOTel CollectorwriteApache DorisreadOrbtrace (in cluster)

Apps send OTLP to your Collector, which writes to Doris. The stateless Orbtrace app in AKS reads telemetry back from Doris and keeps settings + cache in Azure Postgres + the bundled Valkey. Only the app and the ephemeral cache live in AKS; the data you can't lose (Flexible Server, Doris) stays on managed services / VMs outside the pod lifecycle.

What runs where on Azure

ComponentAzure choiceNotes
Orbtrace appAKS (this chart)Stateless — replicas + HPA, spread across zones
Postgres + pgvectorAzure Database for PostgreSQL — Flexible ServerZone-redundant HA in prod; vector must be on the extension allowlist (step 3)
Valkey (cache)bundled in-clusterEphemeral — leave it in AKS. Azure Cache for Redis only if you want it managed
Apache Dorisdoris-operator on AKS, or Azure VMsMemory-heavy, IOPS-heavy — give it its own node pool / VMs
Collectora container / your existing pipelineNever in the chart — see Integration patterns
Ingress + TLSApplication Gateway (AGIC) or app-routing (managed nginx)cert-manager secret, or an App Gateway / Key Vault cert
Block storagePremium SSD v2 (disk.csi.azure.com)Tune IOPS/throughput — Doris BE is IOPS-bound (step 2)

Size the cluster from your workload first with the Capacity planning calculator — the node-pool shapes below follow from its Doris FE/BE counts and per-node CPU/memory/disk.

  1. 1

    Create the AKS cluster — two node pools

    Give Doris BE its own node pool — memory-optimized (E-series), with pinned tunable disk. Spread the system/app pool across zones:

    az aks create -g <rg> -n orbtrace \
      --node-vm-size Standard_D4s_v5 --node-count 3 --zones 1 2 3 \
      --network-plugin azure --generate-ssh-keys
    az aks nodepool add -g <rg> --cluster-name orbtrace -n dorisbe \
      --node-vm-size Standard_E8s_v5 --node-count 3 --zones 1 \
      --labels orbtrace.io/doris-be=true
    az aks get-credentials -g <rg> -n orbtrace

    Azure managed disks are zone-locked — pin Doris BE to one zone

    A managed disk lives in one availability zone; a pod bound to that PVC can only run on a node in the same zone. If a Doris BE pod is rescheduled to another zone it cannot mount its data and stays Pending. Keep the BE node pool in one zone (--zones 1 above), or run one BE pool per zone with the operator's anti-affinity. The stateless app has no such constraint.

  2. 2

    A tunable Premium SSD v2 StorageClass

    AKS ships the Azure Disk CSI driver already — no IAM/identity wiring needed for volumes. But the default managed-csi-premium (Premium SSD) ties IOPS to disk size, which starves Doris BE compaction. Use Premium SSD v2, whose IOPS and throughput are set independently:

    premium2-orbtrace.yaml
    apiVersion: storage.k8s.io/v1
    kind: StorageClass
    metadata:
      name: premium2-orbtrace
      annotations: { storageclass.kubernetes.io/is-default-class: "true" }
    provisioner: disk.csi.azure.com
    parameters:
      skuName: PremiumV2_LRS
      DiskIOPSReadWrite: "6000"     # independent of size — set for BE compaction
      DiskMBpsReadWrite: "250"      # MB/s
    volumeBindingMode: WaitForFirstConsumer   # binds the disk in the pod's zone
    allowVolumeExpansion: true

    Applysave as premium2-orbtrace.yaml, then runkubectl apply -f premium2-orbtrace.yaml

    (Premium SSD v2 must be available in your region/zone; if not, fall back to managed-csi-premium and size disks large enough that their baseline IOPS suffices.)

  3. 3

    Provide Postgres — Flexible Server + the pgvector allowlist

    Create an Azure Database for PostgreSQL — Flexible Server (v16+) with private access (VNet integration) into the AKS VNet (or a peered one). Azure gates extensions behind a per-server allowlist, so add vector to azure.extensions first — this is the step people miss:

    az postgres flexible-server parameter set -g <rg> -s <server-name> \
      --name azure.extensions --value vector

    Then, connected to the server, create the database and enable the extension:

    CREATE DATABASE orbtrace;
    CREATE USER orbtrace WITH PASSWORD 'a-strong-password';
    GRANT ALL PRIVILEGES ON DATABASE orbtrace TO orbtrace;
    \c orbtrace
    CREATE EXTENSION IF NOT EXISTS vector;

    The orbtrace names are a convention; set postgres.database/postgres.username to match in step 6. (Cache: leave Valkey bundled — it's ephemeral; use Azure Cache for Redis only if you want it managed.)

  4. 4

    Set the Doris node kernel prerequisite

    Doris BE needs vm.max_map_count ≥ 2000000 on its nodes. Apply it with a small privileged DaemonSet targeted at the BE node pool from step 1:

    doris-sysctl.yaml
    apiVersion: apps/v1
    kind: DaemonSet
    metadata: { name: doris-sysctl, namespace: kube-system }
    spec:
      selector: { matchLabels: { app: doris-sysctl } }
      template:
        metadata: { labels: { app: doris-sysctl } }
        spec:
          nodeSelector: { "orbtrace.io/doris-be": "true" }
          initContainers:
            - name: sysctl
              image: busybox:1.37
              securityContext: { privileged: true }
              command: ["sh", "-c", "sysctl -w vm.max_map_count=2000000"]
          containers:
            - name: pause
              image: registry.k8s.io/pause:3.9

    Applysave as doris-sysctl.yaml, then runkubectl apply -f doris-sysctl.yaml

  5. 5

    Stand up Doris

    Run Doris with the doris-operator in the cluster — its DorisCluster uses the premium2-orbtrace StorageClass and a nodeSelector for the BE pool — or on Azure VMs and point the chart at it. Full walkthrough is on Setting up Doris. Note the FE Service address for doris.host.

  6. 6

    Install Orbtrace with Helm

    Follow Install with Helm — pull secret and helm install are identical on Azure. In your my-values.yaml:

    my-values.yaml
    global:
      imagePullSecrets: [{ name: ghcr }]     # the secret from the Helm page
    postgres:
      mode: external
      host: <server-name>.postgres.database.azure.com   # Flexible Server endpoint
      port: 5432
      database: orbtrace
      username: orbtrace
      password: <your-postgres-password>     # or existingSecret — see the Helm page
    doris:
      host: <your-doris-fe-host>             # FE Service / VM address from step 5
  7. 7

    Expose it — AGIC (or app-routing) ingress

    Enable the Application Gateway Ingress Controller add-on (az aks enable-addons -a ingress-appgw …) — or the application-routing managed-nginx add-on (az aks approuting enable). Then drive it from the chart's ingress annotations (chart ≥ 2.0.13). AGIC example, terminating TLS with a cert-manager Kubernetes secret and health-checking Orbtrace's readiness path:

    my-values.yaml (add)
    orbtrace:
      ingress:
        enabled: true
        className: azure-application-gateway
        annotations:
          appgw.ingress.kubernetes.io/ssl-redirect: "true"
          appgw.ingress.kubernetes.io/health-probe-path: /actuator/health/readiness
        hosts:
          - host: orbtrace.example.com
            paths: [{ path: /, pathType: Prefix }]
        tls:
          - secretName: orbtrace-tls          # a cert-manager-issued cert, or your own
            hosts: [orbtrace.example.com]

    For an App Gateway– or Key Vault–managed certificate instead of a K8s secret, drop the tls block and add appgw.ingress.kubernetes.io/appgw-ssl-certificate: <cert-name>. With the app-routing managed-nginx add-on instead, set className: webapprouting.kubernetes.azure.com (the IngressClass the add-on registers — not nginx) and the standard nginx.ingress.kubernetes.io/* annotations; it integrates DNS and TLS through Azure DNS + Key Vault. Point DNS at the ingress address, then upgrade the release.

    On a chart older than 2.0.13 the ingress.annotations key isn't rendered — upgrade, or apply a hand-written Ingress.

  8. 8

    Verify

    kubectl -n orbtrace get pods
    kubectl -n orbtrace logs deploy/orbtrace-app -c orbtrace | grep doris-migration
    # ready when you see: [doris-migration] complete
    kubectl -n orbtrace get ingress    # ADDRESS shows the App Gateway public IP once provisioned
    curl -fsSI https://orbtrace.example.com | head -1   # HTTP/2 200

    Then continue to First login.

Production hardening on Azure

  • Flexible Server: zone-redundant HA, automated backups + PITR, and private access (no public endpoint). Keep the password in Key Vault and mount it via the Secrets Store CSI driver, referenced through postgres.existingSecret.
  • Doris backups: enable the chart's backup.* CronJobs to push Postgres dumps and Doris snapshots to Blob Storage (S3-compatible via its S3 endpoint); the reference DorisCluster supports a cold tier — see Capacity planning.
  • Nodes: system/app pool across ≥ 3 zones; enable the Cluster Autoscaler. The chart ships PodDisruptionBudgets.
  • Identity: use Workload Identity for pods that call Azure APIs; scope NSGs so only the AKS subnet reaches Postgres on 5432.

Common Azure first-install snags

  • CREATE EXTENSION vector failsvector isn't on azure.extensions yet (step 3). Set the parameter, then retry.
  • App un-Ready, STORAGE_UNAVAILABLE → Flexible Server isn't reachable (VNet not peered / firewall rule missing) or doris.host is wrong. See Troubleshooting.
  • A Doris BE pod stuck Pending after a reschedule → it landed in a different zone from its managed disk. Pin the BE node pool to one zone (step 1).
  • Ingress has no address → the AGIC add-on / App Gateway subnet isn't set up, or the add-on is disabled.
  • BE disk slow / compaction lagging → default Premium SSD tiers IOPS to size. Use Premium SSD v2 with explicit IOPS (step 2).

Wire your telemetry in — stand up an OTel Collector, or add the doris exporter to your existing OTel pipeline (Integration patterns) — then finish with the post-install checklist.