Search code examples
pythondockerflaskdocker-composedockerfile

Flask debug not hot reloading in docker container


I am attempting to run a Flask server in a docker container with debug enabled so that I can hot reload during development and try out changes. Unfortunately the hot reload is not detecting changes even though I have verified the file has changed from within the container. My set up is as follows:

Host directory structure

|
|- Src
|   |- app.py
|
|- docker-compose.yaml
|- Dockerfile
|- requirements.txt

Requirements.txt

flask

Dockerfile

FROM python:3.11-slim

ENV DEBUG_COLOR=true

ENV PYTHONPATH=.

RUN mkdir /usr/local/app

WORKDIR /usr/local/app

COPY requirements.txt /usr/local/app

RUN pip install -r requirements.txt

CMD ["python", "app.py"]

docker-compose.yaml

services:

    test:
        build:
            dockerfile: ./Dockerfile
            context: .
        image: test:latest
        environment:
            - FLASK_DEBUG=1
        ports: ['3000:3000']
        volumes: [
            './src:/usr/local/app'
            ]
        command:
             python app.py

app.py

from flask import Flask

app = Flask(__name__)


@app.route('/')
def index():
    print('GET /, was called.')
    return 'Hello world.'

if __name__ == "__main__":
    app.run(host = '0.0.0.0', port = '3000')

I can kick this off from the command line using docker compose up and everything builds and runs as expected resulting in the output:

Attaching to test-1
test-1  |  * Serving Flask app 'app'
test-1  |  * Debug mode: on
test-1  | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
test-1  |  * Running on all addresses (0.0.0.0)
test-1  |  * Running on http://127.0.0.1:3000
test-1  |  * Running on http://172.18.0.2:3000
test-1  | Press CTRL+C to quit
test-1  |  * Restarting with stat
test-1  |  * Debugger is active!
test-1  |  * Debugger PIN: 582-087-710

From this I can see the debugger is running and it should be restarting with stat. I can then visit the served page at http://127.0.0.1:3000 and it serves the expected Hello world!. I can also attach to the running container and check the content of app.py using cat app.py.

If I then fire up an editor on the host and change the content of app.py, for example change the message returned to be:

    return 'Hello test world.'

I expect the debugger to detect the change and reload, however it does not do this. I can look at the content of app.py in the container I can see the code has changed, but visiting the URL I still get served Hello world!.

Note: this is unlike the issue in Auto reloading flask server on Docker where the code was copied into the container and volumes was not used to map the host src to the container directory.

Any suggestions on the step I am missing here are very welcome!


Solution

  • Based on your example, I changed the mounted path from /usr/local/app to /project, and set debug=True. Flask was then able to detect changes and hot-reload properly again.

    app.py

    from flask import Flask
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def index():
        print('GET /, was called.')
        return 'Hello world.'
    
    if __name__ == "__main__":
        app.run(host = '0.0.0.0', port = '3000', debug=True)
    

    Dockerfile

    FROM python:3.11-slim
    
    ENV DEBUG_COLOR=true
    
    ENV PYTHONPATH=.
    
    #RUN mkdir /usr/local/app
    
    WORKDIR /project
    
    COPY requirements.txt /project
    
    RUN pip install -r requirements.txt
    
    # Declare it on either the `docker-compose.yml` or `Dockerfile`, don't need both.
    # CMD ["python", "app.py"]
    

    docker-compose.yml

    services:
        test:
            build:
                dockerfile: ./Dockerfile
                context: .
            image: test:latest
            # Because it's not using command like `flask run` to launch the project, so it's not necessary either.
            #environment:
            #    - FLASK_DEBUG=1
            ports: ['3000:3000']
            volumes: [
                './src:/project'
                ]
            command:
                 python app.py
    

    After modifying above, rebuild and launch the project.

    $ docker compose up --build
    

    It’s quite strange. Despite setting debug=True or using docker compose --watch, hot-reloading still doesn’t work unless I change the mounted path from /usr/local/app to /project (which might be related to the system path or Flask's watchdog detection paths).

    The /usr/local directory is often used for system-level installations, and file system events might not be properly propagated when mounting volumes there in a Docker container.