Example: Use the Azure libraries to create and deploy a web app

This example demonstrates how to use the Azure SDK management libraries in a Python script to create and deploy a web app to Azure App Service. The app code is deployed from a GitHub repository.

With the management libraries (namespaces beginning with azure-mgmt, for example, azure-mgmt-web), you can write configuration and deployment programs to perform the same tasks that you can through the Azure portal, Azure CLI, or other resource management tools. For examples, see Quickstart: Deploy a Python (Django or Flask) web app to Azure App Service. (Equivalent Azure CLI commands are given at later in this article.)

All the commands in this article work the same in Linux/macOS bash and Windows command shells unless noted.

1: Set up your local development environment

If you haven't already, set up an environment where you can run this code. Here are some options:

2: Install the required Azure library packages

Create a file named requirements.txt with the following contents:

azure-mgmt-resource
azure-mgmt-web
azure-identity

In a terminal or command prompt with the virtual environment activated, install the requirements:

pip install -r requirements.txt

3: Fork the sample repository

Visit https://github.com/Azure-Samples/python-docs-hello-world and fork the repository into your own GitHub account. You'll use a fork to ensure that you have permissions to deploy the repository to Azure.

Forking the sample repository on GitHub

Then create an environment variable named REPO_URL with the URL of your fork. The example code in the next section depends on this environment variable:

set REPO_URL=<url_of_your_fork>
set AZURE_SUBSCRIPTION_ID=<subscription_id>

4: Write code to create and deploy a web app

Create a Python file named provision_deploy_web_app.py with the following code. The comments explain the details of the code. Be sure to define the REPO_URL and AZURE_SUBSCRIPTION_ID environment variables before running the script.

import random, os
from azure.identity import AzureCliCredential
from azure.mgmt.resource import ResourceManagementClient
from azure.mgmt.web import WebSiteManagementClient

# Acquire a credential object using CLI-based authentication.
credential = AzureCliCredential()

# Retrieve subscription ID from environment variable
subscription_id = os.environ["AZURE_SUBSCRIPTION_ID"]

# Constants we need in multiple places: the resource group name and the region
# in which we provision resources. You can change these values however you want.
RESOURCE_GROUP_NAME = 'PythonAzureExample-WebApp-rg'
LOCATION = "centralus"

# Step 1: Provision the resource group.
resource_client = ResourceManagementClient(credential, subscription_id)

rg_result = resource_client.resource_groups.create_or_update(RESOURCE_GROUP_NAME,
    { "location": LOCATION })

print(f"Provisioned resource group {rg_result.name}")

# For details on the previous code, see Example: Provision a resource group
# at https://docs.microsoft.com/azure/developer/python/azure-sdk-example-resource-group


#Step 2: Provision the App Service plan, which defines the underlying VM for the web app.

# Names for the App Service plan and App Service. We use a random number with the
# latter to create a reasonably unique name. If you've already provisioned a
# web app and need to re-run the script, set the WEB_APP_NAME environment 
# variable to that name instead.
SERVICE_PLAN_NAME = 'PythonAzureExample-WebApp-plan'
WEB_APP_NAME = os.environ.get("WEB_APP_NAME", f"PythonAzureExample-WebApp-{random.randint(1,100000):05}")

# Obtain the client object
app_service_client = WebSiteManagementClient(credential, subscription_id)

# Provision the plan; Linux is the default
poller = app_service_client.app_service_plans.begin_create_or_update(RESOURCE_GROUP_NAME,
    SERVICE_PLAN_NAME,
    {
        "location": LOCATION,
        "reserved": True,
        "sku" : {"name" : "B1"}
    }
)

plan_result = poller.result()

print(f"Provisioned App Service plan {plan_result.name}")


# Step 3: With the plan in place, provision the web app itself, which is the process that can host
# whatever code we want to deploy to it.

poller = app_service_client.web_apps.begin_create_or_update(RESOURCE_GROUP_NAME,
    WEB_APP_NAME,
    {
        "location": LOCATION,
        "server_farm_id": plan_result.id,
        "site_config": {
            "linux_fx_version": "python|3.8"
        }
    }
)

web_app_result = poller.result()

print(f"Provisioned web app {web_app_result.name} at {web_app_result.default_host_name}")

# Step 4: deploy code from a GitHub repository. For Python code, App Service on Linux runs
# the code inside a container that makes certain assumptions about the structure of the code.
# For more information, see How to configure Python apps,
# https://docs.microsoft.com/azure/app-service/containers/how-to-configure-python.
#
# The create_or_update_source_control method doesn't provision a web app. It only sets the
# source control configuration for the app. In this case we're simply pointing to
# a GitHub repository.
#
# You can call this method again to change the repo.

