Deploying Azure web app (Python) with GitHub Actions

Parviz Alizada 20 Reputation points
2023-05-08T08:15:39.3866667+00:00

Hi,

I'm trying to automate the deployment of a Python web app onto Azure cloud with GitHub Actions. The app is working properly when I run it on my local machine. GitHub Actions also seems to compile everything well sending forward to Azure cloud. The problem is that Azure cloud seem not to be able to compile all files and run the app.

The app was built with Plotly Dash which is running on top of flask. So, this is basically a flask app.

I would appreciate if someone could help to understand the cause of the problem.

Below are my app configuration settings:

Publishing model: Code

Runtime Stack: Python - 3.11

Plan Type: App Service plan

Operating System: Linux

Instance Count: 0

SKU and size: Basic (B1)Scale up

Last deployment: Successful on Friday 5 May, 09:10:38 PM

For the deployment with GitHub Actions I'm using a ready template provided by GitHub. See the code below:

# This workflow will build and push a Python application to an Azure Web App when a commit is pushed to your default branch.
#
# This workflow assumes you have already created the target Azure App Service web app.
# For instructions see https://docs.microsoft.com/en-us/azure/app-service/quickstart-python?tabs=bash&pivots=python-framework-flask
#
# To configure this workflow:
#
# 1. Download the Publish Profile for your Azure Web App. You can download this file from the Overview page of your Web App in the Azure Portal.
#    For more information: https://docs.microsoft.com/en-us/azure/app-service/deploy-github-actions?tabs=applevel#generate-deployment-credentials
#
# 2. Create a secret in your repository named AZURE_WEBAPP_PUBLISH_PROFILE, paste the publish profile contents as the value of the secret.
#    For instructions on obtaining the publish profile see: https://docs.microsoft.com/azure/app-service/deploy-github-actions#configure-the-github-secret
#
# 3. Change the value for the AZURE_WEBAPP_NAME. Optionally, change the PYTHON_VERSION environment variables below.
#
# For more information on GitHub Actions for Azure: https://github.com/Azure/Actions
# For more information on the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# For more samples to get started with GitHub Action workflows to deploy to Azure: https://github.com/Azure/actions-workflow-samples

name: Build and deploy Python app to Azure Web App
env:
  AZURE_WEBAPP_NAME: mapnord  # set this to the name of your Azure Web App
  PYTHON_VERSION: '3.11'              # set this to the Python version to use
on:
  push:
    branches: [ "main" ]
  workflow_dispatch:
permissions:
  contents: read
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up Python version
        uses: actions/setup-python@v3.0.0
        with:
          python-version: ${{ env.PYTHON_VERSION }}
          cache: 'pip'
      - name: Create and start virtual environment
        run: |
          python -m venv venv
          source venv/bin/activate
      - name: Install dependencies
        run: pip install -r requirements.txt
      # Optional: Add step to run tests here (PyTest, Django test suites, etc.)
      - name: Upload artifact for deployment jobs
        uses: actions/upload-artifact@v3
        with:
          name: python-app
          path: |
            .
            !venv/
  deploy:
    permissions:
      contents: none
    runs-on: ubuntu-latest
    needs: build
    environment:
      name: 'Development'
      url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
    steps:
      - name: Download artifact from build job
        uses: actions/download-artifact@v3
        with:
          name: python-app
          path: .
      - name: 'Deploy to Azure Web App'
        id: deploy-to-webapp
        uses: azure/webapps-deploy@v2
        with:
          app-name: ${{ env.AZURE_WEBAPP_NAME }}
          publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE }}

I am also attaching the logs from Azure where you can see the deployment logs and error messages. For me, it seems like Azure cannot build a Python virtual environment and therefore, it fails to build and run the app.

