FastAPI 文档不适用于 nginx Ingress 控制器
FastAPI docs not working with nginx Ingress controller
我编写了一个在 Kubernetes pod 中运行 FastAPI 服务器的应用程序。与 pod 的外部通信通过单独 pod 中的 nginx 入口控制器。我是运行nginx:1.17.0.
当它全部启动并且 运行 我可以使用 curl
调用通过入口地址与应用服务器交互,并访问所有简单的 GET 路径以及 address/openapi.json 在我的浏览器中。如果我在 Kubernetes 中使用应用服务的内部 ip,我也可以访问交互式文档页面。
然而,尝试访问交互式文档页面 (address/docs#/default/) 给我一个关于 /openapi.json 的错误.
由于 curl
调用按预期工作,我认为问题不一定出在入口定义中,但由于使用应用程序的内部 ip 也可以正常工作,因此问题不应该出在应用程序内部。
我在下面包含了入口定义文件。
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-nginx-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.17.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: my-host.info
http:
paths:
- path: /server(/|$)(.*)
backend:
serviceName: my-app-service # This is the service that runs my fastAPI server pod
servicePort: 80
编辑
这是 service.yaml 文件
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
type: ClusterIP
selector:
app: server
ports:
- protocol: "TCP"
port: 80
targetPort: 80
由于该服务是我本地集群中的一个 ClusterIP,我可能可以直接 curl 到它,不过我还没有尝试过。当我卷曲时,我使用像
这样的命令
curl -X GET "http://my-host.info/server/subpath/" -H "accept: application/json"
curl -X POST "http://my-host.info/server/subpath/update/" -H "accept: application/json"
来自本地集群之外。
这些是 运行 的所有服务:
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 11d
default my-app-service ClusterIP 10.96.68.29 <none> 80/TCP 18h
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 28d
kubernetes-dashboard dashboard-metrics-scraper ClusterIP 10.96.114.1 <none> 8000/TCP 28d
kubernetes-dashboard kubernetes-dashboard ClusterIP 10.96.249.255 <none> 80/TCP 28d
在我的 /etc/hosts
文件中,我已将 10.0.0.1(集群 "external" IP)连接到 my-host.info.
知道为什么会这样吗?
我认为您绝对应该查看 FastApi 的官方文档:https://fastapi.tiangolo.com/advanced/behind-a-proxy/
正如您所提到的,在内部访问您的应用程序时,Swagger auto 文档工作正常,但是当从集群外部访问时,您遇到了关于 /openapi.json.
的错误
在你的 service.yaml
你有:
- path: /server(/|$)(.*)
backend:
serviceName: my-app-service # This is the service that runs my fastAPI server pod
servicePort: 80
并且在使用 uvicorn 启动您的应用程序时,您应该通过 root_path
uvicorn main:app --root-path /server
注意:在这里您将能够访问路由器端点,但不能访问 Swagger 文档。为了获得 Swagger 文档,您必须编辑主 main.py
文件:
from fastapi import FastAPI, Request
app = FastAPI(openapi_prefix="/server")
@app.get("/")
def read_root(request: Request):
return {"message": "Hello World", "root_path": request.scope.get("root_path")}
我搜索了为什么我们需要显式传递 OpenApi 前缀,但我只找到了解决方法,例如:https://github.com/iwpnd/fastapi-aws-lambda-example/issues/2
所以我建议将 root_path
存储在系统上的环境变量 $ROOT_PATH=/server
中并将其传递给 uvicorn main:app --root-path $ROOT_PATH
以及 main.py
:
import os
from fastapi import FastAPI, Request
app = FastAPI(openapi_prefix=os.getenv('ROOT_PATH', ''))
@app.get("/")
def read_root(request: Request):
return {"message": "Hello World", "root_path": request.scope.get("root_path")}
更新 07.07.2020
目前可以使用 tiangolo docker 图片 https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker are "outdated" if goes on fastapi version which currently is: 0.55.1 - reported here: link
"root_path" 自 0.56.0
起受支持
使用 Kubernetes rewrite feature for ingress 我可以这样解决我的问题:
ingress.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: my-app
http:
paths:
- path: /server(/|$)(.*)
pathType: Prefix
backend:
service:
name: my-fastapi
port:
number: 80
然后我只需要将 root_path 添加到我的 FastAPI 应用程序:
app = FastAPI(root_path="/server")
我编写了一个在 Kubernetes pod 中运行 FastAPI 服务器的应用程序。与 pod 的外部通信通过单独 pod 中的 nginx 入口控制器。我是运行nginx:1.17.0.
当它全部启动并且 运行 我可以使用 curl
调用通过入口地址与应用服务器交互,并访问所有简单的 GET 路径以及 address/openapi.json 在我的浏览器中。如果我在 Kubernetes 中使用应用服务的内部 ip,我也可以访问交互式文档页面。
然而,尝试访问交互式文档页面 (address/docs#/default/) 给我一个关于 /openapi.json 的错误.
由于 curl
调用按预期工作,我认为问题不一定出在入口定义中,但由于使用应用程序的内部 ip 也可以正常工作,因此问题不应该出在应用程序内部。
我在下面包含了入口定义文件。
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-nginx-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.17.0
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: my-host.info
http:
paths:
- path: /server(/|$)(.*)
backend:
serviceName: my-app-service # This is the service that runs my fastAPI server pod
servicePort: 80
编辑
这是 service.yaml 文件
apiVersion: v1
kind: Service
metadata:
name: my-app-service
spec:
type: ClusterIP
selector:
app: server
ports:
- protocol: "TCP"
port: 80
targetPort: 80
由于该服务是我本地集群中的一个 ClusterIP,我可能可以直接 curl 到它,不过我还没有尝试过。当我卷曲时,我使用像
这样的命令curl -X GET "http://my-host.info/server/subpath/" -H "accept: application/json"
curl -X POST "http://my-host.info/server/subpath/update/" -H "accept: application/json"
来自本地集群之外。
这些是 运行 的所有服务:
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 11d
default my-app-service ClusterIP 10.96.68.29 <none> 80/TCP 18h
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 28d
kubernetes-dashboard dashboard-metrics-scraper ClusterIP 10.96.114.1 <none> 8000/TCP 28d
kubernetes-dashboard kubernetes-dashboard ClusterIP 10.96.249.255 <none> 80/TCP 28d
在我的 /etc/hosts
文件中,我已将 10.0.0.1(集群 "external" IP)连接到 my-host.info.
知道为什么会这样吗?
我认为您绝对应该查看 FastApi 的官方文档:https://fastapi.tiangolo.com/advanced/behind-a-proxy/
正如您所提到的,在内部访问您的应用程序时,Swagger auto 文档工作正常,但是当从集群外部访问时,您遇到了关于 /openapi.json.
的错误在你的 service.yaml
你有:
- path: /server(/|$)(.*)
backend:
serviceName: my-app-service # This is the service that runs my fastAPI server pod
servicePort: 80
并且在使用 uvicorn 启动您的应用程序时,您应该通过 root_path
uvicorn main:app --root-path /server
注意:在这里您将能够访问路由器端点,但不能访问 Swagger 文档。为了获得 Swagger 文档,您必须编辑主 main.py
文件:
from fastapi import FastAPI, Request
app = FastAPI(openapi_prefix="/server")
@app.get("/")
def read_root(request: Request):
return {"message": "Hello World", "root_path": request.scope.get("root_path")}
我搜索了为什么我们需要显式传递 OpenApi 前缀,但我只找到了解决方法,例如:https://github.com/iwpnd/fastapi-aws-lambda-example/issues/2
所以我建议将 root_path
存储在系统上的环境变量 $ROOT_PATH=/server
中并将其传递给 uvicorn main:app --root-path $ROOT_PATH
以及 main.py
:
import os
from fastapi import FastAPI, Request
app = FastAPI(openapi_prefix=os.getenv('ROOT_PATH', ''))
@app.get("/")
def read_root(request: Request):
return {"message": "Hello World", "root_path": request.scope.get("root_path")}
更新 07.07.2020
目前可以使用 tiangolo docker 图片 https://github.com/tiangolo/uvicorn-gunicorn-fastapi-docker are "outdated" if goes on fastapi version which currently is: 0.55.1 - reported here: link
"root_path" 自 0.56.0
起受支持使用 Kubernetes rewrite feature for ingress 我可以这样解决我的问题:
ingress.yaml:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: my-app
http:
paths:
- path: /server(/|$)(.*)
pathType: Prefix
backend:
service:
name: my-fastapi
port:
number: 80
然后我只需要将 root_path 添加到我的 FastAPI 应用程序:
app = FastAPI(root_path="/server")