Deploy to Azure App Service on Linux
This tutorial walks you through using Visual Studio Code to deploy a Python application to Azure App Service on Linux using the Azure App Service extension.
Azure App Service on Linux, currently in Preview for Python, runs your source code in a pre-defined Docker container. The characteristics of this container are summarized as follows (for full documentation, see Configure Python apps for App Service on Linux):
- Apps are run with Python 3.7 using the Gunicorn web server.
- The container includes Flask by default but not Django.
- To install Django and any other dependencies, you must provide a
requirements.txtfile and deploy to App Service using Git, as shown in this tutorial.
- Although the container can run Django and Flask apps automatically, provided the app matches an expected structure, you can also provide a custom startup command file through which you have full control over the Gunicorn command line. A custom startup command is typically required for Flask apps, but not Django apps.
- The container definition itself is on the github.com/Azure-App-Service/python.
If you encounter any problems in the course of this tutorial, feel free to file an issue in the Visual Studio Code documentation repository.
To complete this tutorial you need an Azure account, Visual Studio Code with the Azure App Service extension, a Python environment, and an app that you'd like to deploy.
If you don't have an Azure account, sign up now for a free 30-day account with $200 in Azure credits to try out any combination of services.
Visual Studio Code, Python, and the Azure App Service extension
Install the following:
- Visual Studio Code.
- Python and the Python extension as described on Python Tutorial - Prerequisites.
- The Azure App Service extension, which provides interaction with Azure App Service from within VS Code. For general information, explore the App Service extension tutorial and visit the vscode-azureappservice GitHub repository.
Sign in to Azure
Once the App Service extension is installed, sign into your Azure account by navigating to the Azure: App Service explorer, select Sign in to Azure, and follow the prompts.
After signing in, verify that you see the email account of your Azure around in the Status Bar and your subscription(s) in the Azure: App Service explorer:
Note: If you see the error "Cannot find subscription with name [subscription ID]", this may be because you are behind a proxy and unable to reach the Azure API. Configure
HTTPS_PROXYenvironment variables with your proxy information in your terminal:
# macOS/Linux export HTTPS_PROXY=https://username:password@proxy:8080 export HTTP_PROXY=http://username:password@proxy:8080 #Windows set HTTPS_PROXY=https://username:password@proxy:8080 set HTTP_PROXY=http://username:password@proxy:8080
If you don't already have an app you'd like to work with, use one of the options below. Be sure to verify that the app runs locally.
Create a new folder, open it in VS Code, and add a file named
hello.pywith the contents below, which creates a minimal Flask app as used in this walkthrough. The app object is purposely named
myappto demonstrate how the names are used in the startup command for the App Service, as you see later.
Also follow the instructions in Flask Tutorial - Create a project environment for Flask to create a virtual environment with Flask installed within which you can run the app locally.
from flask import Flask myapp = Flask(__name__) @myapp.route("/") def hello(): return "Hello Flask, on Azure App Service for Linux"
Caveat: If your Django app uses a local SQLite database like this sample, you need to include a pre-initialized and pre-populated copy of the
db.sqlite3file in your repository. The reason for this is that, at present, the preview of App Service for Linux doesn't have a means to run Django's
migratecommand as part of deployment, so you must deploy a pre-made database. Even then, the database is effectively read-only; writing to the database also causes errors. The workaround is to use a database that's hosted elsewhere, in which case you would deploy and initialize that database separately before deploying the app code as described in this tutorial.
Create the App Service
In the Azure: App Service explorer, select the + command to create a new App Service, or open the Command Palette and select Azure App Service: Create New Web App. (In App Service terminology, a "web app" is a host for web app code, not the app code itself.)
In the prompts that follow:
- Enter a name for your app, which must be globally unique on App Service; typically you use your name or company name followed by the app name.
- Select Linux for the operating system.
- Select [Preview] Python 3.7 as the runtime.
After a short time you see a message that the new App Service was created, along with the question Deploy to web app?. Answer No at this point because you need to change the deployment source to Git. Otherwise the "Deploy to Web App" command only copies your files to the server using a ZIP file and doesn't install your dependencies.
To confirm that the App Service is running properly, expand your subscription in the Azure: App Service explorer, right-click the App Service name, and select Browse website:
Because you haven't deployed your own code to the App Service yet, you should see only the default app:
Configure a custom startup file
Depending on how you've structured your app, you may need to create a custom startup command file for your app as described on Configure Python apps for App Service on Linux in the Azure docs.
The specific use cases of a custom startup command are as follows:
- You have a Flask app whose startup file and app object are named something other than
app, respectively. In other words, unless you have an
application.pyin the root folder of your project, and the Flask app object is named
app, then you need a custom startup command.
- You want to start the Gunicorn web server with additional arguments beyond the defaults, which are
--bind=0.0.0.0 --timeout 600.
Django apps typically don't need customizations unless you want to provide additional arguments to Gunicorn.
If you need a custom startup file, first create the file and commit it to your repository so it can be deployed with the rest of the app code.
Create a file in your project named
startup.txt(or another name of your choice) that contains your startup command. For Flask, see Flask startup commands in the next section.
In the Azure: App Service explorer, expand the App Service, right-click Application Settings, and select Open in Portal:
In the Azure portal, sign in if necessary; then on the Application settings page, enter your startup file name under Runtime > Startup File, then select Save. (This is the one case in which you need to visit the Azure portal.)
The App Service restarts when you save changes. Because you still haven't deployed your app code, however, visiting the site at this point shows "Service Unavailable." This message indicates that the Gunicorn server started but failed to find the app, and therefore nothing is responding to HTTP requests.
Note: Instead of using a startup command file, you can also put the startup command directly in the Startup File field on the Azure portal. Using a file is generally preferable, however, as it keeps this bit of configuration in your repository where you can audit changes and redeploy to a different App Service instance altogether.
Flask startup commands
By default, the App Service on Linux container assumes that a Flask app's startup file is named
application.py and resides in the app's root folder. It further assumes that the Flask app object defined within that file is named
app. If your app isn't structured in this exact way, then your custom startup command must identify the app object's location:
Different file name and/or app object name: for example, if the app's startup file is
hello.pyand the app object is named
myapp, the startup command is as follows:
gunicorn --bind=0.0.0.0 --timeout 600 hello:myapp
Startup file is in a subfolder: for example, if the startup file is
myapp/website.pyand the app object is
app, then use Gunicorn's
--chdirargument to specify the folder and then name the startup file and app object as usual:
gunicorn --bind=0.0.0.0 --timeout 600 --chdir myapp website:app
Startup file is within a module: in the python-sample-vscode-flask-tutorial code, the
webapp.pystartup file is contained within the folder
hello_app, which is itself a module with an
__init__.pyfile. The app object is named
appand is defined in
webapp.pyuses a relative import. Because of this arrangement, pointing Gunicorn to
webapp:appproduces a "Attempted relative import in non-package" error and the app fails to start.
In this situation, create a simple shim file that imports the app object from the module, and then have Gunicorn launch the app using the shim. The python-sample-vscode-flask-tutorial code, for example, contains
startup.pywith the following contents:
# startup.py shim from hello_app.webapp import app
The startup command is then the following:
gunicorn --bind=0.0.0.0 --timeout 600 startup:app
Add the app to a Git repository
As noted earlier, you must deploy to App Service on Linux using Git in order for the container to install your dependencies in
requirements.txt. The following steps make sure you have both a
requirements.txt file and a repository:
requirements.txtfile in your root folder if you don't have one already:
- Activate your virtual environment with the Python: Select Interpreter command on the Command Palette (⇧⌘P (Windows, Linux Ctrl+Shift+P)).
- Open a terminal for the environment with Terminal: Create New Integrated Terminal.
- Make sure you're in the root folder of the app, then run
pip freeze > requirements.txt.
In your project folder, create a file named
.gitignorewith the following contents (change
.venvif you're using a different folder for a virtual environment):
.vscode/ __pycache__ .venv/
From the Command Palette, run the Git: Initialize Repository command.
The same command is found at the top of the Source Control explorer:
In the prompt that appears, select your current folder for the repository, then answer Open Repository in the subsequent message"
In the Source Control explorer you see your project files ready to commit to the repository. Enter a commit message like "Initial commit", then select the checkmark button:
Deploy your app using Git
As mentioned earlier, you must use Git to deploy Python apps to App Service on Linux so that your dependencies in
requirements.txt are installed. With Git deploy you can use either a local repository or a GitHub repository.
Make sure all your code changes are committed to your repository, and pushed to GitHub if you're using that option.
In the Azure: App Service explorer, right-click the App Service name, and select Configure Deployment Source:
When prompted, choose either LocalGit or GitHub as the source:
LocalGit: code is deployed from the currently active branch of your local copy of the repository.
GitHub: code is deployed from the selected branch of a GitHub repository, and happens automatically when you push commits to the repository. Selecting this option successively prompts you for the organization, repository, and branch to use.
With both choices, the extension connects the App Service to the repository. You don't see indications of the connection in VS Code itself; on the Azure portal, you can examine the connect on the Azure portal in the App Service's Deployment > Deployment options page.
To deploy the app:
LocalGit: Commit your changes to your local repository, then right-click the App Service again, select Deploy to Web App, and select the project folder when prompted. (You can also select use the deploy button at the top of the explorer.)
GitHub: Commit your changes, then do a Git push by selecting Git: Push from the Command Palette or by using the sync changes button on the status bar:
While deployment is taking place, you see an indicator in the App Service extension explorer:
You can also observe progress in the Output panel (⇧⌘U (Windows Ctrl+Shift+U, Linux Ctrl+K Ctrl+H)) by selecting Azure App Service from the drop-down:
After a minute or two (depending on how many dependencies are in your
requirements.txt), VS Code reports that deployment is complete. To verify that your files are deployed, expand the App Service in the Azure: App Service explorer, then expand Files:
You can also expand the
antenvfolder, which is where App Service creates a virtual environment with your dependencies, and verify that the packages you named in
requirements.txtare installed in
Tip: Be mindful that it's easy to misinterpret the file and folder structure because the App Service extension sorts all files and folders alphabetically and indents files slightly more than folders, which makes those files seem like children of a folder rather than peers. (See issue 631 in the App Service extension GitHub repo.)
Right-click the App Service again and select Browse Website to view your running app (you may need to refresh the browser if the previous page was cached):
Make changes and redeploy
With your App Service connected to a repository, you have a simple code-test-deploy process:
Make changes and test the app locally.
Commit changes to your Git repository. Always remember this step, because the App Service extension pulls your code from the repository and won't pick up uncommitted changes!
Deploy the code:
- LocalGit: open the Azure: App Service explorer, right-click the App Service, and select Deploy to Web App.
- GitHub: push your changes to GitHub; App Service automatically deploys the code and restarts.
Once deployment is complete, wait a few seconds for the App Service to restart, then browse the website and verify your changes.
With any deployment option, you can observe status on the Azure portal under the App Service's Deployment > Deployment options page:
Changing the GitHub branch
When you use the App Service extension in VS Code to set GitHub as the deployment source, you're prompted for a specific branch. This branch is then directly wired into the App Service configuration. To use a different branch, you must first disconnect the existing branch, then create a new connection:
In the App Service explorer in VS Code, right-click the App Service and select Open in portal.
On the portal, select Deployment > Deployment options, then select Disconnect.
Once disconnected, you can configure a new connection directly on the portal, or you can use the App Service extension in VS Code to set the deployment source to GitHub again, selecting the desired branch.
Congratulations on completing this walkthrough of deploying Python code to App Service on Linux!
As noted earlier, you can learn more about the App Service extension by visiting its GitHub repository, vscode-azureappservice. Issues and contributions are also very welcome.
To learn more about Azure services that you can use from Python, including data storage along with AI and Machine Learning services, visit Azure Python Developer Center.
There are also other Azure extensions for VS Code that you may find helpful. Just search on "Azure" in the Extensions explorer:
A few favorites include:
And again, if you've encountered any problems in the course of this tutorial, feel free to file an issue in the VS Code docs repo.