Tutorial: Deploy Data API builder to Azure Container Apps with Azure CLI
Data API builder can be quickly deployed to Azure services like Azure Container Apps as part of your application stack. In this tutorial, you use the Azure CLI to automate common tasks when deploying Data API builder to Azure. First, you build a container image with Data API builder and store it in Azure Container Registry. You then deploy the container image to Azure Container Apps with a backing Azure SQL database. The entire tutorial authenticates to each component using managed identities.
In this tutorial, you:
- Create a managed identity with role-based access control permissions
- Deploy Azure SQL with the sample AdventureWorksLT dataset
- Stage the container image in Azure Container Registry
- Deploy Azure Container App with the Data API builder container image
If you don't have an Azure subscription, create a free account before you begin.
Prerequisites
- Azure subscription
- Azure Cloud Shell
- Azure Cloud Shell is an interactive shell environment that you can use through your browser. Use this shell and its preinstalled commands to run the code in this article, without having to install anything on your local environment. To start Azure Cloud Shell:
- Select Try It in a code or command block within this article. Selecting Try it doesn't automatically copy the code or command to Cloud Shell.
- Go to https://shell.azure.com, or select Launch Cloud Shell.
- Select Cloud Shell in the menu bar of the Azure portal (https://portal.azure.com)
- Azure Cloud Shell is an interactive shell environment that you can use through your browser. Use this shell and its preinstalled commands to run the code in this article, without having to install anything on your local environment. To start Azure Cloud Shell:
Create container app
First, create an Azure Container Apps instance with a system-assigned managed identity. This identity is eventually granted role-based access control permissions to access Azure SQL and Azure Container Registry.
Create a universal
SUFFIX
variable to use for multiple resource names later in this tutorial.let SUFFIX=$RANDOM*$RANDOM
Create a
LOCATION
variable with an Azure region you selected to use in this tutorial.LOCATION="<azure-region>"
Note
For example, if you want to deploy to the West US region, you would use this script.
LOCATION="westus"
For a list of supported regions for the current subscription, use
az account list-locations
az account list-locations --query "[].{Name:displayName,Slug:name}" --output table
For more information, see Azure regions.
Create a variable named
RESOURCE_GROUP_NAME
with the resource group name. For this tutorial, we recommendmsdocs-dab-*
. You use this value multiple times in this tutorial.RESOURCE_GROUP_NAME="msdocs-dab$SUFFIX"
Create a new resource group using
az group create
.az group create \ --name $RESOURCE_GROUP_NAME \ --location $LOCATION \ --tag "source=msdocs-dab-tutorial"
Create variables named
API_CONTAINER_NAME
andCONTAINER_ENV_NAME
with uniquely generated names for your Azure Container Apps instance. You use these variables throughout the tutorial.API_CONTAINER_NAME="api$SUFFIX" CONTAINER_ENV_NAME="env$SUFFIX"
Use
az containerapp env create
to create a new Azure Container Apps environment.az containerapp env create \ --resource-group $RESOURCE_GROUP_NAME \ --name $CONTAINER_ENV_NAME \ --logs-destination none \ --location $LOCATION
Create a new container app using the
mcr.microsoft.com/azure-databases/data-api-builder
DAB container image and theaz containerapp create
command. This container app runs successfully, but isn't connected to any database.az containerapp create \ --resource-group $RESOURCE_GROUP_NAME \ --environment $CONTAINER_ENV_NAME \ --name $API_CONTAINER_NAME \ --image "mcr.microsoft.com/azure-databases/data-api-builder" \ --ingress "external" \ --target-port "5000" \ --system-assigned
Get the principal identifier of the managed identity using
az identity show
and store the value in a variable namedMANAGED_IDENTITY_PRINCIPAL_ID
.MANAGED_IDENTITY_PRINCIPAL_ID=$( \ az containerapp show \ --resource-group $RESOURCE_GROUP_NAME \ --name $API_CONTAINER_NAME \ --query "identity.principalId" \ --output "tsv" \ )
Tip
You can always check the output of this command.
echo $MANAGED_IDENTITY_PRINCIPAL_ID
Assign permissions
Now, assign the system-assigned managed identity permissions to read data from Azure SQL and Azure Container Registry. Additionally, assign your identity permissions to write to Azure Container Registry.
Create a variable named
RESOURCE_GROUP_ID
to store the identifier of the resource group. Get the identifier usingaz group show
. You use this variable multiple times in this tutorial.RESOURCE_GROUP_ID=$( \ az group show \ --name $RESOURCE_GROUP_NAME \ --query "id" \ --output "tsv" \ )
Tip
You can always check the output of this command.
echo $RESOURCE_GROUP_ID
Use
az role assignment create
to assign the AcrPush role to your account so you can push containers to Azure Container Registry.CURRENT_USER_PRINCIPAL_ID=$( \ az ad signed-in-user show \ --query "id" \ --output "tsv" \ ) # AcrPush az role assignment create \ --assignee $CURRENT_USER_PRINCIPAL_ID \ --role "8311e382-0749-4cb8-b61a-304f252e45ec" \ --scope $RESOURCE_GROUP_ID
Assign the AcrPull role to your managed identity using
az role assignment create
again. This assignment allows the managed identity to pull container images from Azure Container Registry. The managed identity is eventually assigned to an Azure Container Apps instance.# AcrPull az role assignment create \ --assignee $MANAGED_IDENTITY_PRINCIPAL_ID \ --role "7f951dda-4ed3-4680-a7ca-43fe172d538d" \ --scope $RESOURCE_GROUP_ID
Deploy database
Next, deploy a new server and database in the Azure SQL service. The database uses the AdventureWorksLT sample dataset.
Create a variable named
SQL_SERVER_NAME
with a uniquely generated name for your Azure SQL server instance. You use this variable later in this section.SQL_SERVER_NAME="srvr$SUFFIX"
Create a new Azure SQL server resource using
az sql server create
. Configure the managed identity as the admin of this server.az sql server create \ --resource-group $RESOURCE_GROUP_NAME \ --name $SQL_SERVER_NAME \ --location $LOCATION \ --enable-ad-only-auth \ --external-admin-principal-type "User" \ --external-admin-name $API_CONTAINER_NAME \ --external-admin-sid $MANAGED_IDENTITY_PRINCIPAL_ID
Use
az sql server firewall-rule create
to create a firewall rule to allow access from Azure services.az sql server firewall-rule create \ --resource-group $RESOURCE_GROUP_NAME \ --server $SQL_SERVER_NAME \ --name "AllowAzure" \ --start-ip-address "0.0.0.0" \ --end-ip-address "0.0.0.0"
Use
az sql db create
to create a database within the Azure SQL server namedadventureworks
. Configure the database to use theAdventureWorksLT
sample data.az sql db create \ --resource-group $RESOURCE_GROUP_NAME \ --server $SQL_SERVER_NAME \ --name "adventureworks" \ --sample-name "AdventureWorksLT"
Create a variable named
SQL_CONNECTION_STRING
with the connection string for theadventureworks
database in your Azure SQL server instance. Construct the connection string with the fully-qualified domain name of the server usingaz sql server show
. You use this variable later in this tutorial.SQL_SERVER_ENDPOINT=$( \ az sql server show \ --resource-group $RESOURCE_GROUP_NAME \ --name $SQL_SERVER_NAME \ --query "fullyQualifiedDomainName" \ --output "tsv" \ ) SQL_CONNECTION_STRING="Server=$SQL_SERVER_ENDPOINT;Database=adventureworks;Encrypt=true;Authentication=Active Directory Default;"
Tip
You can always check the output of this command.
echo $SQL_CONNECTION_STRING
Build container image
Next, build a container image using a Dockerfile. Then deploy that container image to a newly created Azure Container Registry instance.
Create a variable named
CONTAINER_REGISTRY_NAME
with a uniquely generated name for your Azure Container Registry instance. You use this variable later in this section.CONTAINER_REGISTRY_NAME="reg$SUFFIX"
Create a new Azure Container Registry instance using
az acr create
.az acr create \ --resource-group $RESOURCE_GROUP_NAME \ --name $CONTAINER_REGISTRY_NAME \ --sku "Standard" \ --location $LOCATION \ --admin-enabled false
Create a multi-stage Dockerfile named
Dockerfile
. In the file, implement these steps.Use the
mcr.microsoft.com/dotnet/sdk
container image as the base of the build stageInstall the DAB CLI.
Create a configuration file for an SQL database connection (
mssql
) using theDATABASE_CONNECTION_STRING
environment variable as the connection string.Create an entity named
Product
mapped to theSalesLT.Product
table.Copy the configuration file to the final
mcr.microsoft.com/azure-databases/data-api-builder
container image.
FROM mcr.microsoft.com/dotnet/sdk:6.0-cbl-mariner2.0 AS build WORKDIR /config RUN dotnet new tool-manifest RUN dotnet tool install Microsoft.DataApiBuilder RUN dotnet tool run dab -- init --database-type "mssql" --connection-string "@env('DATABASE_CONNECTION_STRING')" RUN dotnet tool run dab -- add Product --source "SalesLT.Product" --permissions "anonymous:read" FROM mcr.microsoft.com/azure-databases/data-api-builder COPY --from=build /config /App
Build the Dockerfile as an Azure Container Registry task using
az acr build
.az acr build \ --registry $CONTAINER_REGISTRY_NAME \ --image adventureworkslt-dab:latest \ --image adventureworkslt-dab:{{.Run.ID}} \ --file Dockerfile \ .
Use
az acr show
to get the endpoint for the container registry and store it in a variable namedCONTAINER_REGISTRY_LOGIN_SERVER
.CONTAINER_REGISTRY_LOGIN_SERVER=$( \ az acr show \ --resource-group $RESOURCE_GROUP_NAME \ --name $CONTAINER_REGISTRY_NAME \ --query "loginServer" \ --output "tsv" \ )
Tip
You can always check the output of this command.
echo $CONTAINER_REGISTRY_LOGIN_SERVER
Deploy container image
Finally, update the Azure Container App with the new custom container image and credentials. Test the running application to validate its connectivity to the database.
Configure the container app to use the container registry using
az containerapp registry set
.az containerapp registry set \ --resource-group $RESOURCE_GROUP_NAME \ --name $API_CONTAINER_NAME \ --server $CONTAINER_REGISTRY_LOGIN_SERVER \ --identity "system"
Use
az containerapp secret set
to create a secret namedconn-string
with the Azure SQL connection string.az containerapp secret set \ --resource-group $RESOURCE_GROUP_NAME \ --name $API_CONTAINER_NAME \ --secrets conn-string="$SQL_CONNECTION_STRING"
Important
This connection string doesn't include any username or passwords. The connection string uses the managed identity to access the Azure SQL database. This makes it safe to use the connection string as a secret in the host.
Update the container app with your new custom container image using
az containerapp update
. Set theDATABASE_CONNECTION_STRING
environment variable to read from the previously createdconn-string
secret.az containerapp update \ --resource-group $RESOURCE_GROUP_NAME \ --name $API_CONTAINER_NAME \ --image "$CONTAINER_REGISTRY_LOGIN_SERVER/adventureworkslt-dab:latest" \ --set-env-vars DATABASE_CONNECTION_STRING=secretref:conn-string
Retrieve the fully qualified domain name of the latest revision in the running container app using
az containerapp show
. Store that value in a variable namedAPPLICATION_URL
.APPLICATION_URL=$( \ az containerapp show \ --resource-group $RESOURCE_GROUP_NAME \ --name $API_CONTAINER_NAME \ --query "properties.latestRevisionFqdn" \ --output "tsv" \ )
Tip
You can always check the output of this command.
echo $APPLICATION_URL
Navigate to the URL and test the
Product
REST API.echo "https://$APPLICATION_URL/api/Product"
Warning
Deployment can take up to a minute. If you are not seeing a successful response, wait and refresh your browser.
Clean up resources
When you no longer need the sample application or resources, remove the corresponding deployment and all resources.
az group delete \
--name $RESOURCE_GROUP_NAME