[特殊字符] Docker + FastAPI + PostgreSQL 项目部署避坑指南:从 nc: not found 到 Nginx 500 的完整排查与解决
·
作者:懒人
环境:Ubuntu 22.04 + Docker Compose + FastAPI + PostgreSQL + Nginx(前端容器)
关键词:Docker、FastAPI、PostgreSQL、Nginx、docker-compose、netcat、500错误、端口映射
💡 背景
在使用 Docker Compose 部署一个包含 FastAPI 后端、PostgreSQL 数据库 和 Nginx 前端 的全栈应用时,遇到了两个典型问题:
- 后端启动卡在
Waiting for database...,日志提示sh: 1: nc: not found - 访问
/docs(Swagger UI)时返回 Nginx 500 Internal Server Error
经过多次调试,最终成功解决。本文总结关键踩坑点和最佳实践,供后来者参考。
🔧 问题一:nc: not found —— 后端无法检测数据库就绪
❌ 现象
后端容器日志循环打印:
Waiting for database...
sh: 1: nc: not found
✅ 原因
- 后端启动脚本使用
nc -z host port检测数据库是否可用 - 但基础镜像(如
python:3.11-slim)默认不包含netcat工具 - 导致检测失败,无限等待
✅ 解决方案:在 Dockerfile 中安装 netcat-openbsd
# backend/Dockerfile
FROM python:3.11-slim
WORKDIR /app
ENV PYTHONPATH=/app
# 安装系统依赖(含 netcat)
RUN apt-get update && \
apt-get install -y --no-install-recommends \
libpq-dev \
gcc \
netcat-openbsd \
&& rm -rf /var/lib/apt/lists/*
# ... 其他步骤(pip install、COPY 等)
# 创建非 root 用户(安全)
RUN addgroup --system app && adduser --system --ingroup app app
RUN chown -R app:app /app
USER app
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
⚠️ 注意:Alpine 镜像请用
apk add netcat-openbsd
🛠 问题二:必须重建镜像才能生效!
❌ 错误操作
# 仅重启,不重建 → 无效!
docker compose restart backend
✅ 正确流程
# 1. 修改 Dockerfile 后,必须 rebuild
docker compose build backend
# 2. 再启动
docker compose up -d
📌 Docker 不会自动感知 Dockerfile 变更!必须手动
build
🌐 问题三:Nginx 返回 500 —— 端口不一致 or 代理未配置
❌ 现象
访问 http://IP/docs 返回 500 Internal Server Error
✅ 根本原因分析
情况 1:后端实际监听端口 ≠ 映射端口
# docker-compose.yml
command: uvicorn ... --port 8080 # 实际监听 8080
ports:
- "8000:8000" # 但只映射了 8000!
→ 宿主机无法通过 8000 访问,Nginx 代理失败。
情况 2:前端 Nginx 未配置反向代理
- 如果前端是纯静态 Nginx 容器(无代理配置)
- 访问
/docs会被当成静态资源 → 404/500
✅ 解决方案
✅ 方案 A:统一使用 8000 端口(推荐)
# docker-compose.yml
services:
backend:
command: >
sh -c "while ! nc -z note-db 5432; do sleep 2; done;
uvicorn main:app --host 0.0.0.0 --port 8000"
ports:
- "8000:8000" # 宿主机 8000 → 容器 8000
✅ 方案 B:若用 8080,需暴露并代理
ports:
- "8080:8080"
并在前端 Nginx 配置中添加:
location /docs {
proxy_pass http://backend:8080;
}
location /api/ {
proxy_pass http://backend:8080;
}
🔑 关键:
proxy_pass中的服务名必须是docker-compose.yml中的 服务名(如backend),不是container_name!
🧪 调试技巧
1. 查看服务名(不是容器名!)
docker compose config --services
# 输出:db, backend, frontend
2. 直连后端测试(绕过 Nginx)
curl http://localhost:8000/docs
3. 进入 Nginx 容器测试连通性
docker exec -it note-frontend sh
apk add curl
curl http://backend:8000/docs # 应返回 HTML
4. 清理重建(开发阶段推荐)
docker compose down -v # -v 删除卷(清空数据库)
docker compose build backend
docker compose up -d
⚠️
-v会丢失数据库数据,生产环境慎用!
✅ 最终架构建议
# docker-compose.yml(精简版)
services:
db:
image: postgres:15
container_name: note-db
environment: { ... }
volumes: [pgdata:/var/lib/postgresql/data]
networks: [app-net]
backend:
build: ./backend
container_name: note-backend
command: sh -c "while ! nc -z db 5432; do sleep 2; done; uvicorn main:app --host 0.0.0.0 --port 8000"
ports: ["8000:8000"]
depends_on: [db]
networks: [app-net]
frontend:
build: ./frontend # 内含 Nginx + 代理配置
ports: ["80:80"]
networks: [app-net]
networks:
app-net:
volumes:
pgdata:
🎯 总结:关键注意事项
| 问题 | 注意点 |
|---|---|
nc: not found | 必须在 Dockerfile 安装 netcat-openbsd |
| 服务名 vs 容器名 | docker compose build 用 服务名,docker logs 用 容器名 |
| 端口一致性 | uvicorn --port 必须与 ports 映射端口一致 |
| Nginx 500 | 检查 proxy_pass 是否指向正确的 服务名:端口 |
| 重建镜像 | 修改 Dockerfile 后必须 docker compose build |
| 数据库初始化 | PostgreSQL 日志中的“shutdown”是正常流程,非错误 |
❤️ 结语
Docker Compose 是强大的工具,但细节决定成败。
日志是第一线索,网络和端口是高频陷阱。
希望本文能帮你少走弯路,快速部署成功!
✨ 记住:90% 的“连不上”问题,都是因为服务名、端口、网络或镜像未更新!
更多推荐
所有评论(0)