Reputation: 453
on Azure I am trying to deploy a flask API on a web app hosted on Linux. The code of the app.py
is the following:
app = Flask(__name__)
CORS(app)
basedir = os.path.abspath(os.path.dirname(__file__))
from db_helpers import init_db
app.config[
'SQLALCHEMY_DATABASE_URI'
] = my_microsoft_azure_database_connection.database_connection_uri
app.config['DEBUG'] = False
app.config['TESTING'] = False
app.config['CSRF_ENABLED'] = True
app.config['SECRET_KEY'] = 'needs-to-be-changed'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db_engine = init_db()
db = SQLAlchemy(app, metadata=BaseDeclarative.metadata)
api = Api(app, default_mediatype='application/json')
api.add_resource(
ListAssessmentCaseEndpoint, '/assessments', endpoint='list_assessment_cases'
)
api.add_resource(
AssessmentCaseEndpoint, '/assessments/<uuid:uuid>', endpoint='assessment_cases'
)
api.add_resource(ListAuditLogEndpoint, '/auditing', endpoint='list_audit_logs')
api.add_resource(AuditLogEndpoint, '/auditing/<uuid:uuid>', endpoint='audit_logs')
api.add_resource(HealthCheckEndpoint, '/healthcheck', endpoint='health_check')
# Add Swagger documentation to Flask app
Swagger(app, template_file='swagger.yml')
In order to deploy the application on Azure, we first build an artifact (zip file) using the following ARM template:
trigger:
- develop
variables:
webAppName: 'test-api'
environmentName: 'test-api'
projectRoot: $(System.DefaultWorkingDirectory)/WebApi
pythonVersion: '3.7'
stages:
- stage: Build
displayName: Build stage
jobs:
- job: BuildJob
steps:
- task: UsePythonVersion@0
inputs:
versionSpec: '$(pythonVersion)'
displayName: 'Use Python $(pythonVersion)'
- script: |
python3 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip
pip install waitress==2.1.2
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)/$(webAppName).zip
replaceExistingArchive: true
- publish: $(Build.ArtifactStagingDirectory)/$(webAppName).zip
displayName: 'Upload package'
artifact: drop
We then deploy the artifact on a Web App (hosted on linux using Python 3.7). To do that, we use the following template:
steps:
- task: AzureWebApp@1
displayName: 'Azure Web App Deploy: test-api'
inputs:
azureSubscription: 'azurerm-sp-apps-dev'
appType: webAppLinux
appName: 'testt-api'
package: '$(System.DefaultWorkingDirectory)/test-api-WebApi/drop/test-api.zip'
runtimeStack: 'PYTHON|3.7'
startUpCommand: 'python3.7 -m pip install -r requirements.txt && python3.7 -m pip install gunicorn && python3.7 -m gunicorn --bind=0.0.0.0:80 --workers=4 app:app'
configurationStrings: '-StartupCommand startup.sh'
deploymentMethod: zipDeploy
and we also use an application gateway that is configured as the following:
steps:
- task: test-AppGateway.appGatewayCreate-task.test-AppGateway-CreateUpdate@1
displayName: 'Create or Update Application Gateway Config API'
inputs:
connectedServiceName: 'azurerm-sp-apps-dev'
AppName: 'test-api'
HealthProbeUri: /healthcheck
timeoutInMinutes: 120
retryCountOnTaskFailure: 10
But at the deployment, we have the following strange behaviours:
1 + In the application logs (in the availability and Performance menu), we can see that the gunicorn server has been started correctly and that it is listening on http://0.0.0.0:80, and that the 4 workers have been booted...
2 + But in the platform logs, we have the following errors:
Platform logs contain errors or warnings
Container test-api_0_a8607b6c for site test-api did not start within expected time limit.
Container test-api_0_a8607b6c didn't respond to HTTP pings on port: 8000, failing site start
We have investigated the issue and here are some solutions that we tried, but did not work:
WEBSITES_CONTAINER_START_TIME_LIMIT
: currently we set it to 1800WEBSITES_PORT
: tried to 8000 and 803 + This leads for the /healthcheck
endpoint to not respond (503 server unavailable leading to 502 bad gateway on the application gateway)
4 + another issue encountered is that for some reason, the virtual environment created during the build time is not recognized at the deployment phase:
/opt/startup/startup.sh: startup.sh: not found name source not found
this is the following docker command used internally at the deployment:
docker run -d -p 9286:8000 --expose=49494 --name test-api_0_f5ccb0ab -e WEBSITE_CORS_ALLOWED_ORIGINS=https://test.dev.app.test.com,https://test.eastus2-dev-platform-ase1.appserviceenvironment.net -e WEBSITE_CORS_SUPPORT_CREDENTIALS=True -e WEBSITES_PORT=80 -e WEBSITE_SITE_NAME=test-api -e WEBSITE_AUTH_ENABLED=False -e WEBSITE_ROLE_INSTANCE_ID=0 -e WEBSITE_HOSTNAME=test-api.eastus2-dev-platform-ase1.appserviceenvironment.net -e WEBSITE_INSTANCE_ID=MY-ID -e HTTP_LOGGING_ENABLED=1 -e WEBSITE_USE_DIAGNOSTIC_SERVER=True appsvc/python:3.7_20221128.12.tuxprod python3.7 -m pip install -r requirements.txt && python3.7 -m pip install gunicorn && python3.7 -m gunicorn --bind=0.0.0.0:80 --workers=4 app:app
Any idea how to make it work?
Upvotes: 0
Views: 330
Reputation: 453
After spending much time trying to find the source of the problem; I finally made the rest api work correctly by changing the startup command to the following:
gunicorn -w 2 -k uvicorn.workers.UvicornWorker app:app
now all the errors are gone and the web app is fully functional. Also, you have to add the following to requirements.txt
:
gunicorn~=20.1.0
uvicorn~=0.20.0
Upvotes: 0