Deploy DIAL on Azure
Deploy the full DIAL stack to Azure Kubernetes Service (AKS) using the umbrella Helm chart, with Azure Blob Storage for files and Azure OpenAI as the model provider. This guide assumes you operate an AKS cluster and are familiar with Helm and kubectl. For the chart model and infrastructure mapping, read the Helm chart overview first.
Prerequisites
-
An AKS cluster, version 1.24 or higher, with
kubectland Helm 3.8.0 or higher configured against it -
The Ingress-NGINX controller and cert-manager installed in the cluster
-
Azure AD Workload Identity enabled on the cluster
-
An Azure Blob Storage account for DIAL file storage
-
An Azure OpenAI resource with at least one model deployed
-
A Microsoft Entra ID app registration for DIAL Chat sign-in, with a client secret
-
A domain and a cert-manager
ClusterIssuerfor TLS -
The DIAL Helm repository added:
helm repo add dial https://charts.dialx.ai
helm repo update
Step 1: Create a values file
Start from the upstream Azure simple example and fill in your environment. The required values are:
core:
# Workload Identity managed identity client ID
serviceAccount:
annotations:
azure.workload.identity/client-id: <AZURE_CORE_CLIENT_ID>
env:
aidial.storage.account: <AZURE_CORE_BLOB_STORAGE_NAME>
aidial.storage.endpoint: <AZURE_CORE_BLOB_STORAGE_ENDPOINT>
aidial.identityProviders.azure.jwksUrl: "https://login.microsoftonline.com/<AZURE_TENANT_ID>/discovery/v2.0/keys"
aidial.identityProviders.azure.rolePath: "groups"
aidial.identityProviders.azure.issuerPattern: '^https:\/\/sts\.windows\.net.+$'
ingress:
enabled: true
ingressClassName: nginx
annotations:
cert-manager.io/cluster-issuer: <CLUSTER_ISSUER>
hosts:
- dial.<DOMAIN>
tls:
- secretName: dial-tls-secret
hosts:
- dial.<DOMAIN>
openai:
env:
aidial.openai.endpoint: <AZURE_MODEL_ENDPOINT>
aidial.openai.key: <AZURE_MODEL_KEY>
chat:
env:
AUTH_CALLBACK_BASE_URL: "https://chat.<DOMAIN>"
AUTH_POST_LOGOUT_REDIRECT_URI: "https://chat.<DOMAIN>"
DIAL_CORE_URL: "http://dial-core.dial.svc.cluster.local"
CORS_ORIGIN: "https://chat.<DOMAIN>"
secrets:
AUTH_SESSION_SECRET: <AUTH_SESSION_SECRET>
AUTH_AZURE_AD_CLIENT_ID: <AUTH_AZURE_AD_CLIENT_ID>
AUTH_AZURE_AD_TENANT_ID: <AZURE_TENANT_ID>
AUTH_AZURE_AD_SECRET: <AUTH_AZURE_AD_SECRET>
ingress:
enabled: true
ingressClassName: nginx
annotations:
cert-manager.io/cluster-issuer: <CLUSTER_ISSUER>
hosts:
- chat.<DOMAIN>
tls:
- secretName: chat-tls-secret
hosts:
- chat.<DOMAIN>
DIAL Core and DIAL Chat each get their own Ingress-NGINX host and cert-manager-issued certificate, under core.ingress and chat.ingress; see the Azure example - simple for the full values file.
core.env registers Entra ID as the identity provider DIAL Core trusts for user tokens; chat.env/chat.secrets configure DIAL Chat's own sign-in flow against the same app registration. In the app registration, set the redirect URI to match AUTH_CALLBACK_BASE_URL.
Replace the placeholders:
<AZURE_CORE_CLIENT_ID>— the Workload Identity managed identity client ID for DIAL Core<AZURE_CORE_BLOB_STORAGE_NAME>— the storage account name<AZURE_CORE_BLOB_STORAGE_ENDPOINT>— the Blob Storage endpoint URL<AZURE_TENANT_ID>— your Microsoft Entra tenant ID<AZURE_MODEL_ENDPOINT>— the Azure OpenAI deployment endpoint<AZURE_MODEL_KEY>— the Azure OpenAI API key<DOMAIN>— your base domain; DIAL Core is exposed atdial.<DOMAIN>and DIAL Chat atchat.<DOMAIN>, for exampleexample.com<AUTH_AZURE_AD_CLIENT_ID>— the app registration's application (client) ID<AUTH_AZURE_AD_SECRET>— the app registration's client secret<AUTH_SESSION_SECRET>— a random secret DIAL Chat uses to encrypt session cookies<CLUSTER_ISSUER>— the cert-manager issuer, for exampleletsencrypt-production
Generate the DIAL API key, <AUTH_SESSION_SECRET>, and encryption keys before installing. For production, read these from Azure Key Vault rather than inlining them — see Azure Secrets deployment.
Step 2: Install the chart
helm install dial dial/dial \
-f values.yaml \
--version <CHART_VERSION> \
--namespace dial \
--create-namespace
Pin <CHART_VERSION> to a released chart version.
Step 3: Verify the deployment
Check that the pods are running:
kubectl get pods -n dial
Once the ingress has an address and both certificates are issued, DIAL Chat is reachable at https://chat.<DOMAIN>/; open it in a browser and sign in through Microsoft Entra ID. Confirm the Unified API responds:
curl https://dial.<DOMAIN>/openai/deployments \
-H "Api-Key: <YOUR_DIAL_API_KEY>"
Result
DIAL Core, DIAL Chat, Valkey, and the Azure OpenAI adapter run on your AKS cluster, with files persisted to Azure Blob Storage and models served from Azure OpenAI.
Note
The
openaialias of thedialchart deploys the standalone OpenAI adapter, which will be deprecated. DIAL Model Provider replaces it. Deploy it with the DIAL Extension chart and move your models as described in Migrate from the standalone adapters.
Production architecture
The simple example is a starting point. For a production deployment, size the Azure services and configure redundancy as follows.
Recommended service tiers
| Azure service | Tier |
|---|---|
| Azure Kubernetes Service | Standard, zone-redundant |
| Ingress-NGINX controller | Standard, fronted by an Azure Load Balancer (Standard SKU) |
| Storage Account | Standard, Azure Blob Storage, GZRS |
| Azure Cache for Redis | Premium P1, zone-redundant |
| Azure OpenAI | Sized to capacity requirements; provisioned throughput or pay-as-you-go |
Dependencies whose technology may follow corporate standards:
| Dependency | Azure service |
|---|---|
| SSO | Microsoft Entra ID |
| Firewall | Azure Application Gateway with WAF |
| Logging and monitoring | Azure Application Insights and Log Analytics |
| Container registry | Azure Container Registry |
| Secret storage | Azure Key Vault |
Scalability
DIAL services are stateless, so they run as multiple concurrent copies. As a baseline, run two copies of each service on different nodes for high availability. The services are not resource-intensive and handle thousands of users without further scaling.
To absorb load spikes, configure autoscaling for DIAL Core based on CPU usage (for example, scale out when usage exceeds 80% of the CPU limit for one minute), and enable cluster autoscaling so new nodes are added when existing nodes lack capacity.
Scaling language models is the more common need, because a single model instance is often capped by request rate limits. With Azure OpenAI there are four levels of scaling, applied in order:
- Increase the number of model instances in the same region.
- Request a regional quota extension — each region has a fixed tokens-per-minute (TPM) quota per model type.
- Create model instances in other regions.
- Use multiple subscriptions to access model endpoints.
High availability
Achieve high availability through zone redundancy: run DIAL service copies in a multi-zone AKS cluster and use highly available configurations for the supporting services.
| Service | Availability SLA | Resilient to zone-wide outages |
|---|---|---|
| Azure Kubernetes Service | 99.95% with zone redundancy | Yes, if configured explicitly |
| Key Vault | 99.99% | Yes |
| Storage Account | 99.99% (read), 99.9% (write) | Yes, if configured explicitly |
| Azure Cache for Redis | 99.9% with zone redundancy | Yes, if configured explicitly |
| Azure OpenAI | No SLA | — |
Because Azure OpenAI has no SLA, define multiple model endpoints in different regions. If one endpoint fails, DIAL automatically tries the next in the list.
Disaster recovery
DIAL has two parts with separate recovery policies: DIAL Core and the optional DIAL Analytics.
DIAL Core consists of stateless services plus a single permanent store on an Azure Storage account (Valkey is a cache and can be safely restarted). For a region-wide failure:
- Storage account — with GZRS redundancy it can fail over to the secondary region. After failover it runs as ZRS in one region; set the mode back to GZRS explicitly to restore cross-region failover capability for the next event.
- All other services — being stateless, redeploy the full set in a secondary region and re-route the DIAL domain name to the new entry point. To meet a tight recovery time objective, keep a passive DIAL Core deployment in the secondary region and activate it on failure.
When the primary region is restored, there is no need to fail back.
DIAL Analytics keeps ingested rows in ClickHouse and its catalog of tables, pipelines, saved queries, and dashboards in PostgreSQL. Back up PostgreSQL to keep those definitions. Replicate the usage-log blobs it reads like any other permanent store: the backfill endpoint can re-ingest a date range from them, up to BACKFILL_MAX_DAYS days per request.
Further reading
- Azure Secrets deployment — read secrets from Azure Key Vault
- Deploy Azure OpenAI models — connect Azure OpenAI deployments through DIAL Model Provider
- Custom Apps deployment — deploy your own applications alongside DIAL
- Run DIAL with high availability — replicas, zone spread, and failover settings in the Helm chart
- AWS deployment — the equivalent guide for Amazon EKS
- GCP deployment — the equivalent guide for Google GKE