Chỉnh sửa

Deploy a containerized Python app to App Service

In this part of the tutorial series, you learn how to deploy a containerized Python web application to Azure App Service Web App for Containers. This fully managed service lets you run containerized apps without having to maintain your own container orchestrator.

App Service simplifies deployment through continuous integration/continuous deployment (CI/CD) pipelines that work with Docker Hub, Azure Container Registry, Azure Key Vault, and other DevOps tools. This tutorial is part 4 of a 5-part tutorial series.

At the end of this article, you have a secure, production-ready App Service web app running from a Docker container image. The app uses a system-assigned managed identity to pull the image from Azure Container Registry and retrieve secrets from Azure Key Vault.

This service diagram highlights the components covered in this article.

A screenshot of the services using in the Tutorial - Containerized Python App on Azure with deployment path highlighted.

You can run Azure CLI commands in the Azure Cloud Shell or on a local machine with the Azure CLI installed.

Important

Use Azure Cloud Shell for all CLI-based steps in this tutorial because it:

  • Comes preauthenticated with your Azure account, so you don't encounter authentication problems
  • Includes all required Azure CLI extensions
  • Ensures consistent behavior regardless of your local OS or environment
  • Requires no local installation, ideal for users without admin rights
  • Provides direct access to Azure services from the portal - no local Docker or network setup required
  • Avoids local firewall or network configuration problems

Create Key Vault with RBAC Authorization

Azure Key Vault is a secure service for storing secrets, API keys, connection strings, and certificates. In this script, it stores the MongoDB connection string and the web app’s SECRET_KEY.

Configure the Key Vault to use role-based access control (RBAC) to manage access through Azure roles instead of traditional access policies. The web app uses its system-assigned managed identity to retrieve secrets securely at runtime.

Note

Create the Key Vault early to ensure that you can assign roles before any attempt to access secrets. This approach also helps avoid propagation delays in role assignments. Since Key Vault doesn't depend on the App Service, provisioning it early improves reliability and sequencing.

  1. Use the az keyvault create command to create an Azure Key Vault with RBAC enabled.

    #!/bin/bash
    RESOURCE_GROUP_NAME="msdocs-web-app-rg"
    LOCATION="westus"
    KEYVAULT_NAME="${RESOURCE_GROUP_NAME}-kv"
    
    az keyvault create \
      --name "$KEYVAULT_NAME" \
      --resource-group "$RESOURCE_GROUP_NAME" \
      --location "$LOCATION" \
      --enable-rbac-authorization true
    

Create the app service plan and web app

The App Service Plan defines the compute resources, pricing tier, and region for your web app. The web app runs your containerized application and is provisioned with a system-assigned managed identity that it uses to securely authenticate to Azure Container Registry (ACR) and Azure Key Vault.

In this step, complete the following tasks:

  • Create an App Service Plan
  • Create the web app with its managed identity
  • Configure the web app to deploy by using a specific container image
  • Prepare for continuous deployment via ACR

Note

