I have created a simple python flask API project using pycharm. It works great when I run using IDE and API's can be tested without any problem on localhost. BUT when I create a docker image of it and run the container on localhost, it always throw following error:
Traceback (most recent call last):
File "./app.py", line 2, in <module>
from application import db, application
ModuleNotFoundError: No module named 'application'
It has following directory structure
MyFlaskAPI
|
-Application
|
- __init__.py
|
-Models
|
-Model.py
|
-- Other project folders e.g. template, include, libs etc
|
- app.py
- config.py
- requirements.txt
- Dockerfile
- Few other config files
init.py looks is as follows:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config.from_object('config')
db = SQLAlchemy(app)
app.py is as follows:
from flask import request
from application import db, app
from model.models import FirstModel, SecondItemModel, ThirdModel
Docker file as follows:
FROM python:3
ADD app.py /
ADD requirements.txt /
RUN pip install -r requirements.txt
#EXPOSE 5000
CMD [ "python", "./app.py", "--host", "0.0.0.0"]
dockerfile
FROM python:3
ADD app.py /
ADD requirements.txt /
RUN pip install -r requirements.txt
#EXPOSE 5000
CMD [ "python", "./app.py", "--host", "0.0.0.0"]
Any suggestions/help is highly appreciated.
Related
When I run my app.py file I can access it on localhost and it works.
After running (and having no issues): docker build -t flask-container .
When I run: docker run -p 5000:5000 flask-container
I get: from helpers import apology, login_required, usd
ModuleNotFoundError: No module named 'helpers'
In app.py I have: from helpers import apology, login_required, usd
I have tried putting in an empty __init__.py folder in the main folder, still doesn't work.
Question: How do I fix the Module Not Found Error when trying to run docker?
Dockerfile
FROM python:3.8-alpine
# By default, listen on port 5000
EXPOSE 5000/tcp
# Set the working directory in the container
WORKDIR /app
# Copy the dependencies file to the working directory
COPY requirements.txt .
# Install any dependencies
RUN pip install -r requirements.txt
# Copy the content of the local src directory to the working directory
COPY app.py .
# Specify the command to run on container start
CMD [ "python", "./app.py" ]
requirements.txt
flask===2.1.0
flask_session
Python Version: 3.10.5
Please copy the helpers.py as well into the working directory.
COPY helpers.py .
OR
ADD . /app
#This will add all files in the current local dir to /app
My repo has the following structure (simplified):
project
+--x
| +--y
| +--z
| +--app.py
+--util
| +--database.py
In app.py, we import a function from database.py:
from util.database import create_database_connection
I want to deploy app.py as a webapp using Docker, and created a Dockerfile to do so:
FROM felipederodrigues/python37withpyodbc:v1
# Copy required folders and set working directory.
COPY . .
WORKDIR /x/y/z
# Install required packages.
RUN pip install --upgrade pip && pip install gunicorn eventlet==0.30.2
RUN pip install --no-cache-dir -r requirements.txt
# Set Python path.
ENV PYTHONPATH "${PYTHONPATH}:/home/site/wwwroot/"
# Expose port 8050.
EXPOSE 8050
# Start Flask app.
CMD gunicorn -b :8050 -k eventlet -w 1 app:server
Building the image and pushing it to the container registry works as expected, however, the webapp itself does not work because of the following error:
ModuleNotFoundError: No module named 'util'
Obviously, the app is unable to reach the util folder. Strangely enough, when I move app.py to folder x, and changed the WORKDIR in the Dockerfile to /x, the webapp does actually work.
So my question is, how can I make this work using the /x/y/z folder structure instead of only /x?
I am trying to build and run a flask application using docker on GCP.
My file structure is as follows:
> /project
> static (contains some images)
> templates (contains html files)
> tmp_data (contains some data that is created during usage of the app)
> __init__.py
> auth.py (app has a login feature, this script helps authorize them)
> main.py
> Dockerfile
> some other function scripts
My Dockerfile is as follows:
FROM python:3.9-slim
RUN pip3 install Flask gunicorn scipy seaborn matplotlib pandas numpy flask_excel flask_login flask_sqlalchemy
COPY . /project
WORKDIR project
ENV FLASK_APP=main.python
# run flask in dev mode
ENV FLASK_ENV=development
EXPOSE 5001:5000
CMD ["flask", "run", "--host", "0.0.0.0"]
My main.py file is as follows:
from flask import Blueprint, render_template, redirect, url_for
from flask_login import login_required, current_user
from . import db
import flask_excel as excel
import json
# user written imports (not sure why it wants relative imports now?)
from .generate_data import get_truncated_normal, create_data
from .create_graphs import plot_graph, hist_plot, bar_plot, pie_plot, data_comments
from .generate_html_file import generate_html
main = Blueprint('main', __name__)
#main.route('/')
def index():
return render_template('index.html')
... some functions and flask views ...
When I build my app (successfully) using the command
~/some_upper_folder/project (my_sandbox)$ docker build -t project .
and then run it with the command
~/some_upper_folder/project (my_sandbox)$ docker run project
I get the error:
* Serving Flask app 'main.python' (lazy loading)
* Environment: development
* Debug mode: on
Usage: flask run [OPTIONS]
Try 'flask run --help' for help.
Error: Could not import 'project.main.python'.
I am not sure why this is occurring, I'm guessing this is due to the fact that I'm referencing an incorrect directory?
NOTE: The app is working correctly, I can run it using a venv created in another folder not seen here
trying to dockerize this flask app... running the following
docker build --tag flask-website .
works, output successfully built, successfully tagged.
edit: the next command works
$ docker run --publish 5000:5000 flask-website
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: off
ok, so then I run curl localhost:5000
which gives this error
curl: (7) Failed to connect to localhost port 5000: Connection refused
ok straight forward enough, so then I try this
docker-compose up
and this results
Creating network "app_default" with the default driver
Creating app_web_1 ... done
Attaching to app_web_1
web_1 | * Environment: production
web_1 | WARNING: This is a development server. Do not use it in a production deployment.
web_1 | Use a production WSGI server instead.
web_1 | * Debug mode: off
however trying to navigate to localhost:5000 I get
This site can’t be reachedThe webpage at http://localhost:5000/
might be temporarily down or it may have moved permanently
to a new web address.
ERR_SOCKET_NOT_CONNECTED
directory structure looks like this
├──app_folder/
└── app/
| ├── static/
| | └── css/
| | └──app.css
| | └── js/
| | └──app.js
| └── templates/
| | └── app.html
| | └── subapp.html
| | └── subapp1.html
| | └── subapp2.html
| | └── subapp3.html
| └── app.py
| └── util.py
| └── pickle_file.pickle
| └── requirements.txt
| └── Dockerfile
| └── Makefile
| └── docker-compose.yml
dockerfile looks like this
FROM python:3.8
ENV PYTHONUNBUFFERED=1
WORKDIR /
COPY requirements.txt requirements.txt
COPY . .
RUN pip install -r requirements.txt
# EXPOSE 5000
CMD [ "python", "-m" , "flask", "run", "--host=0.0.0.0"]
I had tried with EXPOSE 5000 uncommented and commented, making no difference
I also updated the directory structure and dockerfile, which got rid of the command line error I was seeing
docker-compose looks like this
version: "3.7"
services:
web:
image: flask-website:latest
ports:
- 5000:5000
I tried with the dockerfile, docker-compose, makefile, and requirements outside of the app directory and a slightly modified dockerfile on the WORKDIR line, that resulted in this error
Error: Failed to find Flask application or factory in module "app". Use "FLASK_APP=app:name to specify one.
not sure what else to try? I can run it locally with python -m flask run, but I cannot seem to dockerize it, seems like this should not be this difficult?
for completeness sake, app.py looks like this
from flask import Flask, request, jsonify
from flask import render_template, redirect
import json
import util
app = Flask(__name__, template_folder="templates", static_folder="static")
#app.route("/", methods=["GET", "POST"])
def index():
return render_template("app.html")
#app.route("/predict_home_price", methods=["GET", "POST"])
def make_prediction():
x = request.form["x"]
y = float(request.form["y"]
response = jsonify(
{
"prediction": util.prediction(x, y)
}
)
response.headers.add("Access-Control-Allow-Origin", "*")
return response
if __name__ == "__main__":
from waitress import serve
serve(app, host="0.0.0.0", port=5000)
util.py looks like this
import pickle
import pandas as pd
from scipy.special import inv_boxcox
# to run locally uncomment out the following
# with open("/path/to/pickle/app/pickle_mod.pickle", "rb") as f:
# to run in docker use the following
with open("app/pickle_mod.pickle", "rb") as f:
__model = pickle.load(f)
def prediction(x, y):
lambs = 0.205
a = [[x, y]]
cols = ["x", "y"]
my_data = pd.DataFrame(data=a, columns=cols)
pred = inv_boxcox(__model.predict(my_data)[0], lambs)
return f"${round(pred)}"
if __name__ == "__main__":
print(prediction(5, 4))
I have also tried both ways with the pickle import in util, same result - I thought because I was building it in a docker container that the second import was correct
I have also tried this block for app.run as well with the same result
if __name__ == "__main__":
app.run()
I have ran a simple flask app in docker and here is the result. In your docker compose, you do not need to add the command: python app/app.py as this line was added in the Dockerfile.
The only thing you need in your Docker Compose is ports and image name
ok the following changes were required to get this image to build and the container to run
dockerfile:
FROM python:3.8
WORKDIR /
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
COPY . .
EXPOSE 5000
ENTRYPOINT ["python", "./app.py"]
then the following change to the main application app.py
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0')
then to util.py, which had an error I did not see until running docker run [TAG]
with open("pickle_mod.pickle", "rb") as f:
__model = pickle.load(f)
then run docker build -t [TAG] .
then run docker-compose up
then navigate to localhost listening on port 5000 and there is the running container
Here's my code:
app.py
from flask_graphql import GraphQLView
from app.infrastructure.graphql import schema
from app.infrastructure.api_resource import app
app.add_url_rule('/graphql', view_func=GraphQLView.as_view('graphql', schema=schema, graphiql=True))
if __name__ == '__main__':
app.run(debug=True)
api_resource.py
import app.infrastructure.repository as repository
from flask import request, url_for
from flask_restplus import Api, Resource, fields
from sqlalchemy_pagination import paginate
from sqlalchemy_fulltext import FullTextSearch
app = repository.app
api = Api(app, version='0.1', title='xxxxx',
description='xxxxx')
...
repository.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from app.domain.model import Base
connection_string = 'xxxxxx'
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = connection_string
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app, metadata=Base.metadata)
However, when i execute the gunicorn command "gunicorn app: app" i get this error:
Failed to find application object 'app' in 'app'
I'm using pipenv whith pipenv shell on ubuntu 16.04, but i've also tried on a docker container and got the same error.
here's my pip file:
[[source]]
url = "https://pypi.python.org/simple"
verify_ssl = true
name = "pypi"
[dev-packages]
[packages]
flask-graphql = "*"
flask-sqlalchemy = "*"
sqlalchemy-fulltext-search = "*"
graphene-sqlalchemy = ">=2.0"
flask-marshmallow = "*"
sqlalchemy-pagination = "*"
flask-restplus = "*"
requests = "*"
mysqlclient = "*"
gunicorn = "*"
[requires]
python_version = "3.6"
What am i doing wrong?
You have a folder called app (as by the import lines in your file) and a app.py file.
Gunicorn will try to find the app WSGI variable inside the app module, which in your case is identified as app/__init__.py
You need to rename your folder or your app.py file to avoid this conflict.
I found that this bug only happens on gunicorn version 20+. When I downgrade to version 19.9.0, it works fine even with the folder and app.py sharing the same name.
Accepted answers might be spot on for the original question , however I got the same error and I was running the gunicorn command as :
gunicorn app
In my case neither renaming the app.py nor downgrading worked.
Following fixed the issue:
gunicorn app:app
After a lot of trial and error trying to change things in init files and the dockerfile, this is what we ended up with, in our gunicorn/conda/Docker stack:
Dockerfile:
FROM continuumio/miniconda3
WORKDIR /app
# create environment
COPY environment.yml /app
RUN conda env create --name my_app_env --file environment.yml
# ensure RUN commands use the new environment
SHELL ["conda", "run", "-n", "my_app_env ", "/bin/bash", "-c"]
COPY . .
EXPOSE 8123
ENTRYPOINT [\
"conda", "run", "--no-capture-output", "-n", "my_app_env ",\
"gunicorn", "-b", "0.0.0.0:8123",\
"--pythonpath", "src/MyApp",\
"src.MyApp.app:server"\
]
Dir structure:
MyApp
|- src
|- MyApp
- __init__.py (file is empty for now)
- app.py
- Dockerfile
- environment.yml
- setup.py
initialisation in app.py
server = flask.Flask(__name__)
app = Dash(__name__, suppress_callback_exceptions=True, server=server)
)```