我有一个FastAPI应用程序,我在端口30000上使用Uvicorn编程运行。现在我也想在端口8443上运行相同的应用程序。同样的应用程序需要在这两个端口上运行。我如何在Python代码中做到这一点?
最小可复制代码:
from fastapi import FastAPI
import uvicorn
app = FastAPI()
@app.get("/healthcheck/")
def healthcheck():
return 'Health - OK'
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=30000)
我想写
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", ports=[30000,8443])
解释:我的应用程序将在我的组织Azure Kubernetes服务上运行。在30000端口上运行的应用程序为内部HTTP流量保留,在8443端口上运行的应用程序映射到Kubernetes服务的443端口以暴露给外部流量。
更多细节:我将从这个应用程序中创建一个Docker容器,我们的想法是包括
CMD ["python3", "app.py"]
以运行应用程序。我正在寻找一种解决方案,既可以提供一种方法来改变python代码(uvicorn.run(app, host="0.0.0.0", ports=[30000,8443])
),也可以改变Dockerfile中的CMD命令,如This GitHub Issue Comment -gunicorn -k uvicorn.workers.UvicornWorker -w 1 --bind ip1:port1 --bind ip2:port2 --bind ip3:port3
在我的例子中,我使用了上面相同的命令,但做了一点改动。我需要在私有端口上公开其他路由。
app = FastAPI()
app2 = FastAPI()
然后,在run.sh
文件,我有:
uvicorn app.main:app --reload --host 0.0.0.0 --port $PORT & uvicorn app.main:app2 --reload --host 0.0.0.0 --port $PORT_INTERNAL_APP
选项之一是在可变环境中使用docker-compose和传输端口。您只需要部署应用程序的多个实例。该版本还不能用于生产,只是一个最小的示例。
docker-compose.yml
Dockerfile
main.py
requirements.txt
main.py:
from fastapi import FastAPI
import uvicorn
import os
app = FastAPI()
@app.get("/healthcheck/")
def healthcheck():
return 'Health - OK'
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=int(os.getenv('APP_PORT')))
Dockerfile:
FROM python:3.8-slim
WORKDIR /usr/src/app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD [ "python", "./main.py" ]
docker-compose.yml:
version: '2'
services:
internal-app:
image: internal-app
environment:
APP_PORT: "3000"
build:
context: .
dockerfile: ./Dockerfile
restart: unless-stopped
network_mode: host
external-app:
image: external-app
environment:
APP_PORT: "8443"
build:
context: .
dockerfile: ./Dockerfile
restart: unless-stopped
network_mode: host
让:
uvicorn
fastapi
启动-docker-compose up -d --build
将启动2个应用程序,每个应用程序在其自己的端口上。
我建议运行多个副本用于内部和外部通信
uvicorn.run(app, host="0.0.0.0", port=int(os.getenv('PORT')))
所以你的一个部署将运行端口30000和8443在kubernets。
相应地,您可以创建两个服务,一个用于外部通信,一个用于内部通信。
进入流量将获得到运行在8443上的pod的路由,而内部服务调用将获得到运行在30000上的pod的路由。
Ingress > service 1 > deployment 1 with port 8443 > pods
Internal traffic > service 2 > deployment 2 with port 30000 > pods
在两个部署中,您都可以更改Port通过设置环境。
附加点:
- 如果您的单个端口失败或应用程序在内部调用或外部调用期间崩溃(因为将运行两个部署),您的pod部署将不会失败
以下解决方案对我有效。它在后台运行一个gunicorn进程,然后另一个进程将其绑定到两个端口。一个可以使用HTTP,一个可以使用HTTPS。
Dockerfile:
FROM python:3.7
WORKDIR /app
COPY requirements.txt .
RUN pip3 install -r requirements.txt
COPY . .
ENTRYPOINT ./docker-starter.sh
EXPOSE 30000 8443
docker-starter.sh
:
gunicorn -k uvicorn.workers.UvicornWorker -w 3 -b 0.0.0.0:30000 -t 360 --reload --access-logfile - app:app & gunicorn --access-logfile - -k --ca_certs ca_certs.txt uvicorn.workers.UvicornWorker -w 3 -b 0.0.0.0:8443 -t 360 --reload --access-logfile - app:app
python应用程序可以保持最小化:
from fastapi import FastAPI
import uvicorn
app = FastAPI()
@app.get("/healthcheck/")
def healthcheck():
return 'Health - OK'
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0")