You must create the web app before assigning access to ACR or Key Vault because the managed identity is created only at deployment time. Also, assigning the container image during creation ensures the app starts up correctly with the intended configuration.

  1. Use the az appservice plan create command to provision the compute environment for your app.

    #!/bin/bash
    APP_SERVICE_PLAN_NAME="msdocs-web-app-plan"
    
    az appservice plan create \
        --name "$APP_SERVICE_PLAN_NAME" \
        --resource-group "$RESOURCE_GROUP_NAME" \
        --sku B1 \
        --is-linux
    
  2. Use the az webapp create command to create the web app. This command also enables a system-assigned managed identity and sets the container image that the app runs.

    #!/bin/bash
    APP_SERVICE_NAME="msdocs-website-name" #APP_SERVICE_NAME must be globally unique as it becomes the website name in the URL `https://<website-name>.azurewebsites.net`.
    # Use the same registry name as in part 2 of this tutorial series.
    REGISTRY_NAME="msdocscontainerregistryname" #REGISTRY_NAME is the registry name you used in part 2 of this tutorial.
    CONTAINER_NAME="$REGISTRY_NAME.azurecr.io/msdocspythoncontainerwebapp:latest" #CONTAINER_NAME is of the form "yourregistryname.azurecr.io/repo_name:tag".
    
    az webapp create \
      --resource-group "$RESOURCE_GROUP_NAME" \
      --plan "$APP_SERVICE_PLAN_NAME" \
      --name "$APP_SERVICE_NAME" \
      --assign-identity '[system]' \
      --deployment-container-image-name "$CONTAINER_NAME" 
    

    Note

    When running this command, you might see the following error:

    No credential was provided to access Azure Container Registry. Trying to look up...
    Retrieving credentials failed with an exception:'Failed to retrieve container registry credentials. Please either provide the credentials or run 'az acr update -n msdocscontainerregistryname --admin-enabled true' to enable admin first.'
    

    This error occurs because the web app tries to use admin credentials to access ACR, but admin credentials are disabled by default. You can safely ignore this message. The next step configures the web app to use its managed identity to authenticate with ACR.

Grant Key Vault Secrets Officer role to authenticated user

To store secrets in Azure Key Vault, the user running the script must have the Key Vault Secrets Officer role. This role grants permission to create and manage secrets within the vault.

In this step, the script assigns that role to the currently authenticated user. This user can then securely store application secrets, such as the MongoDB connection string and the app’s SECRET_KEY.

This role assignment is the first of two Key Vault–related role assignments. Later, the web app’s system-assigned managed identity is granted access to retrieve secrets from the vault.

By using Azure RBAC, you ensure secure, auditable access based on identity, so you don't need to use hard-coded credentials.

Note

Assign the Key Vault Secrets Officer role to the user before they attempt to store any secrets in the key vault. Use the az role assignment create command scoped to the Key Vault to make this assignment.

  1. Use the az role assignment create command to assign the role at the Key Vault scope.

    #!/bin/bash
    CALLER_ID=$(az ad signed-in-user show --query id -o tsv)
    echo $CALLER_ID # Verify this value retrieved successfully. In production, poll to verify this value is retrieved successfully.
    
    az role assignment create \
      --role "Key Vault Secrets Officer" \
      --assignee "$CALLER_ID" \
      --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.KeyVault/vaults/$KEYVAULT_NAME"
    
    

Grant web access to ACR using managed identity

To pull images from Azure Container Registry (ACR) securely, configure the web app to use its system-assigned managed identity. By using managed identity, you don't need admin credentials and can support secure, credential-free deployment.

This process involves two key actions:

  • Enabling the web app to use its managed identity when accessing ACR
  • Assigning the AcrPull role to that identity on the target ACR
  1. In this step, retrieve the principal ID (unique object ID) of the web app’s managed identity by using the az webapp identity show command. Next, enable the use of the managed identity for ACR authentication by setting the acrUseManagedIdentityCreds property to true by using az webapp config set. Then, assign the AcrPull role to the web app’s managed identity by using the az role assignment create command. This role grants the web app permission to pull images from the registry.

    #!/bin/bash
    PRINCIPAL_ID=$(az webapp identity show \
      --name "$APP_SERVICE_NAME" \
      --resource-group "$RESOURCE_GROUP_NAME" \
      --query principalId \
      -o tsv)
    echo $PRINCIPAL_ID # Verify this value retrieved successfully. In production, poll for successful 'AcrPull' role assignment using `az role assignment list`.    
    
    az webapp config set \
      --resource-group "$RESOURCE_GROUP_NAME" \
      --name "$APP_SERVICE_NAME" \
      --generic-configurations '{"acrUseManagedIdentityCreds": true}'
    
    az role assignment create \
    --role "AcrPull" \
    --assignee "$PRINCIPAL_ID" \
    --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.ContainerRegistry/registries/$REGISTRY_NAME"
    
    

