Docker Compose中FastAPI微服务无法通信问题求助
问题描述
我有两个需要通过REST通信的服务:predict和preprocess。本地通过以下curl命令可以正常调用preprocess服务:
curl -X 'POST' \ 'http://0.0.0.0:3000/preprocess' \ -H 'accept: application/json' \ -H 'Content-Type: application/json' \ -d '{ "feature_1": 1, "feature_2": 2 }'
但将两个服务容器化后,在predict服务内部调用preprocess服务时失败,错误信息如下:
requests.exceptions.ConnectionError: HTTPConnectionPool(host='0.0.0.0', port=3000): Max retries exceeded with url: /preprocess (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7fb53b37ad70>: Failed to establish a new connection: [Errno 111] Connection refused'))
项目结构如下:
项目: ├── predict_service │ ├── main.py │ ├── requirements.txt │ └── Dockerfile ├── preprocess_service │ ├── main.py │ ├── requirements.txt │ └── Dockerfile └── docker-compose.yml
相关配置文件
predict_service的Dockerfile
FROM python:3.10 WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir --upgrade -r requirements.txt COPY . . EXPOSE 8000 CMD ["uvicorn", "main:app", "--host", "0.0.0.0"]
preprocess_service的Dockerfile
FROM python:3.10 WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir --upgrade -r requirements.txt COPY . . EXPOSE 3000 CMD ["uvicorn", "main:app", "--host", "0.0.0.0"]
docker-compose.yml
version: "3" services: predict_service: image: dockerplaygroundpredict:latest command: uvicorn main:app --host 0.0.0.0 ports: - "8000:8000" preprocess_service: image: dockerplaygroundpreprocess:latest command: uvicorn main:app --host 0.0.0.0 ports: - "3000:8000"
predict_service的main.py核心代码
app = FastAPI( title="SIMPLE FASTAPI POC", description="----> PREDICTION", version="0.1" ) @app.get("/") def read_root(): """Health check.""" return {"message": HTTPStatus.OK.phrase, "status-code": HTTPStatus.OK,} @app.post("/predict", tags=["Prediction"]) def predict(request: Request, sample: FeatureSample) -> Dict: """Predict output for sample input.""" headers = { 'accept': 'application/json', } json_data = { 'feature_1': 1, 'feature_2': 2, } preprocessing_response = requests.post('http://0.0.0.0:3000/preprocess', headers=headers, json=json_data) return {"message": HTTPStatus.OK.phrase, "status-code": HTTPStatus.OK, "data": {"predictions": "Dummy_Prediction"}}
错误原因分析
容器间调用地址错误:
在predict服务的代码中,使用http://0.0.0.0:3000/preprocess发起请求,但容器内的0.0.0.0指向当前predict容器自身,而非宿主机的3000端口。在Docker Compose创建的默认网络中,服务之间需要通过服务名称(而非IP或0.0.0.0)作为主机名来通信。端口配置不一致:
- preprocess服务的Dockerfile中
EXPOSE 3000,但启动命令未指定端口,uvicorn默认运行在8000端口,导致声明暴露的端口与实际运行端口不符。 - docker-compose.yml中preprocess的端口映射为
3000:8000(宿主机3000映射到容器8000),本地curl能正常访问是因为走了宿主机端口,但容器内部调用需要使用容器内的实际服务端口8000,而非宿主机的3000端口。
- preprocess服务的Dockerfile中
修复步骤
步骤1:修正predict服务的调用地址
修改predict_service/main.py中的请求地址,将http://0.0.0.0:3000/preprocess替换为http://preprocess_service:8000/preprocess(preprocess_service是docker-compose.yml中定义的服务名称,8000是preprocess容器内服务的实际运行端口):
preprocessing_response = requests.post('http://preprocess_service:8000/preprocess', headers=headers, json=json_data)
步骤2:统一preprocess服务的端口配置(可选但推荐)
为了避免端口混淆,建议让preprocess服务的声明端口与实际运行端口一致:
- 修改preprocess_service/Dockerfile的启动命令,指定端口为3000:
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "3000"] - 同步修改docker-compose.yml中preprocess的端口映射:
此时predict服务的调用地址也需要同步改为preprocess_service: image: dockerplaygroundpreprocess:latest command: uvicorn main:app --host 0.0.0.0 --port 3000 ports: - "3000:3000"http://preprocess_service:3000/preprocess。
步骤3:重启服务
执行以下命令重新构建镜像并启动容器:
docker-compose down docker-compose build docker-compose up -d
内容的提问来源于stack exchange,提问作者Joe Dawson

