I am serving a flask app with docker but the docker logs command shows that the app is running on a development server. I want to serve this app with waitress.
The project is structured like this below. A docker-compose.yml file to build the image, expose the port and run the manage.py file
docker-compose.yml
web:
build: .
image: web
container_name: web
ports:
- 8080:5000
command: python manage.py run -h 0.0.0.0
manage.py file imports the create_app and provides it into FLaskGroup
from flask.cli import FlaskGroup
from project.server import create_app
app = create_app()
cli = FlaskGroup(create_app=create_app)
if __name__ == "__main__":
cli()
project/server/__init__.py file imports the main_blueprint and registers it.
from project.server.main.views import main_blueprint
from flask import Flask
import os
def create_app(script_info=None):
app = Flask(
__name__,
template_folder="../client/templates",
static_folder="../client/static",
)
app_settings = os.getenv("APP_SETTINGS")
app.config.from_object(app_settings)
app.register_blueprint(main_blueprint)
app.shell_context_processor({"app": app})
return app
project/server/main/views.py
from flask import render_template, Blueprint, jsonify, request
main_blueprint = Blueprint("main", __name__,)
#main_blueprint.route("/", methods=["GET"])
def home():
return render_template("pages/home.html")
#main_blueprint.route("/test", methods=["GET"])
def parse():
return jsonify({"result": "test"}), 202
How can I modify the existing code to serve the flask app with waitress? Thank you.
I got it running by changing the docker-compose.yml file:
command
python manage.py run -h 0.0.0.0 to waitress-serve --call "project.server:create_app"
port
8080:5000 to 8080:8080
docker-compose.yml file looks like below now:
web:
build: .
image: web
container_name: web
ports:
- 8080:8080
command: waitress-serve --call "project.server:create_app"
You run using python manage.py run -h 0.0.0.0, which uses the classic flask run. You should use waitress commands to run your app.
This doc might help you.
Related
I have developed a flask rest API and I'm using flask_smorest.
I'm developing into cloud shell editor into google cloud.
When I run google cloud run emulator, I receive the error:
##########Linting Output - pylint##########
************* Module app
3,0,error,import-error:Unable to import 'flask_smorest'
and this my dockerfile:
FROM python:3.10
ENV PYTHONUNBUFFERED True
ENV APP_HOME /app
WORKDIR $APP_HOME
COPY . ./
RUN pip install Flask gunicorn flask-smorest marshmallow
CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 app:app
This is app.py file:
import os
from flask import Flask, request
from flask_smorest import Api
app = Flask(__name__)
app.config["PROPAGATE_EXCEPTIONS"] = True
app.config["API_TITLE"] = "Stores REST API"
app.config["API_VERSION"] = "v1"
app.config["OPENAPI_VERSION"] = "3.0.3"
app.config["OPENAPI_URL_PREFIX"] = "/"
app.config["OPENAPI_SWAGGER_UI_PATH"] = "/swagger-ui"
app.config["OPENAPI_SWAGGER_UI_URL"] ="https://cdn.jsdelivr.net/npm/swagger-ui-dist/"
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=int(os.environ.get("PORT", 8080)))
how i can fix this issue? And why i have this error?
Posting this as a community wiki from #dev_:
The issue was resolved by installing the module from the Cloud Shell Terminal.
I am running Flask application in Python using docker-compose. I am able to run the Flask app using 5000 port. I am trying to run it on 6000 besides another Flask app running on 5000. But I am unable run it on 6000 port. Any help would be appreciated.
docker-compose.yml
version: '3.8'
services:
web:
build: ./web
ports:
- "6000:5000"
app.py
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
Dockerfile:
FROM python:3
COPY . /app
WORKDIR /app
RUN pip install -U pip
RUN pip install -r requirements.txt
ENTRYPOINT ["python"]
CMD ["app.py"]
requirements.txt
Flask==1.1.1
Port 6000 is listening. I am able to get a connection succeeded by executing nc command with host and port.
I am unable to run the app on port 6000.
I got the following when I hit http://#{HOST_IP}:6000 in browser
This site can’t be reached
The web page at http://#{HOST_IP}:6000/ might be temporarily down or it may have moved permanently to a new web address.
6000 is unsafe port that is why browser not allowing to access the application.
how-to-fix-err-unsafe-port-error-on-chrome-when-browsing-to-unsafe-ports
But you should not allow this port, just try to publish another port.
version: '3.8'
services:
web:
build: ./web
ports:
- "5001:5000"
For downvoter
Here is Github Repo to verify this
git clone https://github.com/Adiii717/dockerize-flask-app.git
cd dockerize-flask-app/
# this will not work in the browser
PORT=6000 docker-compose up
You haven't defined any routes. The app server has no idea what routes are available nor does it know what you want to return, so you need to specify that.
Here's a more complete version of app.py
from flask import Flask
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'Hello, World!'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
Please refer to the Flask tutorial for a minimal app.
I want to get a value from web3.eth.getTransactionCount. It just hangs. This function works fine elsewhere(normal app, console).
To recreate this behavior simply create a new folder, add these 3 files to the folder, and inside that folder run docker-compose up. *Note that infura credentials are safe to use.
dockerfile
FROM python:3.7
WORKDIR /usr/src/app
RUN pip install flask celery[redis] web3
docker-compose.yml
version: "3"
services:
redis:
image: redis:5.0.7
container_name: redis
ports:
- "6379:6379"
myapp:
build: .
container_name: myapp
ports:
- "5000:5000"
volumes:
- .:/usr/src/app
environment:
- FLASK_ENV=development
- WEB3_INFURA_PROJECT_ID=1cc71ab02b99475b8a3172b6a790c2f8
- WEB3_INFURA_API_SECRET=6a343124ed8e4a6f9b36d28c50ad65ca
entrypoint: |
bash -c "python /usr/src/app/app.py"
celery:
build: .
container_name: celery
volumes:
- .:/usr/src/app
environment:
- WEB3_INFURA_PROJECT_ID=1cc71ab02b99475b8a3172b6a790c2f8
- WEB3_INFURA_API_SECRET=6a343124ed8e4a6f9b36d28c50ad65ca
command: celery worker -A app.client -l info
app.py
from flask import Flask
from web3.auto.infura.rinkeby import w3 as web3
from celery import Celery
app = Flask(__name__)
client = Celery(app.name, broker='redis://redis:6379', backend='redis://redis:6379')
#client.task
def never_return():
print('start') # this is printed
nonce = web3.eth.getTransactionCount('0x51cDD4A883144F01Bf0753b6189f3A034866465f')
print('nonce', nonce) # this is never printed
#app.route('/')
def index():
never_return.apply_async()
return "hello celery"
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
I found only 1 similar unresolved post here: Call to Google Cloud API in Celery task never returns
There seems to be something weird when making a request call by other library within Celery task. Everything works fine when I tried making post requests using request. Unfortunately I don't know how to work around this problem using this request library.
Any kind of suggestions are highly appreciated.
it seems to me this issue has something to do with websockets. so i tried to switch it to HTTP. and it works.
here is modified app.py
from flask import Flask
from web3 import Web3
from celery import Celery
from web3.middleware import geth_poa_middleware
import os
app = Flask(__name__)
client = Celery(app.name, broker='redis://redis:6379', backend='redis://redis:6379')
#client.task
def never_return():
w3 = Web3(Web3.HTTPProvider(f"https://rinkeby.infura.io/v3/{os.getenv('WEB3_INFURA_PROJECT_ID')}", request_kwargs={'timeout': 60}))
w3.middleware_onion.inject(geth_poa_middleware, layer=0)
print('started')
l = w3.eth.getBlock('latest')
print(f'block number: {l}')
print('finished ok')
#app.route('/')
def index():
never_return.apply_async()
return f"hello celery"
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0')
I recently changed my Heroku Python Flask app from the 'small application' format to the 'simple package' format based from flask documentation (De-coupling everything in app.py into separate subdirectories)
The application runs correctly using
> python runserver.py
However, executing
gunicorn runserver:app --log-file=-
outputs:
"Starting gunicorn .... connection in use error" (loops forever)
My runserver.py configuration is:
from re3 import app
app.run(debug=True)
__init__.py configuration:
import os
from flask import Flask
from flask import render_template
app = Flask(__name__)
import views
view.py configuration:
from re3 import app
#app.route('/')
def index():
return 'Hello World!'
What is changing in the two executions?
The problem is that you run your application anytime runserver is imported. You only want that to happen when it's executed directly.
from re3 import app
if __name__ == '__main__':
app.run(debug=True)
Edit:
The usage for gunicorn is
$ gunicorn [OPTIONS] APP_MODULE
When you run gunicorn, it imports APP_MODULE. In your case, you've specified runserver. So while you don't import it yourself, gunicorn does. And before gunicorn can run app, runserver runs it.
I successfully deployed the app and ran the url its shows application error.
Checked the Log, it states:
* Running on http://127.0.0.1:5000/
Web process failed to bind to $PORT within 60 seconds of launch
Procfile
web: python run.py ${PORT}
run.py
from app import app
app.run(debug=False)
I also tried with
from os import environ
from app import app
app.run(debug=False, port=environ.get("PORT", 5000), processes=2)
In both the case the error still persist
views.py
#app.route('/')
#app.route('/login', methods=["GET","POST"])
def login():
....
That's really not how you run a Flask application in production. You need an actual server, such as gunicorn, and you point that to your app object:
web: gunicorn app:app
This is all fully explained in the Heroku tutorial.