2023-05-05T07:34:03.306084981Z A P P   S E R V I C E   O N   L I N U X
2023-05-05T07:34:03.306088381Z 
2023-05-05T07:34:03.306091781Z Documentation: http://aka.ms/webapp-linux
2023-05-05T07:34:03.306095181Z Python 3.11.2
2023-05-05T07:34:03.306098381Z Note: Any data outside '/home' is not persisted
2023-05-05T07:34:05.523918154Z Starting OpenBSD Secure Shell server: sshd.
2023-05-05T07:34:05.629942312Z App Command Line not configured, will attempt auto-detect
2023-05-05T07:34:06.047480518Z Starting periodic command scheduler: cron.
2023-05-05T07:34:06.047516618Z Launching oryx with: create-script -appPath /home/site/wwwroot -output /opt/startup/startup.sh -virtualEnvName antenv -defaultApp /opt/defaultsite
2023-05-05T07:34:06.088078255Z Cound not find build manifest file at '/home/site/wwwroot/oryx-manifest.toml'
2023-05-05T07:34:06.088681657Z Could not find operation ID in manifest. Generating an operation id...
2023-05-05T07:34:06.089480660Z Build Operation ID: 248cc8b9-8c42-4b39-be58-1b7c02a3d4e4
2023-05-05T07:34:06.411290544Z Oryx Version: 0.2.20230322.1, Commit: 6c04ec75685b441c9378c238b6491cf9812313db, ReleaseTagName: 20230322.1
2023-05-05T07:34:06.441380846Z Detected an app based on Flask
2023-05-05T07:34:06.442870451Z Generating `gunicorn` command for 'app:app'
2023-05-05T07:34:06.469695141Z Writing output script to '/opt/startup/startup.sh'
2023-05-05T07:34:06.547742504Z WARNING: Could not find virtual environment directory /home/site/wwwroot/antenv.
2023-05-05T07:34:06.548205005Z WARNING: Could not find package directory /home/site/wwwroot/__oryx_packages__.
2023-05-05T07:34:07.384578723Z [2023-05-05 07:34:07 +0000] [66] [INFO] Starting gunicorn 20.1.0
2023-05-05T07:34:07.415824729Z [2023-05-05 07:34:07 +0000] [66] [INFO] Listening at: http://0.0.0.0:8000 (66)
2023-05-05T07:34:07.421378247Z [2023-05-05 07:34:07 +0000] [66] [INFO] Using worker: sync
2023-05-05T07:34:07.433710289Z [2023-05-05 07:34:07 +0000] [69] [INFO] Booting worker with pid: 69
2023-05-05T07:34:07.497435504Z [2023-05-05 07:34:07 +0000] [69] [ERROR] Exception in worker process
2023-05-05T07:34:07.497475504Z Traceback (most recent call last):
2023-05-05T07:34:07.497481804Z   File "/opt/python/3.11.2/lib/python3.11/site-packages/gunicorn/arbiter.py", line 589, in spawn_worker
2023-05-05T07:34:07.497490504Z     worker.init_process()
2023-05-05T07:34:07.497494704Z   File "/opt/python/3.11.2/lib/python3.11/site-packages/gunicorn/workers/base.py", line 134, in init_process
2023-05-05T07:34:07.497518604Z     self.load_wsgi()
2023-05-05T07:34:07.497523404Z   File "/opt/python/3.11.2/lib/python3.11/site-packages/gunicorn/workers/base.py", line 146, in load_wsgi
2023-05-05T07:34:07.497527604Z     self.wsgi = self.app.wsgi()
2023-05-05T07:34:07.497531304Z                 ^^^^^^^^^^^^^^^
2023-05-05T07:34:07.497535104Z   File "/opt/python/3.11.2/lib/python3.11/site-packages/gunicorn/app/base.py", line 67, in wsgi
2023-05-05T07:34:07.497538904Z     self.callable = self.load()
2023-05-05T07:34:07.497542604Z                     ^^^^^^^^^^^
2023-05-05T07:34:07.497546204Z   File "/opt/python/3.11.2/lib/python3.11/site-packages/gunicorn/app/wsgiapp.py", line 58, in load
2023-05-05T07:34:07.497550104Z     return self.load_wsgiapp()
2023-05-05T07:34:07.497553804Z            ^^^^^^^^^^^^^^^^^^^
2023-05-05T07:34:07.497557404Z   File "/opt/python/3.11.2/lib/python3.11/site-packages/gunicorn/app/wsgiapp.py", line 48, in load_wsgiapp
2023-05-05T07:34:07.497561304Z     return util.import_app(self.app_uri)
2023-05-05T07:34:07.497565004Z            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2023-05-05T07:34:07.497569404Z   File "/opt/python/3.11.2/lib/python3.11/site-packages/gunicorn/util.py", line 359, in import_app
2023-05-05T07:34:07.497573404Z     mod = importlib.import_module(module)
2023-05-05T07:34:07.497577104Z           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2023-05-05T07:34:07.497580704Z   File "/opt/python/3.11.2/lib/python3.11/importlib/__init__.py", line 126, in import_module
2023-05-05T07:34:07.497584604Z     return _bootstrap._gcd_import(name[level:], package, level)
2023-05-05T07:34:07.497588404Z            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2023-05-05T07:34:07.497592104Z   File "
Azure Static Web Apps
Azure Static Web Apps
An Azure service that provides streamlined full-stack web app development.
770 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. brtrach-MSFT 15,256 Reputation points Microsoft Employee
    2023-05-10T03:29:55.7833333+00:00

    It seems that the error is related to the virtual environment. The logs show that the virtual environment directory /home/site/wwwroot/antenv could not be found. This is most likely because the virtual environment was not created or activated properly.

    In the GitHub Actions workflow, the virtual environment is created using the command python -m venv venv and then activated using source venv/bin/activate. However, it seems that the virtual environment is not being activated properly.

    You can try adding the following command to activate the virtual environment before installing the dependencies:

    - name: Activate virtual environment
      run: source venv/bin/activate
    
    

    Also, make sure that the virtual environment is being created in the correct directory. You can check this by adding the following command to the workflow:

    - name: List files in current directory
      run: ls -la
    
    

    This will list all the files in the current directory, including the virtual environment directory. Make sure that the virtual environment directory is present and has the correct name (antenv in this case).

    If the virtual environment is still not being activated properly, you can try using the pipenv package instead. pipenv is a tool that simplifies the process of managing virtual environments and dependencies. You can install pipenv using the following command:

    pip install pipenv
    

    Then, you can replace the steps for creating and activating the virtual environment with the following:

    - name: Install pipenv
      run: pip install pipenv
    - name: Install dependencies
      run: pipenv install
    - name: Activate virtual environment
      run: pipenv shell
    
    

    This will create a new virtual environment and install the dependencies using pipenv. The pipenv shell command will activate the virtual environment.

    Let me know the outcome of the above items. I look forward to your reply.