- Azure Subscription
- Azure CLI
- k6 for generating orders
RESOURCE_GROUP="containerapps"
LOCATION="canadacentral"
CONTAINERAPPS_ENVIRONMENT="containerapps"
az login
az extension add --name containerapp
az provider register --namespace Microsoft.App
az provider show -n Microsoft.App --query registrationState
az group create \
--name $RESOURCE_GROUP \
--location "$LOCATION"
az deployment group create \
--name env-create \
-g $RESOURCE_GROUP \
--template-file ./environment.bicep \
--parameters environmentName=$CONTAINERAPPS_ENVIRONMENT
az containerapp env list -o table
az containerapp env show -n containerapps -g containerapps
az containerapp env dapr-component list -n containerapps -g containerapps -o table
az containerapp env dapr-component show -n containerapps -g containerapps --dapr-component-name statestore
DEPLOY_OUTPUTS=$(az deployment group show --name env-create -g $RESOURCE_GROUP --query properties.outputs)
ACR_USERNAME=$(echo $DEPLOY_OUTPUTS | jq -r .acrUserName.value)
ACR_PASSWORD=$(echo $DEPLOY_OUTPUTS | jq -r .acrPassword.value)
ACR_LOGIN_SERVER=$(echo $DEPLOY_OUTPUTS | jq -r .acrloginServer.value)
ACR_NAME=$(echo $ACR_LOGIN_SERVER | cut -f1,1 -d .)
WORKSPACE_CLIENT_ID=$(echo $DEPLOY_OUTPUTS | jq -r .workspaceId.value)
pushd ~
git clone https://github.com/clarenceb/quickstarts dapr-quickstarts
cd dapr-quickstarts/hello-kubernetes/node
az acr build --image hello-k8s-node:v1 \
--registry $ACR_NAME \
--file Dockerfile .
cd ../python
az acr build --image hello-k8s-python:v1 \
--registry $ACR_NAME \
--file Dockerfile .
popd
# Deploy via Bicep template
az deployment group create \
--name nodeapp-v1 \
-g $RESOURCE_GROUP \
--template-file ./nodeapp-containerapp.bicep \
--parameters environment_name=$CONTAINERAPPS_ENVIRONMENT \
custom_message="v1" \
image_name="$ACR_LOGIN_SERVER/hello-k8s-node:v1" \
registry_login_server=$ACR_LOGIN_SERVER \
registry_username=$ACR_USERNAME \
registry_password=$ACR_PASSWORD
# Or via CLI
az containerapp create \
--name nodeapp \
--container-name nodeapp \
--revisions-mode multiple \
--resource-group $RESOURCE_GROUP \
--environment $CONTAINERAPPS_ENVIRONMENT \
--image $ACR_LOGIN_SERVER/hello-k8s-node:v1 \
--registry-server $ACR_LOGIN_SERVER \
--registry-username $ACR_USERNAME \
--registry-password $ACR_PASSWORD \
--env-vars MESSAGE=v1 \
--cpu 0.5 \
--memory 1.0Gi \
--target-port 3000 \
--ingress external \
--min-replicas 1 \
--max-replicas 1 \
--enable-dapr \
--dapr-app-port 3000 \
--dapr-app-id nodeapp \
--dapr-app-protocol http
az containerapp list -o table
az containerapp revision list -n nodeapp -g $RESOURCE_GROUP -o table
The Python App will invoke the NodeApp every second via it's Dapr sidecar via the URI: http://localhost:{DAPR_PORT}/v1.0/invoke/nodeapp/method/neworder
NODEAPP_INGRESS_URL="https://$(az containerapp show -n nodeapp -g $RESOURCE_GROUP --query properties.configuration.ingress.fqdn -o tsv)"
# Deploy via Bicep template
az deployment group create \
--name pythonapp \
-g $RESOURCE_GROUP \
--template-file ./pythonapp-containerapp.bicep \
--parameters environment_name=$CONTAINERAPPS_ENVIRONMENT \
image_name="$ACR_LOGIN_SERVER/hello-k8s-python:v1" \
registry_login_server=$ACR_LOGIN_SERVER \
registry_username=$ACR_USERNAME \
registry_password=$ACR_PASSWORD
# Or via CLI
az containerapp create \
--name pythonapp \
--container-name pythonapp \
--resource-group $RESOURCE_GROUP \
--environment $CONTAINERAPPS_ENVIRONMENT \
--image $ACR_LOGIN_SERVER/hello-k8s-node:v1 \
--registry-server $ACR_LOGIN_SERVER \
--registry-username $ACR_USERNAME \
--registry-password $ACR_PASSWORD \
--cpu 0.5 \
--memory 1.0Gi \
--min-replicas 1 \
--max-replicas 1 \
--enable-dapr \
--dapr-app-id pythonapp \
--dapr-app-protocol http
# Append paraemter `nodeapp_url` if not using Dapr for service discovery
# nodeapp_url=$NODEAPP_INGRESS_URL/neworder
az containerapp list -o table
az containerapp revision list -n pythonapp -g $RESOURCE_GROUP -o table
curl -i --request POST --data "@sample.json" --header Content-Type:application/json $NODEAPP_INGRESS_URL/neworder
curl -s $NODEAPP_INGRESS_URL/order | jq
az monitor log-analytics query \
--workspace $WORKSPACE_CLIENT_ID \
--analytics-query "ContainerAppConsoleLogs_CL | where ContainerAppName_s == 'nodeapp' and (Log_s contains 'persisted' or Log_s contains 'order') | where TimeGenerated >= ago(30m) | project ContainerAppName_s, Log_s, TimeGenerated | order by TimeGenerated desc | take 20" \
--out table
watch -n 5 az monitor log-analytics query --workspace $WORKSPACE_CLIENT_ID --analytics-query "\"ContainerAppConsoleLogs_CL | where ContainerAppName_s == 'nodeapp' and (Log_s contains 'persisted' or Log_s contains 'order') | where TimeGenerated >= ago(30m) | project ContainerAppName_s, Log_s, TimeGenerated | order by TimeGenerated desc | take 20\"" --out table
# Or in the Azure Portal, enter this KQL query:
ContainerAppConsoleLogs_CL
| where ContainerAppName_s == 'nodeapp' and (Log_s contains 'persisted' or Log_s contains 'order')
| where TimeGenerated >= ago(30m)
| project ContainerAppName_s, Log_s, TimeGenerated
| order by TimeGenerated desc
| take 20
# Note: There is some latency when streaming logs via the CLI. Use the Azure Portal if you want to query logs with less latency.
URL=$NODEAPP_INGRESS_URL/neworder k6 run k6-script.js
# Deploy via Bicep template
az deployment group create \
--name nodeapp-v1 \
-g $RESOURCE_GROUP \
--template-file ./nodeapp-containerapp.bicep \
--parameters environment_name=$CONTAINERAPPS_ENVIRONMENT \
custom_message="v2" \
image_name="$ACR_LOGIN_SERVER/hello-k8s-node:v1" \
registry_login_server=$ACR_LOGIN_SERVER \
registry_username=$ACR_USERNAME \
registry_password=$ACR_PASSWORD
# Or via CLI
az containerapp update \
--name nodeapp \
--container-name nodeapp \
--resource-group $RESOURCE_GROUP \
--image $ACR_LOGIN_SERVER/hello-k8s-node:v1 \
--replace-env-vars MESSAGE=v2 \
--min-replicas 1 \
--max-replicas 1
az containerapp list -o table
az containerapp revision list -n nodeapp -g $RESOURCE_GROUP -o table
In the Azure Portal, split traffic 50% to v1 and v2 and send some orders.
URL=$NODEAPP_INGRESS_URL/neworder k6 run k6-script.js
Inspect the logs via CLI or in the Azure Portal to see round-robin between the two revisions.
watch -n 5 az monitor log-analytics query --workspace $WORKSPACE_CLIENT_ID --analytics-query "\"ContainerAppConsoleLogs_CL | where ContainerAppName_s == 'nodeapp' and (Log_s contains 'persisted' or Log_s contains 'order') | where TimeGenerated >= ago(30m) | project ContainerAppName_s, Log_s, TimeGenerated | order by TimeGenerated desc | take 20\"" --out table
# Or in the Azure Portal, enter this KQL query:
ContainerAppConsoleLogs_CL
| where ContainerAppName_s == 'nodeapp' and (Log_s contains 'persisted' or Log_s contains 'order')
| where TimeGenerated >= ago(30m)
| project ContainerAppName_s, Log_s, TimeGenerated
| order by TimeGenerated desc
| take 20
After creating some orders, check the App Insights resource.
- Application Map
- Performance
Cleanup container apps to restart the demo (retaining enviornment and other resources):
az deployment group delete --name nodeapp-v1 -g $RESOURCE_GROUP
az deployment group delete --name pythonapp -g $RESOURCE_GROUP
az containerapp delete --name nodeapp --resource-group $RESOURCE_GROUP --yes
az containerapp delete --name pythonapp --resource-group $RESOURCE_GROUP --yes
or full cleanup:
az group delete \
--resource-group $RESOURCE_GROUP \
--yes
- Tutorial: Deploy a Dapr application to Azure Container Apps using the Azure CLI
- Hello Kubernetes - Dapr quickstart
- Container Apps Preview ARM template API specification
- Container apps Bicep specifications for 2022-01-01-preview apiVersion
- Container apps Bicep specifications for 2022-03-01 apiVersion