Azure: Docker App Error “…site did not start within expected time limit” and “Container X didn't respond to HTTP pings on port 80”

I have a Flask Python app that is run via Gunicorn from a Docker Linux container. Running the Docker container on Ubuntu works fine locally, but when the container is pushed to the Azure Container Registry and then deployed as an Azure App, it fails with the following error messages:

  1. Container my-app_900f4c for site my-app did not start within expected time limit.
  2. Container my-app_900f4c didn't respond to HTTP pings on port: 80, failing site start.

Docker Log

2020-02-17 INFO  - Pull Image successful, Time taken: 0 Minutes and 15 Seconds
2020-02-17 INFO  - Starting container for site
2020-02-17 INFO  - docker run -d -p 9031:80 --name my-app_900f4c -e PORT=80 -e WEBSITES_PORT=80 -e WEBSITE_SITE_NAME=my-app -e WEBSITE_AUTH_ENABLED=False -e WEBSITE_ROLE_INSTANCE_ID=0 -e WEBSITE_HOSTNAME=my-app.azurewebsites.net -e WEBSITE_INSTANCE_ID=eaaf...51e441df96704916ba7b506b6150b26cdc7 -e HTTP_LOGGING_ENABLED=1 myazureappregistry.azurecr.io/my_app:v1  

2020-02-17 INFO - Initiating warmup request to container my-app_900f4c for site my-app
2020-02-17 ERROR - Container my-app_900f4c for site my-app did not start within expected time limit. Elapsed time = 255.9515056 sec
2020-02-17 ERROR - Container my-app_900f4c didn’t respond to HTTP pings on port: 80, failing site start. See container logs for debugging.
2020-02-17 INFO - Stopping site my-app because it failed during startup.

Default Docker Log

2020-02-17 [1] [INFO] Starting gunicorn 20.0.4
2020-02-17 [1] [INFO] Listening at: http://0.0.0.0:80 (1)
2020-02-17 [1] [INFO] Using worker: gthread
2020-02-17 [7] [INFO] Booting worker with pid: 7
2020-02-17 [8] [INFO] Booting worker with pid: 8
2020-02-17 [9] [INFO] Booting worker with pid: 9
2020-02-17 [10] [INFO] Booting worker with pid: 10

In the Azure Portal under Settings > Configuration I have the following Application settings:

  • PORT 80
  • WEBSITES_PORT 80

Dockerfile

FROM python:3.8-slim-buster

LABEL Name=my_app Version=0.0.1
EXPOSE 80

WORKDIR /app

RUN python3 -m pip install --upgrade pip
RUN python3 -m pip install -r requirements.txt
ADD . /app
CMD ["gunicorn", "-c", "gunicorn.conf.py", "main:app"]

I don't understand what is causing HTTP pings on port 80 to fail, when the logs show that Gunicorn is listening on http://0.0.0.0:80.

Similar questions that have not resolved the issue:

The container must implement an HTTP 404 (Not Found) error handler.

When Azure starts a container, the warmup request checks the server by requesting resources to ensure that it is responding. If one of the requested resources is not found and the container does not have an HTTP 404 (Not Found) error handler, then the request will timeout and the container will be stopped.

Docker Container Port Configuration

The Azure PORT flag is not needed. The WEBSITES_PORT flag should be set to whichever port is exposed within the container.

Set WEBSITES_PORT from the Azure CLI as follows:

az webapp config appsettings set --resource-group <resource-group-name> --name <app-name> --settings WEBSITES_PORT=8000

Or use the Azure portal:
Your app > Settings > Configuration > Application settings

Flask Example - HTTP 404 Error Handler

from flask import Flask
from werkzeug.exceptions import Forbidden, HTTPException, NotFound, RequestTimeout, Unauthorized

app = Flask(name)

@app.route(’/’)
def hello():
return “Hello Flask!”

@app.errorhandler(NotFound)
def page_not_found_handler(e: HTTPException):
return render_template(‘404.html’), 404

@app.errorhandler(Unauthorized)
def unauthorized_handler(e: HTTPException):
return render_template(‘401.html’), 401

@app.errorhandler(Forbidden)
def forbidden_handler(e: HTTPException):
return render_template(‘403.html’), 403

@app.errorhandler(RequestTimeout)
def request_timeout_handler(e: HTTPException):
return render_template(‘408.html’), 408

if name == ‘main’:
app.run()