REPO_URL = os.environ["REPO_URL"]

poller = app_service_client.web_apps.begin_create_or_update_source_control(RESOURCE_GROUP_NAME,
    WEB_APP_NAME, 
    { 
        "location": "GitHub",
        "repo_url": REPO_URL,
        "branch": "master",
        "is_manual_integration": True
    }
)

sc_result = poller.result()

print(f"Set source control on web app to {sc_result.branch} branch of {sc_result.repo_url}")

# Step 5: Deploy the code using the repository and branch configured in the previous step.
#
# If you push subsequent code changes to the repo and branch, you must call this method again
# or use another Azure tool like the Azure CLI or Azure portal to redeploy. 
# Note: By default, the method returns None.

app_service_client.web_apps.sync_repository(RESOURCE_GROUP_NAME, WEB_APP_NAME)

print(f"Deploy code")

This code uses CLI-based authentication (using AzureCliCredential) because it demonstrates actions that you might otherwise do with the Azure CLI directly. In both cases, you're using the same identity for authentication. Depending on your environment, you might need to run az login first to authenticate.

To use such code in a production script (for example, to automate VM management), use DefaultAzureCredential (recommended) with a service principal based method as described in How to authenticate Python apps with Azure services.

5: Run the script

python provision_deploy_web_app.py

6: Verify the web app deployment

Visit the deployed web site by running the following command:

az webapp browse --name PythonAzureExample-WebApp-12345 --resource-group PythonAzureExample-WebApp-rg

Replace the web app name (--name option) and resource group name (--resource-group option) with the values you used in the script. You should see "Hello, World!" in the browser.

If you don't see the expected output, wait a few minutes and try again.

If you still don't see the expected output, then:

  1. Go to the Azure portal.
  2. Select Resource groups, and find the resource group you created.
  3. Select the resource group name to view the resources it contains. Specifically, verify that there's an App Service Plan and the App Service.
  4. Select the App Service, and then select Deployment Center.
  5. Select the logs tab to view deployment logs.

7: Redeploy the web app code (optional)

The script sets up the resources needed to host your web app and sets the deployment source to your fork using manual integration. With manual integration, you must trigger the web app to pull from the configured repository and branch.

The script calls the WebSiteManagementClient.web_apps.sync_repository method to trigger a pull from the web app. If you push subsequent code changes to your repository, you can redeploy your code by invoking this API or by using other Azure tooling like the Azure CLI or Azure portal.

You can deploy your code with the Azure CLI by running the az webapp deployment source sync command:

az webapp deployment source sync --name PythonAzureExample-WebApp-12345 --resource-group PythonAzureExample-WebApp-rg

Replace the web app name (--name option) and resource group name (--resource-group option) with the values you used in the script.

To deploy your code from Azure portal:

  1. Go to the Azure portal.
  2. Select Resource groups, and find the resource group you created.
  3. Select the resource group name to view the resources it contains. Specifically, verify that there's an App Service Plan and the App Service.
  4. Select the App Service, and then select Deployment Center.
  5. On the top menu, select Sync to deploy your code.

8: Clean up resources

az group delete --name PythonAzureExample-WebApp-rg --no-wait

Run the az group delete command if you don't need to keep the resource group created in this example. Resource groups don't incur any ongoing charges in your subscription, but it's a good practice to clean up any group that you aren't actively using. The --no-wait argument allows the command to return immediately instead of waiting for the operation to finish.

You can also use the ResourceManagementClient.resource_groups.begin_delete method to delete a resource group from code.

For reference: equivalent Azure CLI commands

The following Azure CLI commands complete the same provisioning steps as the Python script:

rem Replace <your_github_user_name> with the account name of the fork.

set repoUrl=https://github.com/<your_github_user_name>/python-docs-hello-world
set appName=PythonAzureExample-WebApp-%random%

az group create -l centralus -n PythonAzureExample-WebApp-rg

az appservice plan create -n PythonAzureExample-WebApp-plan -g PythonAzureExample-WebApp-rg ^
     --is-linux --sku F1

echo Creating app: %appName%

az webapp create -g PythonAzureExample-WebApp-rg -n %appName% ^
    --plan PythonAzureExample-WebApp-plan --runtime "python|3.8"

rem You can use --deployment-source-url with the first create command. It is shown here
rem to match the sequence of the Python code.

az webapp create -n %appName% -g PythonAzureExample-WebApp-rg ^
    --plan PythonAzureExample-WebApp-plan --runtime "python|3.8" ^
    --deployment-source-url %repoUrl% 

rem The previous command sets up External Git deployment from the specified repository. This 
rem command triggers a pull from the repository.

az webapp deployment source sync --name %appName% --resource-group PythonAzureExample-WebApp-rg

See also