Closed davidwynter closed 4 years ago
Check the docs here: https://github.com/tiangolo/uwsgi-nginx-flask-docker#serve-indexhtml-directly
For instructing Nginx to serve your static files directly. That's more efficient than going through your Flask app.
Then here for setting a custom directory in where those static files are stored: https://github.com/tiangolo/uwsgi-nginx-flask-docker#custom-static-path
Thank you for that. It will improve efficiency to have nginx serve them.
But more important to me currently is getting my dynamically produce json from flask_restful served. I cannot see anything in the documentation that covers this
But more important to me currently is getting my dynamically produce json from flask_restful served. I cannot see anything in the documentation that covers this
Sorry, I'm not sure I understand what you refer to with this.
The following does not work, i.e. the classes I have created to respond to individual restul api calls are not being reached. Sorry but flask_restful is not clear, more like magic.
from flask_restful import Api
...
api = Api(app)
api.add_resource(resources.Login, '/api/login', methods=['POST'])
The 1st argument sets up the class that responds to the restful api call, the 2nd and 3rd are equivalent to the @app.post('api/login') annotation in normal flask. The resources.Login method in resources.py module looks like this:
class Login(Resource):
def post(self):
...
return {
'message': 'Logged in as {}'.format(email),
'access_token': access_token,
'refresh_token': refresh_token,
'requires_totp': str(user.totp),
'layout': app_layout,
'anon': anon,
'role': str(user.role)
}
It is not clear if this uses werkzurg or if uwsgi is suitable. Maybe I cannot use flask_restful? Actually, maybe I am completely off track? Originally I used a location in nginx.conf to pass the /api resful calls to my app
location /api {
proxy_redirect off;
proxy_pass_header Server;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Scheme $scheme;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;
proxy_connect_timeout 5;
proxy_read_timeout 240;
proxy_intercept_errors on;
proxy_pass http://127.0.0.1:5000;
}
I include this now except use port 80 as uwsgi is listening on that port, whereas werkzurg listened on port 5000
Hmm, this shouldn't have anything to do with this image.
Independent of how flask-restful works, it would expose a single Flask app (technically, a WSGI app).
You shouldn't need to add any specific additional configurations to Nginx for it to work.
Try with the simplest example you can imagine. And see if it works correctly. Then increase that example slowly to what you have in your actual app. At the point that it breaks, you should check what might be wrong in your code (or even in flask-restful itself).
But if the simplest example works, there's a very low chance that additional changes to your app would need changes in the image configurations.
As a side note, if you don't already have your app built but you need to use Flask, I would suggest using Flask-apispec. I tested Flask-restful and several others before finding it and it ended up working better.
If you don't have any code yet and you don't depend on Flask, I would suggest you try FastAPI. It includes a lot of the learnings from several previous frameworks. And is designed from the beginning to have autocomplete everywhere and be super easy to learn, understand, and use.
I have a big hint here in the log. When my flask app starts up it has to build a large in memory cache of pre-calculated analytical data used for graphs in the React front end. I think that something in uwsgi is terminating (SIGTERM) while I am building the cache:
DEBUG:apscheduler.scheduler:Next wakeup is due at 2019-05-31 06:00:00+00:00 (in 70367.536472 seconds)
WSGI app 0 (mountpoint='') ready in 10 seconds on interpreter 0x563ac96c4f70 pid: 14 (default app)
uWSGI running as root, you can use --uid/--gid/--chroot options
*** WARNING: you are running uWSGI as root !!! (use the --uid flag) ***
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI master process (pid: 14)
spawned uWSGI worker 1 (pid: 45, cores: 1)
spawned uWSGI worker 2 (pid: 46, cores: 1)
running "unix_signal:15 gracefully_kill_them_all" (master-start)...
2019/05/30 10:30:22 [alert] 15#15: 1024 worker_connections are not enough
2019/05/30 10:30:22 [error] 15#15: *1023 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 127.0.0.1, server: localhost, request: "POST /api/login HTTP/1.0", upstream: "http://127.0.0.1:80/api/login", host: "localhost", referrer: "http://localhost/login"
2019/05/30 10:30:22 [error] 15#15: *1023 open() "/app/ui/50x.html" failed (2: No such file or directory), client: 127.0.0.1, server: localhost, request: "POST /api/login HTTP/1.0", upstream: "http://127.0.0.1:80/api/login", host: "localhost", referrer: "http://localhost/login"
127.0.0.1 - - [30/May/2019:10:30:22 +0000] "POST /api/login HTTP/1.0" 404 555 "http://localhost/login" "Mozilla/5.0 (X11; L
inux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36 OPR/60.0.3255.27" "172.17.0.1, 127.0.
0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.
1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1,
127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 1
27.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127
.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0.0.1, 127.0
...
There are pages and pages of those 127.0.0.1, entries in the log, any way I can cut them down so the log is more easily readable?
Something else concerns me this message in the log "POST /api/login HTTP/1.0" 404 2293 "http://localhost/login"
when the flask_restful is listening on api.add_resource(resources.Login, '/api/login', methods=['POST'])
i.e. http://localhost/api/login
I did what you asked and created a minimal application using flask-restful, it gets this error:
(general) (base) david@david-desktop:~/gitlab/docker_restful_test$ curl http://localhost:5000/todo1 -d "data=Remember the milk" -X PUT
curl: (56) Recv failure: Connection reset by peer
Using this Dockerfile:
FROM tiangolo/uwsgi-nginx-flask:python3.7
# Copy app
COPY ./*.py /app/
COPY conf/uwsgi.ini /app
COPY requirements.txt /tmp/
RUN pip install -U pip && pip install -U sphinx && pip install -r /tmp/requirements.txt
EXPOSE 5000
requirements.txt:
flask
flask_restful
Flask-Cors
from this code
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
todos = {}
class TodoSimple(Resource):
def get(self, todo_id):
return {todo_id: todos[todo_id]}
def put(self, todo_id):
todos[todo_id] = request.form['data']
return {todo_id: todos[todo_id]}
api.add_resource(TodoSimple, '/<string:todo_id>')
if __name__ == '__main__':
app.run(debug=True)
I use this docker run command
docker run --name restfultest -d -e URL=http://localhost -p 5000:5000 --rm -e WORKERS_PER_CORE="0.125" -e MODULE_NAME="webapp" fairgo/dockerrestfultest:v01
. The docker logs restfultest
shows no errors, last 2 lines
2019-06-03 15:58:54,993 INFO success: uwsgi entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
The example is straight out of https://flask-restful.readthedocs.io/en/0.3.5/quickstart.html
This keep happening! Ping!
+1
I get the following error when using this image:
Not Found
The requested URL was not found on the server. If you entered the URL manually please check > your spelling and try again.
Here the config I'm using:
.Dockerfile
FROM tiangolo/uwsgi-nginx-flask:python3.6-alpine3.7
LABEL Name=myappname Version=0.0.1
EXPOSE 3000
ENV LISTEN_PORT=3000
WORKDIR /app
ADD . /app
RUN python -m pip install -r requirements.txt
docker-compose.yml
version: '3.3'
services:
myappname:
image: myappname
build: .
ports:
- 3000:3000
links:
- db
depends_on:
- db
environment:
- MONGO_DB_HOST=db
db:
image: mongo
main.py
from flask import Flask
from flask_restful import Api
from event import Event, EventList
app = Flask(__name__)
api = Api(app)
##
# Actually setup the Api resource routing here
##
api.add_resource(EventList, '/api/v1/events')
api.add_resource(Event, '/api/v1/events/<string:event_id>')
if __name__ == '__main__':
app.run(debug=True)
I don't use Flask-Restful, as I would instead use FastAPI :man_shrugging: , but anyway, here's a working example:
.
├── app
│ ├── main.py
│ └── uwsgi.ini
├── Dockerfile
└── requirements.txt
app/main.py
:
from flask import Flask, request
from flask_restful import Resource, Api
app = Flask(__name__)
api = Api(app)
todos = {}
class TodoSimple(Resource):
def get(self, todo_id):
return {todo_id: todos[todo_id]}
def put(self, todo_id):
todos[todo_id] = request.form['data']
return {todo_id: todos[todo_id]}
api.add_resource(TodoSimple, '/rest/<string:todo_id>')
@app.route("/hello")
def hello():
return "Hello"
if __name__ == '__main__':
app.run(debug=True)
app/uwsgi.ini
:
[uwsgi]
module = main
callable = app
Dockerfile
:
FROM tiangolo/uwsgi-nginx-flask:python3.7
COPY requirements.txt /tmp/
RUN pip install -r /tmp/requirements.txt
COPY ./app /app
requirements.txt
:
flask
flask_restful
$ docker build -t restfully .
---> 100%
$ docker run -d --name restfully -p 80:80 restfully
c61078da16d22
// Check that standard Flask works
$ curl http://localhost/hello
Hello
$ curl http://localhost/rest/todo1 -d "data=Remember the milk" -X PUT
{"todo1": "Remember the milk"}
$ curl http://localhost/rest/todo1
// Error because it was probably served by one of the processes that don't have the dict in memory, still, you wouldn't store that in memory but in a DB
{"message": "Internal Server Error"}
// But try again
$ curl http://localhost/rest/todo1
// It's probably served by the process that has the dict in memory
{"todo1": "Remember the milk"}
I hope that can help to guide you to solve your own issues.
Hi! I'm facing the same issue and I made some test that maybe can help. I think the problem, at least for me, is with structured projects. The last test I did is with a tree like this:
├── app │ ├── app │ │ ├── init.py │ │ ├── main.py │ └── uwsgi.ini └── Dockerfile
Using a plain flask @app.route, it works perfect. But when I change the plain flask to the flask_restplus way, then I have a 404 error.
Can the issue be related to that?
@noktus I wouldn't know for sure.
I personally don't use Flask-Restful or Flask-Resplus, when I tried them the best combination for me was Fask-apispec with Marshmallow and Webargs.
But after that, I built FastAPI heavily inspired by those ideas, and improving them with the new tools in modern Python, like type annotations.
But it seems that similar errors would probably not be related to this image but to the framework configuration directly...
Maybe you can check the example I provided above and adapt it to your use case and it might help you find where's the problem.
@davidwynter if you solved your problem, then you can close the issue.
Assuming the original issue was solved, it will be automatically closed now. But feel free to add more comments or create new issues.
Subsequent to my last issue I now have SPA React pages served from my docker container.
But the flask_restful implementation seems to hide the route information normally exposed using the @app.route annotation. My main.py (webapp.py in my case) has the following:
The additional nginx config, derived from what I has when running native with werkzurg serving on port 5000 is as follows:
I realise that uwsgi is not serving on port 5000, but it is not clear on what changes I need to make.