Closed will-m-buchanan closed 4 months ago
I think this is related to flask being behind a reserve proxy on k8 that isn't present in your development environment. Have you tried configuring Flask's ProxyFix? I think this is possibly the same issue as was discussed over on this issue, with a few alternative solutions proposed: https://github.com/python-restx/flask-restx/issues/58
Thanks @peter-doggart. That issue was very helpful. What worked for me was a combination of solutions:
I added
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=0, x_proto=0, x_host=0, x_port=0, x_prefix=1)
after defining app
, then I also included
@api.documentation
def custom_ui():
"""Use a custom swagger UI endpoint.
Updates specs_url to point to the custom endpoint.
"""
return render_template("swagger-ui.html",
title=api.title,
specs_url=APPLICATION_ROOT + SWAGGER_SPEC)
@api.route(SWAGGER_SPEC)
@api.hide
class SwaggerDoc(Resource):
"""Endpoint for rendering JSON swagger spec in browser"""
@api.doc(security=[])
def get(self):
"""Modify apischema to customize swagger spec"""
apischema = copy.copy(api.__schema__)
apischema["basePath"] = APPLICATION_ROOT + "/"
return apischema
as per @CpiliotisSTLA's suggestion. Finally, I added
nginx.ingress.kubernetes.io/x-forwarded-prefix: /my-app
to my Ingress
' metadata.annotations
, as per @rodrigocaus' comment. All that seemed to create a cocktail that worked for me!
@will-m-buchanan, Where are the APPLICATION_ROOT and SWAGGER_SPEC definitions?
APPLICATION_ROOT is the root path named in the ingress (/my-app
in my example's case), and SWAGGER_SPEC
is the endpoint that the UI will call on to get the JSON that renders the API docs (/swagger-spec
in my case)
Ask a question I have written a Flask app using
flask-restx
. The docs render properly when I run locally, but not when deployed in k8s.I run locally via a __main__
if
in my main file:This runs fine, and the swagger docs are rendered properly at 127.0.0.1:8899/
In my k8s deployment, I use
gunicorn --bind 0.0.0.0:8899 ...
to run the app, I have aService
that maps 8899 to 8080 and anIngress
that runs myService
on the path "/my-app(/|$)(.*)"This all seems to work such that when I hit the app's endpoints in postman (i.e. my-host.com/my-app/endpointx), I get the responses I'm looking for. However, when I navigate to my-host.com/my-app/, the expected swagger docs do not render. Instead I get a blank page.
Investigating the html, I see that the
<head>
block is rendered properly (so, for instance, the page has<title>My App<\title>
, as defined in the code withBut within the
<body>
block, the div which – locally – contains the main content:<div id="swagger-ui">
, is completely empty in the k8s deployment.The last difference I've been able to find is in
swagger.json
. The swagger json exists at my-host.com/my-app/swagger.json1. The big difference I notice is that at the top level of the json, locally I have"basePath": "\/",
whereas in k8s I have"basePath": "/",
. All other paths are similarly escaped locally but not in k8s. e.g. local:k8s:
Any ideas what is going on?
1: when I navigate here in my browser the file renders in a single wrapped line, whereas locally http://127.0.0.1:8899/swagger.json is pretty-printed. This isn't a big deal that I need to solve I don't think, but it is a curious difference between the local run and the k8s deployment