With Azure Developer CLI installed, you can deploy a fully configured sample app shown in this tutorial and see it running in Azure. Just running the following commands in an empty working directory:
azd auth login
azd init --template msdocs-flask-postgresql-sample-app
azd up
With Azure Developer CLI installed, you can skip to the end of the tutorial by running the following commands in an empty working directory:
azd auth login
azd init --template msdocs-django-postgresql-sample-app
azd up
Sample application
Sample Python applications using the Flask and Django framework are provided to help you follow along with this tutorial. To deploy them without running them locally, skip this part.
To run the application locally, make sure you have Python 3.7 or higher and PostgreSQL installed locally. Then, clone the sample repository's starter-no-infra branch and change to the repository root.
git clone -b starter-no-infra https://github.com/Azure-Samples/msdocs-flask-postgresql-sample-app
cd msdocs-flask-postgresql-sample-app
Create an .env file as shown below using the .env.sample file as a guide. Set the value of DBNAME to the name of an existing database in your local PostgreSQL instance. Set the values of DBHOST, DBUSER, and DBPASS as appropriate for your local PostgreSQL instance.
git clone -b starter-no-infra https://github.com/Azure-Samples/msdocs-django-postgresql-sample-app
cd msdocs-django-postgresql-sample-app
Create an .env file as shown below using the .env.sample file as a guide. Set the value of DBNAME to the name of an existing database in your local PostgreSQL instance. Set the values of DBHOST, DBUSER, and DBPASS as appropriate for your local PostgreSQL instance.
In this step, you create the Azure resources. The steps used in this tutorial create a set of secure-by-default resources that include App Service and Azure Database for PostgreSQL. For the creation process, you'll specify:
The Name for the web app. It's the name used as part of the DNS name for your webapp in the form of https://<app-name>.azurewebsites.net.
The Region to run the app physically in the world.
The Runtime stack for the app. It's where you select the version of Python to use for your app.
The Hosting plan for the app. It's the pricing tier that includes the set of features and scaling capacity for your app.
The Resource Group for the app. A resource group lets you group (in a logical container) all the Azure resources needed for the application.
Sign in to the Azure portal and follow these steps to create your Azure App Service resources.
Enter "web app database" in the search bar at the top of the Azure portal.
Select the item labeled Web App + Database under the Marketplace heading.
You can also navigate to the creation wizard directly.
Step 2: In the Create Web App + Database page, fill out the form as follows.
Resource Group → Select Create new and use a name of msdocs-python-postgres-tutorial.
Region → Any Azure region near you.
Name → msdocs-python-postgres-XYZ where XYZ is any three random characters. This name must be unique across Azure.
Runtime stack → Python 3.10.
Database → PostgreSQL - Flexible Server is selected by default as the database engine. The server name and database name are also set by default to appropriate values.
Hosting plan → Basic. When you're ready, you can scale up to a production pricing tier later.
Select Review + create.
After validation completes, select Create.
Step 3: The deployment takes a few minutes to complete. Once deployment completes, select the Go to resource button. You're taken directly to the App Service app, but the following resources are created:
Resource group → The container for all the created resources.
App Service plan → Defines the compute resources for App Service. A Linux plan in the Basic tier is created.
App Service → Represents your app and runs in the App Service plan.
Virtual network → Integrated with the App Service app and isolates back-end network traffic.
Azure Database for PostgreSQL flexible server → Accessible only from within the virtual network. A database and a user are created for you on the server.
Private DNS zone → Enables DNS resolution of the PostgreSQL server in the virtual network.
Step 1: In the Azure portal:
Enter "web app database" in the search bar at the top of the Azure portal.
Select the item labeled Web App + Database under the Marketplace heading.
You can also navigate to the creation wizard directly.
Step 2: In the Create Web App + Database page, fill out the form as follows.
Resource Group → Select Create new and use a name of msdocs-python-postgres-tutorial.
Region → Any Azure region near you.
Name → msdocs-python-postgres-XYZ where XYZ is any three random characters. This name must be unique across Azure.
Runtime stack → Python 3.12.
Database → PostgreSQL - Flexible Server is selected by default as the database engine. The server name and database name are also set by default to appropriate values.
Add Azure Cache for Redis → Yes.
Hosting plan → Basic. When you're ready, you can scale up to a production pricing tier later.
Select Review + create.
After validation completes, select Create.
Step 3: The deployment takes a few minutes to complete. Once deployment completes, select the Go to resource button. You're taken directly to the App Service app, but the following resources are created:
Resource group → The container for all the created resources.
App Service plan → Defines the compute resources for App Service. A Linux plan in the Basic tier is created.
App Service → Represents your app and runs in the App Service plan.
Virtual network → Integrated with the App Service app and isolates back-end network traffic.
Azure Database for PostgreSQL flexible server → Accessible only from within the virtual network. A database and a user are created for you on the server.
Azure Cache for Redis → Accessible only from within the virtual network.
Private DNS zones → Enables DNS resolution of the PostgreSQL server and the Redis server in the virtual network.
2. Verify connection settings
The creation wizard generated the connectivity variables for you already as app settings. App settings are one way to keep connection secrets out of your code repository. When you're ready to move your secrets to a more secure location, here's an article on storing in Azure Key Vault.
Step 1: In the App Service page, in the left menu, select Configuration.
Step 2: In the Application settings tab of the Configuration page, verify that AZURE_POSTGRESQL_CONNECTIONSTRING is present. That will be injected into the runtime environment as an environment variable.
Step 3: In a terminal or command prompt, run the following Python script to generate a unique secret: python -c 'import secrets; print(secrets.token_hex())'. Copy the output value to use in the next step.
Step 1: In the App Service page, in the left menu, select Configuration.
Step 2: In the Application settings tab of the Configuration page, verify that AZURE_POSTGRESQL_CONNECTIONSTRING and AZURE_REDIS_CONNECTIONSTRING are present. They will be injected into the runtime environment as an environment variable.
Step 3: In a terminal or command prompt, run the following Python script to generate a unique secret: python -c 'import secrets; print(secrets.token_hex())'. Copy the output value to use in the next step.
Step 4: Back in the Configuration page, select New application setting. Name the setting SECRET_KEY. Paste the value from the previous value. Select OK.
Step 5: Select Save.
3. Deploy sample code
In this step, you'll configure GitHub deployment using GitHub Actions. It's just one of many ways to deploy to App Service, but also a great way to have continuous integration in your deployment process. By default, every git push to your GitHub repository will kick off the build and deploy action.
Step 2: In the GitHub page, open Visual Studio Code in the browser by pressing the . key.
Step 3: In Visual Studio Code in the browser, open azureproject/production.py in the explorer.
See the environment variables being used in the production environment, including the app settings that you saw in the configuration page.
Step 4: Back in the App Service page, in the left menu, select Deployment Center.
Step 5: In the Deployment Center page:
In Source, select GitHub. By default, GitHub Actions is selected as the build provider.
Sign in to your GitHub account and follow the prompt to authorize Azure.
In Organization, select your account.
In Repository, select msdocs-flask-postgresql-sample-app.
In Branch, select main.
Keep the default option selected to Add a workflow.
Under Authentication type, select User-assigned identity.
In the top menu, select Save. App Service commits a workflow file into the chosen GitHub repository, in the .github/workflows directory.
Step 6: In the Deployment Center page:
Select Logs. A deployment run is already started.
In the log item for the deployment run, select Build/Deploy Logs.
Step 7: You're taken to your GitHub repository and see that the GitHub action is running. The workflow file defines two separate stages, build and deploy. Wait for the GitHub run to show a status of Complete. It takes about 5 minutes.
Step 2: In the GitHub page, open Visual Studio Code in the browser by pressing the . key.
Step 3: In Visual Studio Code in the browser, open azureproject/production.py in the explorer.
See the environment variables being used in the production environment, including the app settings that you saw in the configuration page.
Step 4: Back in the App Service page, in the left menu, select Deployment Center.
Step 5: In the Deployment Center page:
In Source, select GitHub. By default, GitHub Actions is selected as the build provider.
Sign in to your GitHub account and follow the prompt to authorize Azure.
In Organization, select your account.
In Repository, select msdocs-django-postgresql-sample-app.
In Branch, select main.
In the top menu, select Save. App Service commits a workflow file into the chosen GitHub repository, in the .github/workflows directory.
Step 6: In the Deployment Center page:
Select Logs. A deployment run is already started.
In the log item for the deployment run, select Build/Deploy Logs.
Step 7: You're taken to your GitHub repository and see that the GitHub action is running. The workflow file defines two separate stages, build and deploy. Wait for the GitHub run to show a status of Complete. It takes about 5 minutes.
With the PostgreSQL database protected by the virtual network, the easiest way to run Flask database migrations is in an SSH session with the App Service container.
Step 1: Back in the App Service page, in the left menu,
Select SSH.
Select Go.
Step 2: In the SSH terminal, run flask db upgrade. If it succeeds, App Service is connecting successfully to the database.
Only changes to files in /home can persist beyond app restarts. Changes outside of /home aren't persisted.
With the PostgreSQL database protected by the virtual network, the easiest way to run Django database migrations is in an SSH session with the App Service container.
Step 1: Back in the App Service page, in the left menu,
Select SSH.
Select Go.
Step 2: In the SSH terminal, run python manage.py migrate. If it succeeds, App Service is connecting successfully to the database.
Only changes to files in /home can persist beyond app restarts. Changes outside of /home aren't persisted.
Tip
In an SSH session, for Django you can also create users with the python manage.py createsuperuser command like you would with a typical Django app. For more information, see the documentation for django django-admin and manage.py. Use the superuser account to access the /admin portion of the web site. For Flask, use an extension such as Flask-admin to provide the same functionality.
Select the URL of your app. You can also navigate directly to https://<app-name>.azurewebsites.net.
Step 2: Add a few restaurants to the list.
Congratulations, you're running a web app in Azure App Service, with secure connectivity to Azure Database for PostgreSQL.
Step 1: In the App Service page:
From the left menu, select Overview.
Select the URL of your app. You can also navigate directly to https://<app-name>.azurewebsites.net.
Step 2: Add a few restaurants to the list.
Congratulations, you're running a web app in Azure App Service, with secure connectivity to Azure Database for PostgreSQL.
The home page shows that the name of the last visited restaurant, and the data is saved to and retrieved from the Azure cache. Remember that the sample app uses the connection string AZURE_REDIS_CONNECTIONSTRING, which was created for you by the wizard.
6. Stream diagnostic logs
Azure App Service captures all messages output to the console to help you diagnose issues with your application. The sample app includes print() statements to demonstrate this capability as shown below.
When you're finished, you can delete all of the resources from your Azure subscription by deleting the resource group.
Step 1: In the search bar at the top of the Azure portal:
Enter the resource group name.
Select the resource group.
Step 2: In the resource group page, select Delete resource group.
Step 3:
Enter the resource group name to confirm your deletion.
Select Delete.
:
1. Create Azure resources and deploy a sample app
In this step, you create the Azure resources and deploy a sample app to App Service on Linux. The steps used in this tutorial create a set of secure-by-default resources that include App Service and Azure Database for PostgreSQL.
If you haven't already, clone the sample repository's starter-no-infra branch in a local terminal.
The current directory is not empty. Would you like to initialize a project here in '<your-directory>'?
Y
What would you like to do with these files?
Keep my existing files unchanged
Enter a new environment name
Type a unique name. The azd template uses this name as part of the DNS name of your web app in Azure (<app-name>.azurewebsites.net). Alphanumeric characters and hyphens are allowed.
Run the azd up command to provision the necessary Azure resources and deploy the app code. If you are not already signed-in to Azure, the browser will launch and ask you to sign-in. The azd up command will also prompt you to select the desired subscription and location to deploy to.
azd up
The azd up command might take a few minutes to complete. It also compiles and deploys your application code, but you'll modify your code later to work with App Service. While it's running, the command provides messages about the provisioning and deployment process, including a link to the deployment in Azure. When it finishes, the command also displays a link to the deploy application.
This azd template contains files (azure.yaml and the infra directory) that generate a secure-by-default architecture with the following Azure resources:
Resource group → The container for all the created resources.
App Service plan → Defines the compute resources for App Service. A Linux plan in the B1 tier is specified.
App Service → Represents your app and runs in the App Service plan.
Virtual network → Integrated with the App Service app and isolates back-end network traffic.
Azure Database for PostgreSQL flexible server → Accessible only from within the virtual network. A database and a user are created for you on the server.
Private DNS zone → Enables DNS resolution of the PostgreSQL server in the virtual network.
Log Analytics workspace → Acts as the target container for your app to ship its logs, where you can also query the logs.
Resource group → The container for all the created resources.
App Service plan → Defines the compute resources for App Service. A Linux plan in the B1 tier is specified.
App Service → Represents your app and runs in the App Service plan.
Virtual network → Integrated with the App Service app and isolates back-end network traffic.
Azure Database for PostgreSQL flexible server → Accessible only from within the virtual network. A database and a user are created for you on the server.
Azure Cache for Redis → Accessible only from within the virtual network.
Private DNS zone → Enables DNS resolution of the PostgreSQL server in the virtual network.
Log Analytics workspace → Acts as the target container for your app to ship its logs, where you can also query the logs.
2. Use the database connection string
The azd template you use generated the connectivity variables for you already as app settings and outputs the them to the terminal for your convenience. App settings are one way to keep connection secrets out of your code repository.
In the azd output, find the app settings and find the settings AZURE_POSTGRESQL_CONNECTIONSTRING and AZURE_REDIS_CONNECTIONSTRING. To keep secrets safe, only the setting names are displayed. They look like this in the azd output:
App Service app has the following settings:
- AZURE_POSTGRESQL_CONNECTIONSTRING
- AZURE_REDIS_CONNECTIONSTRING
- FLASK_DEBUG
- SCM_DO_BUILD_DURING_DEPLOYMENT
- SECRET_KEY
AZURE_POSTGRESQL_CONNECTIONSTRING contains the connection string to the Postgres database in Azure, and AZURE_REDIS_CONNECTIONSTRING contains the connection string to the Redis cache in Azure. You need to use them your code to connect to it. Open azureproject/production.py, uncomment the following lines, and save the file:
conn_str = os.environ['AZURE_POSTGRESQL_CONNECTIONSTRING']
conn_str_params = {pair.split('=')[0]: pair.split('=')[1] for pair in conn_str.split(' ')}
DATABASE_URI = 'postgresql+psycopg2://{dbuser}:{dbpass}@{dbhost}/{dbname}'.format(
dbuser=conn_str_params['user'],
dbpass=conn_str_params['password'],
dbhost=conn_str_params['host'],
dbname=conn_str_params['dbname']
)
Your application code is now configured to connect to the PostgreSQL database in Azure. If you want, open app.py and see how the DATABASE_URI environment variable is used.
Your application code is now configured to connect to the PostgreSQL database and Redis cache in Azure.
In the terminal, run azd deploy.
azd deploy
4. Generate database schema
With the PostgreSQL database protected by the virtual network, the easiest way to run Flask database migrations is in an SSH session with the App Service container.
To delete all Azure resources in the current deployment environment, run azd down.
azd down
Troubleshooting
Listed below are issues you might encounter while trying to work through this tutorial and steps to resolve them.
I can't connect to the SSH session
If you can't connect to the SSH session, then the app itself has failed to start. Check the diagnostic logs for details. For example, if you see an error like KeyError: 'AZURE_POSTGRESQL_CONNECTIONSTRING', it might mean that the environment variable is missing (you might have removed the app setting).
I get an error when running database migrations
If you encounter any errors related to connecting to the database, check if the app settings (AZURE_POSTGRESQL_CONNECTIONSTRING) have been changed. Without that connection string, the migrate command can't communicate with the database.
The App Service plan is created in Basic tier and can be scaled up or down. See App Service pricing.
The PostgreSQL flexible server is created in the lowest burstable tier Standard_B1ms, with the minimum storage size, which can be scaled up or down. See Azure Database for PostgreSQL pricing.
The virtual network doesn't incur a charge unless you configure extra functionality, such as peering. See Azure Virtual Network pricing.
How do I connect to the PostgreSQL server that's secured behind the virtual network with other tools?
For basic access from a command-line tool, you can run psql from the app's SSH terminal.
To connect from a desktop tool, your machine must be within the virtual network. For example, it could be an Azure VM that's connected to one of the subnets, or a machine in an on-premises network that has a site-to-site VPN connection with the Azure virtual network.
How does local app development work with GitHub Actions?
Using the autogenerated workflow file from App Service as an example, each git push kicks off a new build and deployment run. From a local clone of the GitHub repository, you make the desired updates and push to GitHub. For example:
How is the Django sample configured to run on Azure App Service?
Note
If you are following along with this tutorial with your own app, look at the requirements.txt file description in each project's README.md file (Flask, Django) to see what packages you'll need.
The Django sample application configures settings in the azureproject/production.py file so that it can run in Azure App Service. These changes are common to deploying Django to production, and not specific to App Service.
# Configure the domain name using the environment variable
# that Azure automatically creates for us.
ALLOWED_HOSTS = [os.environ['WEBSITE_HOSTNAME']] if 'WEBSITE_HOSTNAME' in os.environ else []
Django doesn't support serving static files in production. For this tutorial, you use WhiteNoise to enable serving the files. The WhiteNoise package was already installed with requirements.txt, and its middleware is added to the list.
# WhiteNoise configuration
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
# Add whitenoise middleware after the security middleware
'whitenoise.middleware.WhiteNoiseMiddleware',
Then the static file settings are configured according to the Django documentation.
Administer an SQL Server database infrastructure for cloud, on-premises and hybrid relational databases using the Microsoft PaaS relational database offerings.