Deploying to Azure¶
This guide covers deploying the DBN Analytics POC API to Microsoft Azure using three production-ready options:
| Option | Best For | Complexity |
|---|---|---|
| Azure Container Apps | Serverless auto-scaling, easiest setup | ⭐ Low |
| Azure App Service (Web Apps) | Traditional PaaS, familiar experience | ⭐⭐ Medium |
| Azure Kubernetes Service (AKS) | Enterprise-scale, full control | ⭐⭐⭐ High |
Prerequisites¶
Before you begin, ensure you have:
- An active Azure subscription
- The Azure CLI installed
- Docker Desktop installed (for building images locally)
Install and verify the Azure CLI:
Common Setup (All Options)¶
1. Set Environment Variables¶
Set these shell variables once. They will be referenced throughout all deployment options.
2. Create a Resource Group¶
3. Create an Azure Container Registry (ACR)¶
ACR is used to store your Docker image privately in Azure.
az acr create \
--resource-group $RESOURCE_GROUP \
--name $ACR_NAME \
--sku Basic \
--admin-enabled true
4. Build and Push the Docker Image to ACR¶
# Log in to ACR
az acr login --name $ACR_NAME
# Build the image
docker build -t $ACR_NAME.azurecr.io/$IMAGE_NAME:$IMAGE_TAG .
# Push to ACR
docker push $ACR_NAME.azurecr.io/$IMAGE_NAME:$IMAGE_TAG
Alternatively, use ACR's built-in cloud build (no local Docker required):
Option 1: Azure Container Apps¶
Recommended — serverless, scales to zero, built-in HTTPS and ingress.
Architecture¶
flowchart LR
Internet(["🌐 Internet"]) -->|HTTPS| Ingress
subgraph Azure Container Apps Environment
Ingress["🔀 Managed Ingress\n(TLS terminated)"]
App["📦 Container App\ndbn-analytics-poc"]
end
App --> ACR[("🐳 Azure Container\nRegistry (ACR)")]
App --> KV["🔑 Azure Key Vault\n(Secrets)"]
Step 1: Create the Container Apps Environment¶
az containerapp env create \
--name dbn-analytics-env \
--resource-group $RESOURCE_GROUP \
--location $LOCATION
Step 2: Deploy the Container App¶
ACR_PASSWORD=$(az acr credential show \
--name $ACR_NAME \
--query "passwords[0].value" \
--output tsv)
az containerapp create \
--name dbn-analytics-poc \
--resource-group $RESOURCE_GROUP \
--environment dbn-analytics-env \
--image $ACR_NAME.azurecr.io/$IMAGE_NAME:$IMAGE_TAG \
--registry-server $ACR_NAME.azurecr.io \
--registry-username $ACR_NAME \
--registry-password $ACR_PASSWORD \
--target-port 8080 \
--ingress external \
--min-replicas 0 \
--max-replicas 5 \
--cpu 0.5 \
--memory 1.0Gi \
--secrets openai-api-key=<YOUR_OPENAI_API_KEY> \
--env-vars OPENAI_API_KEY=secretref:openai-api-key
Scales to zero
--min-replicas 0 means the app costs nothing when idle and auto-starts on the first request.
Step 3: Get the Live URL¶
az containerapp show \
--name dbn-analytics-poc \
--resource-group $RESOURCE_GROUP \
--query "properties.configuration.ingress.fqdn" \
--output tsv
This returns a URL like dbn-analytics-poc.nicemeadow-abc12345.eastus.azurecontainerapps.io.
Updating a Deployment¶
After code changes, rebuild, push, and update in one command:
az acr build --registry $ACR_NAME --image $IMAGE_NAME:$IMAGE_TAG .
az containerapp update \
--name dbn-analytics-poc \
--resource-group $RESOURCE_GROUP \
--image $ACR_NAME.azurecr.io/$IMAGE_NAME:$IMAGE_TAG
Option 2: Azure App Service (Web Apps)¶
Ideal for teams familiar with traditional Azure PaaS hosting. Includes built-in CI/CD integration with GitHub Actions.
Step 1: Create an App Service Plan¶
az appservice plan create \
--name dbn-analytics-plan \
--resource-group $RESOURCE_GROUP \
--sku B2 \
--is-linux
| SKU | vCPUs | Memory | Monthly Cost (approx.) |
|---|---|---|---|
B1 |
1 | 1.75 GB | ~$13 USD |
B2 |
2 | 3.5 GB | ~$26 USD |
P1v3 |
2 | 8 GB | ~$82 USD |
Step 2: Create the Web App¶
ACR_PASSWORD=$(az acr credential show \
--name $ACR_NAME \
--query "passwords[0].value" \
--output tsv)
az webapp create \
--resource-group $RESOURCE_GROUP \
--plan dbn-analytics-plan \
--name dbn-analytics-poc \
--deployment-container-image-name $ACR_NAME.azurecr.io/$IMAGE_NAME:$IMAGE_TAG \
--docker-registry-server-url https://$ACR_NAME.azurecr.io \
--docker-registry-server-user $ACR_NAME \
--docker-registry-server-password $ACR_PASSWORD
Step 3: Set Application Settings (Environment Variables)¶
az webapp config appsettings set \
--resource-group $RESOURCE_GROUP \
--name dbn-analytics-poc \
--settings \
OPENAI_API_KEY="<YOUR_OPENAI_API_KEY>" \
VANNA_MODEL="gpt-4o" \
WEBSITES_PORT=8080
WEBSITES_PORT
Azure App Service requires WEBSITES_PORT=8080 so the platform knows which port your container is listening on.
Step 4: Enable Continuous Deployment from ACR¶
az webapp deployment container config \
--resource-group $RESOURCE_GROUP \
--name dbn-analytics-poc \
--enable-cd true
Step 5: Get the Live URL¶
az webapp show \
--resource-group $RESOURCE_GROUP \
--name dbn-analytics-poc \
--query "defaultHostName" \
--output tsv
The app will be available at https://dbn-analytics-poc.azurewebsites.net.
Option 3: Azure Kubernetes Service (AKS)¶
For enterprise deployments requiring custom scaling policies, network isolation, or multi-service orchestration.
Step 1: Create an AKS Cluster¶
az aks create \
--resource-group $RESOURCE_GROUP \
--name dbn-analytics-aks \
--node-count 1 \
--node-vm-size Standard_B2s \
--enable-managed-identity \
--attach-acr $ACR_NAME \
--generate-ssh-keys
Step 2: Get Credentials¶
Verify connectivity:
Step 3: Create Kubernetes Secret for OpenAI¶
Step 4: Apply Kubernetes Manifests¶
Create the deployment and service configuration:
apiVersion: apps/v1
kind: Deployment
metadata:
name: dbn-analytics-poc
labels:
app: dbn-analytics-poc
spec:
replicas: 2
selector:
matchLabels:
app: dbn-analytics-poc
template:
metadata:
labels:
app: dbn-analytics-poc
spec:
containers:
- name: api
image: dbnanalyticsacr.azurecr.io/dbn-analytics-poc:latest
ports:
- containerPort: 8080
env:
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: openai-secret
key: OPENAI_API_KEY
- name: VANNA_MODEL
value: "gpt-4o"
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "1000m"
memory: "1Gi"
livenessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 15
periodSeconds: 20
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
---
apiVersion: v1
kind: Service
metadata:
name: dbn-analytics-poc-svc
spec:
type: LoadBalancer
selector:
app: dbn-analytics-poc
ports:
- protocol: TCP
port: 80
targetPort: 8080
Step 5: Get the External IP¶
Wait for the EXTERNAL-IP column to populate, then access: http://<EXTERNAL-IP>/docs.
Securing Secrets with Azure Key Vault¶
For all deployment options, it is best practice to store secrets in Azure Key Vault rather than passing them as plain environment variables.
Create a Key Vault and Store the Secret¶
az keyvault create \
--name dbn-analytics-kv \
--resource-group $RESOURCE_GROUP \
--location $LOCATION
az keyvault secret set \
--vault-name dbn-analytics-kv \
--name "OPENAI-API-KEY" \
--value "<YOUR_OPENAI_API_KEY>"
Reference Key Vault in Container Apps¶
# Grant Container App identity access to Key Vault
PRINCIPAL_ID=$(az containerapp show \
--name dbn-analytics-poc \
--resource-group $RESOURCE_GROUP \
--query "identity.principalId" -o tsv)
az keyvault set-policy \
--name dbn-analytics-kv \
--object-id $PRINCIPAL_ID \
--secret-permissions get list
CI/CD with GitHub Actions¶
Automate your deployment pipeline by creating .github/workflows/azure-deploy.yml:
name: Build and Deploy to Azure Container Apps
on:
push:
branches: [ main ]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Log in to Azure
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Build and push to ACR
run: |
az acr build \
--registry dbnanalyticsacr \
--image dbn-analytics-poc:${{ github.sha }} \
.
- name: Deploy to Azure Container Apps
run: |
az containerapp update \
--name dbn-analytics-poc \
--resource-group dbn-analytics-rg \
--image dbnanalyticsacr.azurecr.io/dbn-analytics-poc:${{ github.sha }}
Set AZURE_CREDENTIALS in your GitHub repository secrets using:
az ad sp create-for-rbac \
--name "dbn-analytics-github-actions" \
--role contributor \
--scopes /subscriptions/<SUB_ID>/resourceGroups/$RESOURCE_GROUP \
--sdk-auth
Clean Up Resources¶
When done, remove all Azure resources to avoid charges:
Comparison Summary¶
| Feature | Container Apps | App Service | AKS |
|---|---|---|---|
| Scale to zero | ✅ | ❌ | ✅ (with KEDA) |
| Managed TLS | ✅ | ✅ | ⚙️ Manual |
| Custom domains | ✅ | ✅ | ✅ |
| Setup complexity | Low | Medium | High |
| CI/CD integration | ✅ | ✅ | ✅ |
| Best for | Serverless APIs | Traditional teams | Enterprise scale |