title | description | ms.topic | ms.date | ms.custom |
---|---|---|---|---|
Build and deploy a Python web app with Azure Container Apps |
Describes how to create a container from a Python web app and deploy it to Azure Container Apps, a serverless platform for hosting containerized applications. |
conceptual |
12/15/2024 |
devx-track-python, devx-track-azurecli |
This article is part of a tutorial about how to containerize and deploy a Python web app to Azure Container Apps. Container Apps enables you to deploy containerized apps without managing complex infrastructure.
In this part of the tutorial, you learn how to containerize and deploy a Python sample web app (Django or Flask). Specifically, you build the container image in the cloud and deploy it to Azure Container Apps. You define environment variables that enable the container app to connect to an Azure Database for PostgreSQL - Flexible Server instance, where the sample app stores data.
This service diagram highlights the components covered in this article: building and deploying a container image.
:::image type="content" source="./media/tutorial-container-apps/service-diagram-overview-for-tutorial-deploy-python-azure-container-apps-deploy.png" alt-text="A screenshot of the services in the Tutorial - Deploy a Python App on Azure Container Apps. Section highlighted is what is covered in this article." lightbox="./media/tutorial-container-apps/service-diagram-overview-for-tutorial-deploy-python-azure-container-apps-deploy.png":::
If you don't have an Azure subscription, create a free account before you begin.
Azure CLI commands can be run in the Azure Cloud Shell or on a workstation with the Azure CLI installed.
If you're running locally, follow these steps to sign in and install the necessary modules for this tutorial.
-
Sign in to Azure and authenticate, if needed:
az login
-
Make sure you're running the latest version of the Azure CLI:
az upgrade
-
Install or upgrade the containerapp and rdbms-connect Azure CLI extensions with the az extension add command.
az extension add --name containerapp --upgrade az extension add --name rdbms-connect --upgrade
[!Note] To list the extensions installed on your system, you can use the az extension list command. For example,
az extension list --query [].name --output tsv
Make sure the following extensions are installed:
- Docker extension for VS Code.
- Azure Databases extension for VS Code.
- Azure Container Apps extension for VS Code.
Sign in to the Azure portal.
Fork and clone the sample code to your developer environment.
-
Go to the GitHub repository of the sample app (Django or Flask) and select Fork.
Follow the steps to fork the directory to your GitHub account. You can also download the code repo directly to your local machine without forking or a GitHub account, however, you won't be able to set up CI/CD discussed later in the tutorial.
-
Use the git clone command to clone the forked repo into the python-container folder:
# Django git clone https://github.com/$USERNAME/msdocs-python-django-azure-container-apps.git python-container # Flask # git clone https://github.com/$USERNAME/msdocs-python-flask-azure-container-apps.git python-container
-
Change directory.
cd python-container
After following these steps, you'll have an Azure Container Registry that contains a Docker container image built from the sample code.
-
Create a resource group with the az group create command.
az group create \ --name pythoncontainer-rg \ --location <location>
<location> is one of the Azure location Name values from the output of the command
az account list-locations -o table
. -
Create a container registry with the az acr create command.
az acr create \ --resource-group pythoncontainer-rg \ --name <registry-name> \ --sku Basic \ --admin-enabled
<registry-name> must be unique within Azure, and contain 5-50 alphanumeric characters.
-
Sign in to the registry using the az acr login command.
az acr login --name <registry-name>
The command adds "azurecr.io" to the name to create the fully qualified registry name. If successful, you'll see the message "Login Succeeded". If you're accessing the registry from a subscription different from the one in which the registry was created, use the
--suffix
switch.If sign-in fails, make sure the Docker daemon is running on your system.
-
Build the image with the az acr build command.
az acr build \ --registry <registry-name> \ --resource-group pythoncontainer-rg \ --image pythoncontainer:latest .
Note that:
-
The dot (".") at the end of the command indicates the location of the source code to build. If you aren't running this command in the sample app root directory, specify the path to the code.
-
If you're running the command in Azure Cloud Shell, use
git clone
to first pull the repo into the Cloud Shell environment first and change directory into the root of the project so that dot (".") is interpreted correctly. -
If you leave out the
-t
(same as--image
) option, the command queues a local context build without pushing it to the registry. Building without pushing can be useful to check that the image builds.
-
-
Confirm the container image was created with the az acr repository list command.
az acr repository list --name <registry-name>
These steps require the Docker extension for VS Code.
-
Create an Azure Container Registry.
Start the Create Registry task:
- Select F1 or CTRL+SHIFT+P to open the command palette.
- Type "Azure Container Registry".
- Select the task Azure Container Registry: Create Registry.
:::image type="content" source="media/tutorial-container-apps/visual-studio-code-create-registry.png" alt-text="Screenshot showing how to start creating a new Azure Container Registry in Visual Studio Code." lightbox="media/tutorial-container-apps/visual-studio-code-build-image-01.png":::
Follow the prompts to create a registry and a resource group:
- If you're prompted, select the subscription you want to create resources in for this tutorial.
- Registry name: The registry name must be unique within Azure, and contain 5-50 alphanumeric characters.
- Select a SKU: Select Basic.
- Create a new resource group: Select this option to create the resource group.
- Resource group: Create a new resource group named pythoncontainer-rg.
- Location: Select a location and wait until the notification that indicates the registry has been created.
-
Build the image.
Start the Build Image in Azure task:
- Select F1 or CTRL+SHIFT+P to open the command palette.
- Type "Azure Container Registry".
- Select the task Azure Container Registry: Build Image in Azure.
:::image type="content" source="media/tutorial-container-apps/visual-studio-code-build-image-01.png" alt-text="Screenshot showing how to start building a new container image in an Azure Container Registry with Visual Studio Code." lightbox="media/tutorial-container-apps/visual-studio-code-build-image-01.png":::
Alternatively, you can right-click the Dockerfile and select Build Image in Azure to start the same task to build the image. If you don't see the Build Image Azure task, make sure you're signed into Azure.
Follow the prompts to build the image.
- Tag image as: Enter pythoncontainer:latest.
- Registry provider: Select Azure.
- If you're prompted, select your subscription.
- Registry: Select the Container registry from the list.
- Select OS: Select Linux.
Monitor progress in the Output window and confirm that the image builds successfully. If an error occurs, see the Troubleshooting section.
-
Confirm the registry was created.
Select the Docker extension and to the Registries section. Expand the Azure node to find the new Azure Container Registry.
:::image type="content" source="media/tutorial-container-apps/visual-studio-code-build-image-03.png" alt-text="Screenshot showing how to confirm the Azure Container Registry was created in Visual Studio Code." lightbox="media/tutorial-container-apps/visual-studio-code-build-image-03.png":::
-
Use the az acr update command to enable the administrator user account for the registry. You can run the command in Visual Studio Code terminal window or the Azure Cloud Shell.
az acr update --name <registry-name> \ --resource-group pythoncontainer-rg \ --admin-enabled true
Alternatively, you can select the registry in the Docker extension, right-click, and select Open in Portal. Then you can follow the instructions in the Azure portal tab of this article to enable the administrator user account.
You can view the credentials created for admin with:
az acr credential show \ --name <registry-name> \ --resource-group pythoncontainer-rg
-
In the Azure portal, search for container registry. Under Marketplace in the results, select Container Registry.
-
On the Basics tab, enter the following fields:
- Resource group: Select Create new and enter pythoncontainer-rg.
- Registry name: The registry name must be unique within Azure, and contain 5-50 alphanumeric characters.
- Location: Select a location near you.
- SKU: Select Basic.
:::image type="content" source="media/tutorial-container-apps/azure-portal-build-image-01.png" alt-text="Screenshot showing how to specify a new Azure Container Registry in Azure portal." lightbox="media/tutorial-container-apps/azure-portal-build-image-01.png":::
When finished, select Review + create. After validation is complete, select Create.
-
When deployment completes, select Go to resource. If you miss this notification, you can search container registry and select your registry under Resources in the results.
-
Enable the administrator user account.
- Under Settings on the service menu, select Access Keys.
- Select the Admin user checkbox.
-
Select the Azure Cloud Shell icon in the top menu bar to finish configuration and build an image.
:::image type="content" source="media/tutorial-container-apps/azure-portal-build-image-02.png" alt-text="Screenshot showing how to access Azure Cloud Shell in Azure portal." lightbox="media/tutorial-container-apps/azure-portal-build-image-02.png":::
You can also go directly to Azure Cloud Shell.
-
Use the az acr build command to build the image from the repo.
az acr build --registry <registry-name> \ --resource-group pythoncontainer-rg \ --image pythoncontainer:latest <repo-path>
Specify <registry-name> as the name of the registry you created. For <repo-path>, choose either the Django or Flask repo path.
-
After the command completes, under Services, select Repositories and confirm the image shows up.
Note
The steps in this section create a container registry in the Basic service tier. This tier is cost-optimized, with a feature set and throughput targeted for developer scenarios, and is suitable for the requirements of this tutorial. In production scenarios, you would most likely use either the Standard or Premium service tier. These tiers provide enhanced levels of storage and throughput. To learn more, see Azure Container Registry service tiers. For information about pricing, see Azure Container Registry pricing.
The sample app (Django or Flask) stores restaurant review data in a PostgreSQL database. In these steps, you create the server that will contain the database.
-
Use the az postgres flexible-server create command to create the PostgreSQL server in Azure. It isn't uncommon for this command to run for a few minutes to complete.
az postgres flexible-server create \ --resource-group pythoncontainer-rg \ --name <postgres-server-name> \ --location <location> \ --admin-user demoadmin \ --admin-password <admin-password> \ --active-directory-auth Enabled \ --tier burstable \ --sku-name standard_b1ms \ --public-access 0.0.0.0
-
"pythoncontainer-rg": The resource group name used in this tutorial. If you used a different name, change this value.
-
<postgres-server-name>: The PostgreSQL database server name. This name must be unique across all Azure. The server endpoint is "https://<postgres-server-name>.postgres.database.azure.com". Allowed characters are "A"-"Z", "0"-"9", and "-".
-
<location>: Use the same location used for the web app. <location> is one of the Azure location Name values from the output of the command
az account list-locations -o table
. -
<admin-username>: Username for the administrator account. It can't be "azure_superuser", "admin", "administrator", "root", "guest", or "public". Use "demoadmin" for this tutorial.
-
<admin-password>: Password of the administrator user. It must contain 8 to 128 characters from three of the following categories: English uppercase letters, English lowercase letters, numbers, and non-alphanumeric characters.
[!IMPORTANT] When creating usernames or passwords do not use the "$" character. Later you create environment variables with these values where the "$" character has special meaning within the Linux container used to run Python apps.
-
--active-directory-auth: Specifies whether Microsoft Entra ID authentication is enabled on the PostreSQL server. Set to
Enabled
. -
--sku-name: The name of the pricing tier and compute configuration, for example "Standard_B1ms". For more information, see Azure Database for PostgreSQL pricing. To list available SKUs, use
az postgres flexible-server list-skus --location <location>
. -
--public-access: Use "0.0.0.0", which allows public access to the server from any Azure service, such as Container Apps.
[!NOTE] If you plan on working the PostgreSQL server from your local workstation with tools, you'll need to add a firewall rule for your workstation's IP address with the az postgres flexible-server firewall-rule create command.
-
-
Use the az ad signed-in-user show command to get the object ID of your user account to use in the next command.
az ad signed-in-user show --query id --output tsv
-
Use the az postgres flexible-server ad-admin create command to add your user account as a Microsoft Entra administrator on the PostgreSQL server.
az postgres flexible-server ad-admin create \ --resource-group pythoncontainer-rg \ --server-name <postgres-server-name> \ --display-name <your-email-address> \ --object-id <your-account-object-id>
For your account object ID, use the value you got in the previous step.
These steps require the Azure Databases extension for VS Code.
-
Start the PostgreSQL create task.
- Select F1 or CTRL+SHIFT+P to open the command palette.
- Type "Azure Databases".
- Select the task Azure Databases: Create Server.
:::image type="content" source="media/tutorial-container-apps/visual-studio-code-create-postgres-server-01.png" alt-text="Screenshot showing how to search for the task to create an Azure PostgreSQL Flexible Server instance in Visual Studio Code." lightbox="media/tutorial-container-apps/visual-studio-code-create-postgres-server-01.png":::
Alternatively, you can select the Azure extension, RESOURCES, and expand your subscription. (Make sure you viewing resources by Group by Resource Type.). Then, right-click PostgreSQL servers and select Create server to start the same create server task.
-
A series of prompts guides you through the process of creating the server. Fill in the information as follows.
-
If you're asked to select a subscription, select the subscription you're using for this tutorial.
-
Select an Azure Database Server: Select PostgreSQL Flexible Server.
-
Server name: Specify a name for the server. Enter a name for the database server that's unique across all Azure (the database server's URL becomes
https://<server-name>.postgres.database.azure.com
). Allowed characters areA
-Z
,0
-9
, and-
. For example: postgres-db-<unique-id>. -
Select the Postgres SKU and options: Select the B1ms Basic SKU (1 vCore, 2 GiB Memory, 5-GB storage).
-
Administrator Username: Create an administrator user name. This name for an administrator account on the database server. Use demoadmin for this tutorial.
-
Administrator Password: Create a password for the administrator and confirm it.
-
Select a resource group for new resources: Select a resource group to put the server in. Use the same resource group that you created the container registry in, pythoncontainer-rg.
-
Select a location for new resources: Select the same location as the resource group and container registry.
Monitor progress in the Azure window and confirm that the server is created successfully. If an error occurs, see the Troubleshooting section.
:::image type="content" source="media/tutorial-container-apps/visual-studio-code-create-postgres-server-02.gif" alt-text="Screenshot showing how to complete the task to create an Azure PostgreSQL Flexible Server instance in Visual Studio Code." lightbox="media/tutorial-container-apps/visual-studio-code-create-postgres-server-02.gif":::
-
-
After the server is created, configure access from your local environment to the Azure Database for PostgreSQL server.
First, confirm that the server was created by checking the Azure: Activity Log window. When you're sure the server exists then:
-
Open the Command Palette (F1 or Ctrl + Shift + P).
-
Search for and select PostgreSQL: Configure Firewall. (Select a subscription if prompted.)
-
Select PostgreSQL servers (Flexible), then select the server you created in the previous step. If the server doesn't appear in the list, it's likely it hasn't finished being created.
-
Select Yes in the dialog box to add your IP address to the firewall rules of the PostgreSQL server.
:::image type="content" source="media/tutorial-container-apps/visual-studio-code-create-postgres-server-04.png" alt-text="Screenshot showing how to Confirm adding local workstation IP as firewall rule for Azure PostgreSQL Flexible Server instance in Visual Studio Code." lightbox="media/tutorial-container-apps/visual-studio-code-create-postgres-server-04.png":::
-
-
The following steps require the Azure CLI. If you have the Azure CLI installed locally, you can run them in a terminal prompt; otherwise, open the Azure Cloud Shell in a browser.
-
Use the az postgres flexible-server firewall-rule create command to add a rule to allow your web app to access the PostgreSQL Flexible server. In the following command, you configure the server's firewall to accept connections from all Azure resources.
az postgres flexible-server firewall-rule create \ --name <postgres-server_name> \ --resource-group pythoncontainer-rg \ --rule-name AllowAllAzureServices \ --start-ip-address 0.0.0.0 \ --end-ip-address 0.0.0.0
-
Use the az postgres flexible-server update command to enable Microsoft Entra authentication on the server.
az postgres flexible-server update \ --resource-group pythoncontainer-rg \ --name <postgres-server-name> --active-directory-auth Enabled
-
Use the az ad signed-in-user show command to get the object ID of your user account to use in the next command.
az ad signed-in-user show --query id --output tsv
-
Use the az postgres flexible-server ad-admin create command to add your user account as a Microsoft Entra administrator on the PostgreSQL server.
az postgres flexible-server ad-admin create \ --resource-group pythoncontainer-rg \ --server-name <postgres-server-name> \ --display-name <your-email-address> \ --object-id <your-account-object-id>
For your account object ID, use the value you got in the previous step.
-
In the Azure portal, search for postgresql flexible. Under Marketplace in the results, select Azure Database for PostgreSQL Flexible Server.
-
On the Basics tab, enter the following values:
- Resource group: The resource group used in this tutorial "pythoncontainer-rg".
- Server name: Enter a name for the database server that's unique across Azure. The database server's URL becomes
https://<server-name>.postgres.database.azure.com
. Allowed characters areA
-Z
,0
-9
, and-
. For example: postgres-db-<unique-id>. - Region: The same region you used for the resource group.
- Workload Type: Select Development.
- Authentication Method: Select PostgreSQL and Microsoft Entra authentication.
- Set Microsoft Entra admin: Select Set admin. On the Select Microsoft Entra Admins page, search for your Azure user account, select it in the results, and then click Select.
- Admin username: Use demoadmin.
- Password and Confirm password: A password for the admin account.
:::image type="content" source="media/tutorial-container-apps/azure-portal-create-postgres-server-basics-tab.png" alt-text="Screenshot showing how to specify basic settings of an Azure PostgreSQL Flexible Server instance in Azure portal." lightbox="media/tutorial-container-apps/azure-portal-create-postgres-server-basics-tab.png":::
For all other settings, leave the defaults. When done, select Next: Networking.
-
On the Networking tab, enter the following values:
- Connectivity method: Make sure Public access (allowed IP addresses) and Private endpoint is selected.
- Allow public access to this resource through the internet using a public IP address: Make sure the checkbox is selected.
- Allow public access from any Azure service within Azure to this service: Select the checkbox.
- Add current client IP address: Select (add) if you plan on accessing the database from your local server.
:::image type="content" source="media/tutorial-container-apps/azure-portal-create-postgres-server-networking-tab.png" alt-text="Screenshot showing how to specify networking settings of an Azure PostgreSQL Flexible Server instance in Azure portal." lightbox="media/tutorial-container-apps/azure-portal-create-postgres-server-networking-tab.png":::
For all other settings, leave the defaults. Select Review + Create to continue.
-
Review the settings and, when satisfied, select Create.
Note
The steps in this section create a PostgreSQL server with a single vCore and limited memory in the Burstable pricing tier. The Burstable tier is a lower cost option for workloads that don't need the full CPU continuously, and is suitable for the requirements of this tutorial. For production workloads, you might upgrade to either the General Purpose or Memory Optimized pricing tier. These tiers provide higher performance, but increase costs. To learn more, see Compute options in Azure Database for PostgreSQL - Flexible Server. For information about pricing, see Azure Database for PostgreSQL pricing.
At this point, you have a PostgreSQL server. In this section, you create a database on the server.
Use the az postgres flexible-server db create command to create a database named restaurants_reviews.
az postgres flexible-server db create \
--resource-group pythoncontainer-rg \
--server-name <postgres-server-name> \
--database-name restaurants_reviews
Where:
- "pythoncontainer-rg": The resource group name used in this tutorial. If you used a different name, change this value.
<postgres-server-name>
: The name of the PostgreSQL server.
You could also use the az postgres flexible-server connect command to connect to the database and then work with psql commands. When working with psql, it's often easier to use the Azure Cloud Shell because all the dependencies are included for you in the shell.
These steps require the Azure Databases extension for VS Code.
-
In the Azure extension, find the PostgreSQL Server you created, right-click it, and select Create Database.
-
At the prompt, enter restaurants_reviews as the Database Name.
If you have trouble creating the database, the server might still be processing the firewall rule from the previous step. Wait a moment and try again. If you're prompted to enter credentials to access the database, use the "demoadmin" username, and password you entered when you created the database.
- In the Azure portal, navigate to your PostgreSQL server. For example, you can enter the name of your PostgreSQL server in the search bar and select it under Resources in the results.
- Under Settings on the service menu, select Databases.
- Select Add on the top menu of the Databases page.
- On the Create Database page, enter restaurants_reviews for the Name, then select Save.
- When the operation completes, you're returned to the Databases page. Verify that restaurants_reviews appears in the list of databases. You might need to refresh the page for it to appear.
You can also connect to Azure PostgreSQL Flexible server and create a database using psql or an IDE that supports PostgreSQL like Azure Data Studio. For steps using psql, see Configure the managed identity on the postgresql database.
Create a user-assigned managed identity. This managed identity will be used as the identity for the container app when running in Azure.
Note
To create a user-assigned managed identity, your account needs the Managed Identity Contributor role assignment.
Use the az identity create command to create a user-assigned managed identity.
az identity create --name my-ua-managed-id --resource-group pythoncontainer-rg
There isn't currently a VS Code extension that supports creating user-assigned managed identities. Follow the steps for Azure CLI or the Azure portal.
-
In the Azure portal, search for managed identity. Under Marketplace in the results, select User Assigned Managed Identity.
-
On the Basics tab, enter the following values:
- Subscription: Choose the subscription you're using for the resources in this tutorial.
- Resource group: Enter the resource group for this tutorial; pythoncontainer-rg.
- Region: Choose the region you're using for the resources in this tutorial.
- Name: Enter the name for your user-assigned managed identity. For this tutorial, use: my-ua-managed-id. You can use a different name, but the commands in this tutorial assume my-ua-managed-id. If you use a different name, you'll have to change it in other commands.
:::image type="content" source="media/tutorial-container-apps/create-user-assigned-managed-identity-portal.png" alt-text="Screenshot that shows the Create User Assigned Managed Identity pane." lightbox="media/tutorial-container-apps/create-user-assigned-managed-identity-portal.png":::
-
Select Review + create to review the changes.
-
Select Create.
Configure the managed identity as a role on the PostgreSQL server and then grant it necessary permissions for the restaurants_reviews database. Whether using the Azure CLI or psql, you must connect to the Azure PostgreSQL server with a user that is configured as a Microsoft Entra admin on your server instance. Only Microsoft Entra accounts configured as a PostreSQL admin can configure managed identities and other Microsoft Admin roles on your server.
-
Get an access token for your Azure account with the az account get-access-token command. You use the access token in the following steps.
az account get-access-token --resource-type oss-rdbms --output tsv --query accessToken
The returned token is long. Set its value in an environment variable to use in the commands in the following step:
MY_ACCESS_TOKEN=<your-access-token>
-
Add the user-assigned managed identity as database role on your PostgreSQL server with the az postgres flexible-server execute command.
az postgres flexible-server execute \ --name <postgres-server-name> \ --database-name postgres \ --querytext "select * from pgaadauth_create_principal('"my-ua-managed-id"', false, false);select * from pgaadauth_list_principals(false);" \ --admin-user <your-Azure-account-email> \ --admin-password $MY_ACCESS_TOKEN
-
If you used a different name for your managed identity, replace
my-ua-managed-id
in thepgaadauth_create_principal
command with the name of your managed identity. -
For the
--admin-user
value, use your Azure account email address. -
For the
--admin-password
value, use the access token output by the previous command, unquoted. -
Make sure the database name is
postgres
.
[!NOTE] If you're running the az postgres flexible-server execute command on your local workstation, make sure you've added a firewall rule for your workstation's IP address. You can add a rule with the az postgres flexible-server firewall-rule create command. The same requirement also exists for the command in the next step.
-
-
Grant the user-assigned managed identity necessary permissions on the restaurants_reviews database with the following az postgres flexible-server execute command.
az postgres flexible-server execute \ --name <postgres-server-name> \ --database-name restaurants_reviews \ --querytext "GRANT CONNECT ON DATABASE restaurants_reviews TO \"my-ua-managed-id\";GRANT USAGE ON SCHEMA public TO \"my-ua-managed-id\";GRANT CREATE ON SCHEMA public TO \"my-ua-managed-id\";GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO \"my-ua-managed-id\";ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO \"my-ua-managed-id\";" \ --admin-user <your-Azure-account-email> \ --admin-password $MY_ACCESS_TOKEN
-
If you used a different name for your managed identity, replace all instances of
my-ua-managed-id
in the command with the name of your managed identity. There are five instances in the query string. -
For the
--admin-user
value, use your Azure account email address. -
For the
--admin-password
value, use the access token output previously, unquoted. -
Make sure the database name is
restaurants_reviews
.
The Azure CLI command above connects to the restaurants_reviews database on the server and issues the following SQL commands:
GRANT CONNECT ON DATABASE restaurants_reviews TO "my-ua-managed-id"; GRANT USAGE ON SCHEMA public TO "my-ua-managed-id"; GRANT CREATE ON SCHEMA public TO "my-ua-managed-id"; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "my-ua-managed-id"; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "my-ua-managed-id";
-
You can use the PostgreSQL interactive terminal psql in your local environment, or in the Azure Cloud Shell, which is also accessible in the Azure portal. When working with psql, it's often easier to use the Cloud Shell because all the dependencies are included for you in the shell.
-
Connect to the database with psql with an Azure account previously configured as a Microsoft Entra admin on your server. If you've been following the steps in this tutorial, your Azure account is already configured as an admin on the server.
psql --host=<postgres-server-name>.postgres.database.azure.com \ --port=5432 \ --username=<your-azure-email-address> \ --dbname=postgres \ --set sslmode=require
Where <postgres-server-name> is the name of the PostgreSQL server and <your-azure-email-address> is the email address of your Azure account. The command prompts you for your Azure account password.
If you're working in Azure Cloud Shell or if you have the Azure CLI installed on your local system, you can use the az account get-access-token command to get an access token that you can copy and enter as the password.
az account get-access-token --resource-type oss-rdbms --output tsv --query accessToken
Or, you can combine the psql and Azure CLI commands:
psql "host=<postgres-server-name>.postgres.database.azure.com port=5432 dbname=postgres user=<your-azure-email-address> password='$(az account get-access-token --resource-type oss-rdbms --output tsv --query accessToken)' sslmode=require"
Be sure to replace the <postgres-server-name> and <your-azure-email-address> placeholders before running the command.
If you have trouble connecting, restart the database and try again. If you're connecting from your local environment, your IP address must be added to the firewall rule list for the database service.
-
Add the user-assigned managed identity as database role on your PostgreSQL server.
At the
postgres=>
prompt enter:SELECT * FROM pgaadauth_create_principal('my-ua-managed-id', false, false);SELECT * FROM pgaadauth_list_principals(false);
The semicolon (";") at the end of each command is necessary. To verify that the database was successfully created, use the command
\c restaurants_reviews
. Type\?
to show help or\q
to quit. -
Connect to the restaurants_reviews database using the
\c
(Connect) command.\c restaurants_reviews
[!NOTE] If you haven't yet created the restaurants_reviews database, you can do so with the following command:
CREATE DATABASE resaurants_reviews
-
Grant the user-assigned managed identity necessary permissions on the restaurants_reviews database.
At the
restaurants_reviews_=>
prompt, enter the following commands:GRANT CONNECT ON DATABASE restaurants_reviews TO "my-ua-managed-id"; GRANT USAGE ON SCHEMA public TO "my-ua-managed-id"; GRANT CREATE ON SCHEMA public TO "my-ua-managed-id"; GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "my-ua-managed-id"; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "my-ua-managed-id";
-
Quit psql using the
\q
command:\q
Container apps are deployed to Container Apps environments, which act as a secure boundary. In the following steps, you create the environment, a container inside the environment, and configure the container so that the website is visible externally.
These steps require the Azure Container Apps extension, containerapp.
-
Create a Container Apps environment with the az containerapp env create command.
az containerapp env create \ --name python-container-env \ --resource-group pythoncontainer-rg \ --location <location>
<location> is one of the Azure location Name values from the output of the command
az account list-locations -o table
. -
Get the sign-in credentials for the Azure Container Registry with the az acr credential show command.
az acr credential show -n <registry-name>
You use the username and one of the passwords returned from the output of the command when you create the container app in step 5.
-
Use the az identity show command to get the client ID and resource ID of the user-assigned managed identity.
az identity show --name my-ua-managed-id --resource-group pythoncontainer-rg --query "[clientId, id]" --output tsv
You use the value of the client ID (GUID) and the resource ID output by the command when you create the container app in step 5. The resource ID has the following form:
/subscriptions/<subscription-id>/resourcegroups/pythoncontainer-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/my-ua-managed-id
-
Run the following command to generate a secret key value.
python -c 'import secrets; print(secrets.token_hex())'
You use the secret key value to set an environment variable when you create the container app in step 5.
[!NOTE] The command shown is for a bash shell. Depending on your environment, you might need to invoke python using
python3
. On Windows, you need to enclose the command in the-c
parameter in double quotes, rather than single quotes. You also might need to invoke python usingpy
orpy -3
depending on your environment. -
Create a container app in the environment with the az containerapp create command.
az containerapp create \ --name python-container-app \ --resource-group pythoncontainer-rg \ --image <registry-name>.azurecr.io/pythoncontainer:latest \ --environment python-container-env \ --ingress external \ --target-port <5000 for Flask or 8000 for Django> \ --registry-server <registry-name>.azurecr.io \ --registry-username <registry-username> \ --registry-password <registry-password> \ --user-assigned <managed-identity-resource-id> \ --query properties.configuration.ingress.fqdn \ --env-vars DBHOST="<postgres-server-name>" \ DBNAME="restaurants_reviews" \ DBUSER="my-ua-managed-id" \ RUNNING_IN_PRODUCTION="1" \ AZURE_CLIENT_ID="<managed-identity-client-id>" \ AZURE_SECRET_KEY="<your-secret-key>"
Make sure you replace all of the values in angle brackets with values you're using in this tutorial. Be aware that the name of your container app must be unique across Azure.
The value of the
--env-vars
parameter is a string composed of space-separated values in the key="value" format with the following values:- DBHOST="<postgres-server-name>"
- DBNAME="restaurants_reviews"
- DBUSER="my-ua-managed-id"
- RUNNING_IN_PRODUCTION="1"
- AZURE_CLIENT_ID="<managed-identity-client-id>"
- AZURE_SECRET_KEY="<your-secret-key>"
The value for
DBUSER
is the name of your user-assigned managed identity.The value for
AZURE_CLIENT_ID
is the client ID of your user-assigned managed identity. You got this value in a previous step.The value for
AZURE_SECRET_KEY
is the secret key value you generated in a previous step. -
For Django only, migrate and create database schema. (In the Flask sample app, it's done automatically, and you can skip this step.)
Connect with the az containerapp exec command:
az containerapp exec \ --name python-container-app \ --resource-group pythoncontainer-rg
Then, at the shell command prompt type
python manage.py migrate
.You don't need to migrate for revisions of the container.
-
Test the website.
The
az containerapp create
command you entered previously outputs an application URL you can use to browse to the app. The URL ends in "azurecontainerapps.io". Navigate to the URL in a browser. Alternatively, you can use the az containerapp browse command.
These steps require the Azure Container Apps extension for VS Code.
-
Get values you need for environment variables:
-
Open a terminal in VS Code and enter the following commands. You can also enter the commands from Azure Cloud Shell.
-
Get the client ID of the managed identity with the az identity show command.
az identity show --name my-ua-managed-id --resource-group pythoncontainer-rg --query clientId -o tsv
The client ID is a GUID. You use it to set an environment variable in the next step.
-
Generate a secret key value:
python -c 'import secrets; print(secrets.token_hex())'
You use the secret key value to set an environment variable in the next step.
[!NOTE] The command shown is for a bash shell. Depending on your environment, you might need to invoke python using
python3
. On Windows, you need to enclose the command in the-c
parameter in double quotes, rather than single quotes. You also might need to invoke python usingpy
orpy -3
.
-
-
Create an .env file that you'll reference during the creation of the container app.
In the sample repo, there's an .env.example file you can start from. Create the .env file with the following values:
DBHOST="<postgres-server-name>" DBNAME="restaurants_reviews" DBUSER="my-ua-managed-id" RUNNING_IN_PRODUCTION="1" AZURE_CLIENT_ID="<managed-identity-client-id>" AZURE_SECRET_KEY="<your-secret-key>"
The
DBUSER
value is the name of your user-assigned managed identity.The
AZURE_CLIENT_ID
value is the client ID of your user-assigned managed identity. You got it in the previous step.The
AZURE_SECRET_KEY
value is the secret key value you generated in the previous step. -
Create a container apps environment.
Start the container apps environment create task:
- Select F1 or CTRL+SHIFT+P to open the command palette.
- Type "container apps".
- Select the task Azure Container Apps: Create Container Apps Environment
Alternatively, you can open the Azure extension and select + icon in the Resources section.
Follow the prompts to create the container app environment:
- If you're prompted, select your subscription.
- Enter a container apps environment name: Enter "python-container-env".
- Select a location for new resources: Choose the same location that resource group you created previously.
It takes several minutes to create the environment. A notification shows the progress of the operation. Look for "Successfully created new Container Apps environment" before going to the next step. The environment is created in a resource group of the same name "python-container-env".
:::image type="content" source="media/tutorial-container-apps/visual-studio-code-create-container-app-02.gif" alt-text="Screenshot showing how to create an environment for Azure Container Apps in Visual Studio Code." lightbox="media/tutorial-container-apps/visual-studio-code-create-container-app-02.gif":::
-
After the environment is created, create a container app in it. by finding the Azure Container Apps: Create Container App task in the command palette.
Start the container app create task:
- Select F1 or CTRL+SHIFT+P to open the command palette.
- Type "container apps".
- Select the task Azure Container Apps: Create Container App
Alternatively, you can go to the Azure extension, Container Apps section, select the environment, right-click, and select Create Container App to start the create container app task.
Follow the prompts to create the container app:
- Select subscription: Select the subscription you're using for this tutorial.
- Select a container apps environment: Select the environment created in the previous step.
- Enter a container app name: Enter python-container-app.
- Select an image source for the container app: Select Container Registry.
- Select a container registry: Select Azure Container Registry.
- Select an Azure Container Registry: Select the name of the registry you created previously.
- Select a repository: Select pythoncontainer.
- Select a tag: Select latest.
- Select a .env file to set the environment variables for the container instance: Select the .env file you created in step two.
- Enable ingress for applications that need an HTTP endpoint: Select Enable.
- Select the HTTP traffic that the endpoint will accept: Select External.
- Port the container is listening on: Set to 8000 (Django) or 5000 (Flask).
:::image type="content" source="media/tutorial-container-apps/visual-studio-code-create-container-app-03.gif" alt-text="Screenshot showing how to create an Azure Container app in an environment in Visual Studio Code." lightbox="media/tutorial-container-apps/visual-studio-code-create-container-app-03.gif":::
A notification shows the progress of the operation. Look for "Successfully created new Container App environment" before going to the next step. The container app is created in the same resource group as the container app environment "python-container-env".
-
After the container app is created, configure the user-assigned managed identity on it.
-
Open a terminal in VS Code and enter the following Azure CLI commands. You can also enter the commands from Azure Cloud Shell.
-
Get the resource ID of the managed identity.
az identity show --name my-ua-managed-id --resource-group pythoncontainer-rg --query id -o tsv
The resource ID has the following form: /subscriptions/<subscription ID>/resourcegroups/pythoncontainer-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/my-ua-managed-id
-
Assign the managed identity to the container app with the az containerapp identity assign command.
az containerapp identity assign \ --name python-container-app \ --resource-group container-app-environment \ --user-assigned <managed-identity-resource-id>
Replace the
<managed-identity-resource-id>
placeholder with the resource ID output by the previous command.The resource group in this commmand is the same resource group that the container apps environment and container app were created in, python-container-app.
-
-
For Django only, migrate and create database schema. (In the Flask sample app, it's done automatically, and you can skip this step.)
- Go to the Azure extension, expand the Container Apps section, find and expand your container environment, and right-click the container app you created and select Open Console in Portal.
- Choose a startup command and select Connect.
- At the shell prompt, type
python manage.py migrate
.
You don't need to migrate for revisions of the container.
:::image type="content" source="media/tutorial-container-apps/azure-portal-create-container-app-11.png" alt-text="Screenshot showing how to connect to an Azure Container Apps container in Azure portal." lightbox="media/tutorial-container-apps/azure-portal-create-container-app-11.png":::
-
Test the website.
After the create container task completes, you'll see a notification with a Browse button to go to the website.
:::image type="content" source="media/tutorial-container-apps/visual-studio-code-create-container-app-04.png" alt-text="Screenshot showing how to browse to an Azure Container app after it's created in Visual Studio Code." lightbox="media/tutorial-container-apps/visual-studio-code-create-container-app-04.png":::
If you miss the notification, go to the Azure extension, expand the Container Apps section, find and expand your container environment, and right-click the container app and select Browse. You can also enter the Azure Container Apps: Browse task in the command palette and follow the prompts.
-
Get the client ID for the user-assigned managed identity. You use it in a later step.
- In the Azure portal, search for my-ua-managed-id and select it under Resources in the results.
- Select Overview on the service menu and note down the Client ID value.
-
Open Azure Cloud Shell and enter the following command to get a secret key value.
python -c 'import secrets; print(secrets.token_hex())'
You use the secret key value to set an environment variable in a later step.
-
In the portal, search for container apps. Under Marketplace in the results, select Container App.
-
On the Basics tab, enter the following values:
- Resource group: Use the group created previously that contains the Azure Container Registry.
- Container app name: python-container-app.
- Deployment source: Make sure that Container image is selected.
- Region: Use the same region/location as the resource group.
- Container Apps Environment: Select Create new to create a new environment named python-container-env.
:::image type="content" source="media/tutorial-container-apps/azure-portal-create-containerapp-basics-tab.png" alt-text="Screenshot showing how to configure basic settings for an Azure Container Apps service in Azure portal." lightbox="media/tutorial-container-apps/azure-portal-create-containerapp-basics-tab.png":::
Select Next: Container to continue configuration.
-
On the Container tab, continue configuring the container app.
- Use quickstart image: Make sure the checkbox is not selected.
- Image source: Make sure Azure Container Registry is selected.
- Registry: Select the name of registry you created earlier.
- Image name: Select pythoncontainer (the name of the image you built).
- Image tag: Select latest.
Under Environment variables, enter values for the following variables:
- DBHOST="<postgres-server-name>"
- DBNAME="restaurants_reviews"
- DBUSER="my-ua-managed-id"
- RUNNING_IN_PRODUCTION="1"
- AZURE_CLIENT_ID="<managed-identity-client-id>"
- AZURE_SECRET_KEY="<your-secret-key>"
For
AZURE_CLIENT_ID
, use the client ID you copied for the user-assigned managed identity.For
AZURE_SECRET_KEY
, use the secret key value you generated in a previous step.:::image type="content" source="media/tutorial-container-apps/azure-portal-create-containerapp-container-tab.png" alt-text="Screenshot showing how to the configure container settings for an Azure Container Apps service in Azure portal." lightbox="media/tutorial-container-apps/azure-portal-create-containerapp-container-tab.png":::
Select Next: Ingress to continue.
-
Under the Ingress tab, continue configuring the container app.
- Ingress: Select the Enabled checkbox. More selections appear.
- Ingress traffic: Select Accepting traffic from anywhere.
- Target port: Set to 8000 for Django or 5000 for Flask.
:::image type="content" source="media/tutorial-container-apps/azure-portal-create-containerapp-ingress-tab.png" alt-text="Screenshot showing how to the configure ingress settings for an Azure Container Apps service in Azure portal." lightbox="media/tutorial-container-apps/azure-portal-create-containerapp-ingress-tab.png":::
Select Review and create to go to review page. After reviewing the settings, select Create to kick off deployment.
-
After the deployment finishes, select Go to resource.
-
Add the user-assigned managed identity to the container app.
- Under Settings on the service menu, select Identity, then select the User assigned tab.
- Under the User assigned tab, select Add.
- On the Add user assigned managed identity page, select my-ua-managed-identity then select Add.
- When the operation completes, you're returned to the User assigned tab. Verify that my-ua-managed-id appears in the list of identities.
[!TIP] Instead of adding the managed identity and defining environment variables, you can use Service Connector. Service Connector helps you connect to Azure compute services to other backing services by configuring connection information and generating and storing environment variables for you. If you use a service connector, make sure you synchronize the environment variables in the sample code to the environment variables created with Service Connector.
-
Django only, migrate and create database schema. (In the Flask sample app, it's done automatically, and you can skip this step.)
- Under Monitoring on the service menu, select Console.
- Choose a startup command and select Connect.
- At the shell prompt, type
python manage.py migrate
.
You don't need to migrate for revisions of the container.
:::image type="content" source="media/tutorial-container-apps/azure-portal-create-container-app-11.png" alt-text="Screenshot showing how to connect to an Azure Container Apps container in Azure portal." lightbox="media/tutorial-container-apps/azure-portal-create-container-app-11.png":::
-
Test the website.
- Select Overview on the service menu.
- Under Essentials, select Application Url to open the website in a browser.
:::image type="content" source="media/tutorial-container-apps/azure-portal-create-container-app-10.png" alt-text="Screenshot showing how to find the website Url of an Azure Container Apps container in Azure portal." lightbox="media/tutorial-container-apps/azure-portal-create-container-app-10.png":::
Here's an example of the sample website after adding a restaurant and two reviews.
:::image type="content" source="media/tutorial-container-apps/final-website-example-400px.png" alt-text="Screenshot showing an example of the sample website built in this tutorial." lightbox="media/tutorial-container-apps/final-website-example.png":::
-
You forgot the Application Url to access the website.
- In the Azure portal, go to the Overview page of the Container App and look for the Application Url.
- In VS Code, go to the Azure view (Ctrl+Shift+A) and expand the subscription that you're working in. Expand the Container Apps node, then expand the managed environment and right-click python-container-app and select Browse. It opens the browser with the Application Url.
- With Azure CLI, use the command
az containerapp show -g pythoncontainer-rg -n python-container-app --query properties.configuration.ingress.fqdn
.
-
In VS Code, the Build Image in Azure task returns an error.
- If you see the message "Error: failed to download context. Please check if the URL is incorrect." in the VS Code Output window, then refresh the registry in the Docker extension. To refresh, select the Docker extension, go to the Registries section, find the registry, and select it.
- If you run the Build Image in Azure task again, check to see if your registry from a previous run exists and if so, use it.
-
In the Azure portal during the creation of a Container App, you see an access error that contains "Cannot access ACR '<name>.azurecr.io'".
- This error occurs when admin credentials on the ACR are disabled. To check admin status in the portal, go to your Azure Container Registry, select the Access keys resource, and ensure that Admin user is enabled.
-
Your container image doesn't appear in the Azure Container Registry.
- Check the output of the Azure CLI command or VS Code Output and look for messages to confirm success.
- Check that the name of the registry was specified correctly in your build command with the Azure CLI or in the VS Code task prompts.
- Make sure your credentials aren't expired. For example, in VS Code, find the target registry in the Docker extension and refresh. In Azure CLI, run
az login
.
-
Website returns "Bad Request (400)".
- Check the PostgreSQL environment variables passed in to the container. The 400 error often indicates that the Python code can't connect to the PostgreSQL instance.
- The sample code used in this tutorial checks for the existence of the container environment variable
RUNNING_IN_PRODUCTION
, which can be set to any value like "1".
-
Website returns "Not Found (404)".
- Check the Application Url on the Overview page for the container. If the Application Url contains the word "internal", then ingress isn't set correctly.
- Check the ingress of the container. For example, in Azure portal, go to the Ingress resource of the container and make sure HTTP Ingress is enabled and Accepting traffic from anywhere is selected.
-
Website doesn't start, you see "stream timeout", or nothing is returned.
- Check the logs.
- In the Azure portal, go to the Container App's Revision management resource and check the Provision Status of the container.
- If "Provisioning", then wait until provisioning has completed.
- If "Failed", then select the revision and view the console logs. Choose the order of the columns to show "Time Generated", "Stream_s", and "Log_s". Sort the logs by most-recent first and look for Python stderr and stdout messages in the "Stream_s" column. Python 'print' output will be stdout messages.
- With the Azure CLI, use the az containerapp logs show command.
- In the Azure portal, go to the Container App's Revision management resource and check the Provision Status of the container.
- If using the Django framework, check to see if the restaurants_reviews tables exist in the database. If not, use a console to access the container and run
python manage.py migrate
.
- Check the logs.
[!div class="nextstepaction"] Configure continuous deployment