Breaker
Breaker

Reputation: 33

Odd issue with Python Flask App on Linux Azure App Service

App Structure

The other modules used by app.py reference some additional modules via import that are to be installed by requirements.txt such as pyyaml and sqlparse.

Here is a snippet from the pipeline yaml that installs these during the build in Azure DevOps

- task: Bash@3
displayName: 'Install Python dependencies'
inputs:
targetType: 'inline'
script: |
python3.9 -m venv antenv
source antenv/bin/activate
pip3 install --upgrade pip
pip3 install --upgrade setuptools
pip3 install --upgrade setuptools_rust
pip3 install uamqp --upgrade --no-cache-dir
pip3 install -r requirements.txt --upgrade --no-cache-dir

When I run the build pipeline in Azure DevOps, I can see the modules getting installed fine. Here is when things get weird...

When I execute the release pipeline, the release fails and in the logs for the Azure Web App, I can see a 'ModuleNotFound' error....'No module named yaml'. This is due to one of my py files using an 'import yaml' statement - so it appears it is not finding the pyyaml module.

Upon running 'pip3 list', I do not see pyyaml installed. So then I commented out 'import yaml' in my py file and deployed the release, it was successful. I did this so I could SSH into the Web App to do some inspecting. However, when I drill down in the virtual environment directory (antenv), I can see the modules installed there (/home/site/wwwroot/antenv/lib/python3.9/site-packages/). When I open a Python shell, and try to do an 'import yaml', I see that module not found error there as well.

I checked around the web and I did find people mentioning you need to configure an app setting on the Azure Web App, SCM_DO_BUILD_DURING_DEPLOYMENT and set that to 'true' or '1' - which I made sure to do beforehand.

This is where it gets even more odd, just as a test, I copied the actual 'yaml' directory (pyyaml module folder for the pyyaml install) to the app.py root level, then did a build/release again, and it deployed fine....even with the 'import yaml' uncommented in one of my .py files!! The app is even functional! Also, running 'pip3 list' within the Web App STILL does not show pyyaml as installed!!

Anyone know what the issue could be? Spent days trying to get this to work....copying every additional non-OOTB Python module to the root of my repo along-side app.py cannot possibly be the feasible solution right?

Upvotes: 1

Views: 630

Answers (1)

SiddheshDesai
SiddheshDesai

Reputation: 8157

Make sure you add PYyaml in requirements.txt like below for the import statement in the app.py to work, Given requirements.txt is in the root folder:-

app.py to load config.yaml:-
import os
from flask import (Flask, redirect, render_template, request,
                   send_from_directory, url_for)
import yaml

app = Flask(__name__)

# Define a global variable to store the loaded YAML data
config = None

def load_config():
    global config
    try:
        with open('config.yaml', 'r') as config_file:
            config = yaml.load(config_file, Loader=yaml.FullLoader)
    except FileNotFoundError:
        print('Config file not found.')

# Load the configuration when the app starts
load_config()

@app.route('/')
def index():
    print('Request for index page received')
    return render_template('index.html')

@app.route('/favicon.ico')
def favicon():
    return send_from_directory(os.path.join(app.root_path, 'static'),
                               'favicon.ico', mimetype='image/vnd.microsoft.icon')

@app.route('/hello', methods=['POST'])
def hello():
    name = request.form.get('name')

    if name:
        print('Request for hello page received with name=%s' % name)
        return render_template('hello.html', name=name, config=config)
    else:
        print('Request for hello page received with no name or blank name -- redirecting')
        return redirect(url_for('index'))

if __name__ == '__main__':
    app.run()

requirements.txt:-

Flask==2.0.2
gunicorn
PyYAML

My yaml pipeline:-

trigger:
- main

variables:
  
  azureServiceConnectionId: 'xxxxxxxxxxxxx0b035'

  
  webAppName: 'siliconwebapp098'

 
  vmImageName: 'ubuntu-latest'

 
  environmentName: 'siliconwebapp098'

  
  projectRoot: $(System.DefaultWorkingDirectory)

  
  pythonVersion: '3.7'

stages:
- stage: Build
  displayName: Build stage
  jobs:
  - job: BuildJob
    pool:
      vmImage: $(vmImageName)
    steps:
    - task: UsePythonVersion@0
      inputs:
        versionSpec: '$(pythonVersion)'
      displayName: 'Use Python $(pythonVersion)'

    - script: |
        python -m venv antenv
        source antenv/bin/activate
        python -m pip install --upgrade pip
        pip install setup
        pip install -r requirements.txt
      workingDirectory: $(projectRoot)
      displayName: "Install requirements"

    - task: ArchiveFiles@2
      displayName: 'Archive files'
      inputs:
        rootFolderOrFile: '$(projectRoot)'
        includeRootFolder: false
        archiveType: zip
        archiveFile: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
        replaceExistingArchive: true

    - upload: $(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip
      displayName: 'Upload package'
      artifact: drop

- stage: Deploy
  displayName: 'Deploy Web App'
  dependsOn: Build
  condition: succeeded()
  jobs:
  - deployment: DeploymentJob
    pool:
      vmImage: $(vmImageName)
    environment: $(environmentName)
    strategy:
      runOnce:
        deploy:
          steps:

          - task: UsePythonVersion@0
            inputs:
              versionSpec: '$(pythonVersion)'
            displayName: 'Use Python version'

          - task: AzureWebApp@1
            displayName: 'Deploy Azure Web App : siliconwebapp098'
            inputs:
              azureSubscription: $(azureServiceConnectionId)
              appName: $(webAppName)
              package: $(Pipeline.Workspace)/drop/$(Build.BuildId).zip

Installed requirements.txt with this task:-

    - script: |
        python -m venv antenv
        source antenv/bin/activate
        python -m pip install --upgrade pip
        pip install setup
        pip install -r requirements.txt
      workingDirectory: $(projectRoot)
      displayName: "Install requirements"

enter image description here

enter image description here

enter image description here

Upvotes: 0

Related Questions