Similar questions have been asked but I've never found a working solution to this issue.
I have a very basic Docker and Flask setup as such:
directory structure:
├── Dockerfile
├── app
│ ├── __init__.py
│ └── constants.py
├── docker-compose.yml
└── requirements.txt
Contents of init.py
from flask import Flask
from .constants import MYCONSTANT
def create_app():
"""Create the app."""
app = Flask(__name__)
@app.route('/', methods=['GET'])
def index():
return 'hello world'
return app
Dockerfile
FROM python:3.6-alpine
COPY requirements.txt /
RUN pip install Flask gunicorn
COPY app/ /app
WORKDIR /app
EXPOSE 8000
CMD gunicorn --bind=0.0.0.0:8000 "app.__init__.create_app()"
docker-compose.yml
docker-compose:
version: '3'
services:
web:
build: .
ports: ['5000:5000']
volumes: ['./app:/app']
When I run docker-compose up --build
, the app complains that module 'app' cannot be found:
web_1 | ModuleNotFoundError: No module named 'app'
Due to test suites and and some other factors, I can't change to from constants import MYCONSTANT
, so I'm not really sure how to resolve this.
I've tried changing the gunicorn line to CMD gunicorn --bind=0.0.0.0:8000 "__init__:create_app()"
but then I get this import error:
web_1 | from .constants import MYCONSTANT
web_1 | ImportError: attempted relative import with no known parent package
CodePudding user response:
The core of your problem here is that you've lost a layer of directory. You're running GUnicorn from the /app
directory, and trying to import the Python app
module, but there's no ./app/__init__.py
relative to the directory you're starting from.
Your first step should be to delete the volumes:
block from the docker-compose.yml
file. Especially if you're having directory-layout problems, mounting something over the entire application code makes it hard to debug the issue, and you'll get different results depending on what exactly the current system has checked out. The application code is built into the image so there's no need to inject it separately.
In the Dockerfile, I'd avoid copying files into the container root directory. The important thing is to make sure you're copying the app
subdirectory from the build context into an app
subdirectory of the current directory.
FROM python:3.6-alpine
# Switch out of the root directory before copying anything in.
# (This directory is frequently named /app; picking something
# different for clarity.)
WORKDIR /web
# Install Python dependencies. (Keep this as a separate early step
# so repeated `docker build` goes faster.)
COPY requirements.txt .
RUN pip install -r requirements.txt
# Copy in the main application source.
COPY app/ ./app/ # <-- *** note, ./app relative to WORKDIR
# Set metadata for how to run the container.
EXPOSE 8000
CMD gunicorn --bind=0.0.0.0:8000 "app.__init__.create_app()"
version: '3.8'
services:
web:
build: .
ports: ['5000:5000']
# no volumes: required