David Scott
David Scott

Reputation: 886

Running Flask in Docker Using Volumes Causes Error on Reload

I'm setting up my dev environment for a flask app in a docker container and during dev I want to be able to put Flask in development mode so that I can get live reloads when I change a file. I'm using volumes so that I can edit the files outside of docker. I am getting the desired behavior from Flask, on editing the flask test file it detects the file change, however, it appears to be attempting to serve trunkated files instead of the files as edited resulting in errors from the app.

Dockerfile:

FROM python:3.8.1-alpine3.11
RUN apk update && apk upgrade && apk add bash

#Set ENV Variables
ENV FLASK_APP hello.py

#Add user.
RUN adduser -D eskimotv
USER eskimotv

#Set Work directory
WORKDIR /home/eskimotv

#Install Dependencies
COPY requirements requirements
RUN python -m venv venv
RUN venv/bin/pip install --upgrade pip
RUN venv/bin/pip install -r requirements/docker.txt

#Copy project files
COPY frontend frontend
COPY migrations migrations
COPY boot.sh ./

#Deploy Project
EXPOSE 5000
#ENTRYPOINT ["./boot.sh"]

Docker-compose.yml:

version: '3'
services:
  frontend:
    image: bentsea/eskimotv-frontend:latest
    build:
      dockerfile: frontend.dockerfile
      context: .
    ports:
      - "8000:5000"
    env_file: .env
    volumes:
      - './boot.sh:/home/eskimotv/boot.sh'
      - './hello.py:/home/eskimotv/hello.py'
      - './frontend:/home/eskimotv/frontend'
    #entrypoint: ./boot.sh
    restart: always

Simple flask app, hello.py:

from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    return '<h1>Hello World!</h1><p> Please work!</p>'

@app.route('/user/<name>')
def user(name):
    return '<h1>Hello, {}!</h1>'.format(name)

Environtment variable FLASK_ENV is set to development. When starting up the app for the first time all my changes are displayed correctly:

Working App Serving Correctly

If I make a very simple edit, such as changing line 10 of hello.py with a cosmetic change, such as the following:

return '<h1>Hello, {}, I made a small change to the text!</h1>'.format(name)

Flask will appropriately reload:

 * Detected change in '/home/eskimotv/hello.py', reloading
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 234-654-899
172.21.0.1 - - [31/Dec/2019 20:00:20] "GET /user/David HTTP/1.1" 200 -
 * Detected change in '/home/eskimotv/hello.py', reloading
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 234-654-899

However, the page will begin to produce an error rather than correctly display the page:

Example of error generated after file reloads.

Sometimes it's just an EOL error that indicates that the file is truncated, sometimes it indicates this null error. Either restarting the Flask server or undoing the edits made to the file resolves the issue and the app will function normally. Restarting the server every time I make an edit is the action I was wanting to avoid.

Does anyone have any ideas what would cause the files in this volume configuration to load incorrectly and what I can do to resolve the issue to get the intended behavior of having the reload display the file as it is edited?

Upvotes: 1

Views: 1680

Answers (2)

David Scott
David Scott

Reputation: 886

I don't know why the error is occurring, however it does appear to be caused by mounting a single file instead of a directory. By restructuring my app to mount only entire directories that include the files that need to be updated I was able to successfully use a workflow that allows for automatic Flask reload through Docker on file change.

For whatever reason Docker does not accurately update individual files that are mounted if they are outside of a mounted directory.

Upvotes: 3

MasterOfTheHouse
MasterOfTheHouse

Reputation: 1339

Try after you change your code to rebuild your docker. Before making the change do

docker-compose stop

Then make the change by editing the line

return '<h1>Hello, {}, I made a small change to the text!</h1>'.format(name)

after making your change above, now do

docker-compose build

And finally

docker-compose up

Upvotes: -1

Related Questions