Grant key vault access to the web app's managed identity

The web app needs permission to access secrets like the MongoDB connection string and the SECRET_KEY. To grant these permissions, assign the Key Vault Secrets User role to the web app’s system-assigned managed identity.

  1. In this step, use the unique identifier (principal ID) of the web app’s system-assigned managed identity to grant the web app access to the Key Vault with the Key Vault Secrets User role by using the az role assignment create command.

    #!/bin/bash
    
    az role assignment create \
    --role "Key Vault Secrets User" \
    --assignee "$PRINCIPAL_ID" \
    --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.KeyVault/vaults/$KEYVAULT_NAME"
    

Store secrets in Key Vault

To avoid hardcoding secrets in your application, store the MongoDB connection string and the web app’s secret key in Azure Key Vault. The web app can securely access these secrets at runtime through its managed identity, so you don't need to store credentials in code or configuration.

Note

While this tutorial stores only the connection string and secret key in the key vault, you can optionally store other application settings such as the MongoDB database name or collection name in Key Vault as well.

  1. Use the az cosmosdb keys list command to retrieve the MongoDB connection string. Then, use the az keyvault secret set command to store both the connection string and a randomly generated secret key in Key Vault.

    #!/bin/bash
    ACCOUNT_NAME="msdocs-cosmos-db-account-name"
    
    MONGO_CONNECTION_STRING=$(az cosmosdb keys list \
      --name "$ACCOUNT_NAME" \
      --resource-group "$RESOURCE_GROUP_NAME" \
      --type connection-strings \
      --query "connectionStrings[?description=='Primary MongoDB Connection String'].connectionString" -o tsv)
    
    SECRET_KEY=$(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9')
    # This key is cryptographically secure, using OpenSSL’s strong random number generator.
    
    az keyvault secret set \
      --vault-name "$KEYVAULT_NAME" \
      --name "MongoConnectionString" \
      --value "$MONGO_CONNECTION_STRING"
    
    az keyvault secret set \
      --vault-name "$KEYVAULT_NAME" \
      --name "MongoSecretKey" \
      --value "$SECRET_KEY"
    

Configure web app to use Key Vault secrets

To access secrets securely at runtime, configure the web app to reference the secrets stored in Azure Key Vault. Use Key Vault references to inject the secret values into the app’s environment through its system-assigned managed identity.

This approach avoids hardcoding secrets and allows the app to securely retrieve sensitive values like the MongoDB connection string and secret key during execution.

  1. Use the az webapp config appsettings set command to add application settings that reference the Key Vault secrets. Specifically, set the MongoConnectionString and MongoSecretKey app settings to reference the corresponding secrets stored in Key Vault.

    #!/bin/bash
    MONGODB_NAME="restaurants_reviews"
    MONGODB_COLLECTION_NAME="restaurants_reviews"
    
    az webapp config appsettings set \
      --resource-group "$RESOURCE_GROUP_NAME" \
      --name "$APP_SERVICE_NAME" \
      --settings \
          CONNECTION_STRING="@Microsoft.KeyVault(SecretUri=https://$KEYVAULT_NAME.vault.azure.net/secrets/MongoConnectionString)" \
          SECRET_KEY="@Microsoft.KeyVault(SecretUri=https://$KEYVAULT_NAME.vault.azure.net/secrets/MongoSecretKey)" \
          DB_NAME="$MONGODB_NAME" \
          COLLECTION_NAME="$MONGODB_COLLECTION_NAME"
    

Enable continuous deployment from ACR

When you enable continuous deployment, the web app automatically pulls and runs the latest container image whenever you push one to Azure Container Registry (ACR). This feature reduces manual deployment steps and helps ensure your app stays up to date.

Note

In the next step, you register a webhook in ACR to notify the web app when a new image is pushed.

  1. Use the az webapp deployment container config command to enable continuous deployment from ACR to the web app.

    #!/bin/bash
    az webapp deployment container config \
      --name "$APP_SERVICE_NAME" \
      --resource-group "$RESOURCE_GROUP_NAME" \
      --enable-cd true
    

Register an ACR webhook for continuous deployment

To automate deployments, register a webhook in Azure Container Registry (ACR) that notifies the web app whenever a new container image is pushed. By using the webhook, the app automatically pulls and runs the latest version.

The webhook you configure in Azure Container Registry (ACR) sends a POST request to the web app’s SCM endpoint (SERVICE_URI) whenever a new image is pushed to the msdocspythoncontainerwebapp repository. This action triggers the web app to pull and deploy the updated image, completing the continuous deployment pipeline between ACR and Azure App Service.

Note

The webhook URI must follow this format:
https://<app-name>.scm.azurewebsites.net/api/registry/webhook

It must end with /api/registry/webhook. If you receive a URI error, confirm that the path is correct.

  1. Use the az acr webhook create command to register the webhook and configure it to trigger on push events.

    #!/bin/bash
    CREDENTIAL=$(az webapp deployment list-publishing-credentials \
        --resource-group "$RESOURCE_GROUP_NAME" \
        --name "$APP_SERVICE_NAME" \
        --query publishingPassword --output tsv)
    # Web app publishing credentials may not be available immediately. In production, poll until non-empty.   
    
    SERVICE_URI="https://$APP_SERVICE_NAME:$CREDENTIAL@$APP_SERVICE_NAME.scm.azurewebsites.net/api/registry/webhook"
    
    az acr webhook create \
      --name webhookforwebapp \
      --registry "$REGISTRY_NAME" \
      --scope msdocspythoncontainerwebapp:* \
      --uri "$SERVICE_URI" \
      --actions push
    
    

Browse the site

To verify that the web app is running, open https://<website-name>.azurewebsites.net, replacing <website-name> with the name of your App Service. You should see the restaurant review sample app. It might take a few moments to load the first time.

Once the site appears, try adding a restaurant and submitting a review to confirm that the app is functioning correctly.

Note

The az webapp browse command isn't supported in Cloud Shell. If you're using Cloud Shell, manually open a browser and go to the site URL.

If you're using the Azure CLI locally, use the az webapp browse command to open the site in your default browser:

az webapp browse --name $APP_SERVICE_NAME --resource-group $RESOURCE_GROUP_NAME

Note

The az webapp browse command isn't supported in Cloud Shell. Open a browser window and go to the website URL instead.

Troubleshoot deployment

If you don't see the sample app, try the following steps.

  • For container deployment and App Service, always check the Deployment Center / Logs page in the Azure portal. Confirm that the container is pulled and running. The initial pull and running of the container can take a few moments.
  • Try to restart the App Service and see if that resolves your issue.
  • If there are programming errors, those errors show up in the application logs. On the Azure portal page for the App Service, select Diagnose and solve problems/Application logs.
  • The sample app relies on a connection to Azure Cosmos DB for MongoDB. Confirm that the App Service has application settings with the correct connection info.
  • Confirm that managed identity is enabled for the App Service and is used in the Deployment Center. On the Azure portal page for the App Service, go to the App Service Deployment Center resource and confirm that Authentication is set to Managed Identity.
  • Check that the webhook is defined in the Azure Container Registry. The webhook enables the App Service to pull the container image. In particular, check that Service URI ends with "/api/registry/webhook". If not, add it.
  • Different Azure Container Registry skus have different features, including number of webhooks. If you're reusing an existing registry, you might see the message: "Quota exceeded for resource type webhooks for the registry SKU Basic. Learn more about different SKU quotas and upgrade process: https://aka.ms/acr/tiers". If you see this message, use a new registry, or reduce the number of registry webhooks in use.

Next step