三公机器人

牛牛机器人,三公撑船机器人,微信牛牛机器人

三公机器人 你的FastAPI又在服务器上“跑不起来”了?今天把打包部署彻底聊透


做Python后端开发,谁没踩过FastAPI打包的坑?本地跑的好好的服务,传到服务器上缺依赖、端口不对、路径乱码,甚至连uvicorn都找不到——折腾大半天,最后发现就是打包环节没做对,白瞎了一下午开发时间。


今天把FastAPI从开发到生产的打包方案全梳理一遍,从最简单的单文件打包,到容器化、生产级镜像优化,全覆盖,看完你再不会遇到“本地好好的,线上跑不起来”的问题。


先理清楚:FastAPI部署到底要打包什么?


很多新手刚入门会搞混:FastAPI本身只是一个Web框架,你的服务跑起来,其实需要三个部分:


你的业务代码‌:写的接口、路由、工具函数这些

Python依赖环境‌:FastAPI本身、uvicorn、pydantic,还有你用的各种第三方库

运行入口‌:启动服务的命令、绑定的IP/端口配置


打包出问题,90%都是这三个部分某一个没对齐:要么本地Python版本和服务器不一样,要么依赖漏装,要么路径写死导致找不到文件。接下来我们从最简单到最复杂,一个个说方案。


方案一:最基础的requirements.txt打包——小项目够用,新手入门首选


这是最传统、最简单的方案,适合个人小项目、原型验证,不需要学复杂工具,两步就能搞定。


第一步:本地导出依赖,别直接pip freeze


很多人习惯直接pip freeze > requirements.txt,但这个方法会把你本地所有的包都导进去,包括开发调试用的工具、你根本没用到的依赖,传到服务器安装慢还容易冲突。


正确做法是用pipreqs只导出你项目实际用到的依赖:


bash

# 安装pipreqs

pip install pipreqs

# 在项目根目录生成requirements.txt,会自动扫描你import的包

pipreqs . --force



生成之后打开requirements.txt检查一下,FastAPI和uvicorn肯定要有,一般长这样:


txt

fastapi>=0.100.0

uvicorn[standard]>=0.27.0

pydantic>=2.0.0


第二步:服务器部署,对齐Python版本


打包流程:


把你的项目代码(除了本地虚拟环境、__pycache__这些)打包成zip传到服务器

服务器上先装和你本地‌大版本一致‌的Python(比如本地用3.11,服务器就装3.11,别差大版本)

新建虚拟环境隔离依赖,避免和系统Python冲突:

bash

python3 -m venv venv

source venv/bin/activate

# 安装依赖

pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple


启动服务,注意IP一定要写0.0.0.0,不然只能本地访问:

bash

uvicorn main:app --host 0.0.0.0 --port 8000


这个方案的坑&解决方法:


❌ 坑1:启动提示No module named 'main'——大概率是你没在项目根目录启动,或者你的入口文件名不是main.py,改成你实际的文件名就行:uvicorn your_filename:app

❌ 坑2:本地正常,服务器报依赖版本冲突——就是因为直接pip freeze导了太多无用依赖,用pipreqs重新生成就好

✅ 优点:简单不用学额外工具,适合小项目

❌ 缺点:环境对齐麻烦,多项目部署容易依赖冲突,要自己维护进程守护


方案二:单文件可执行打包——不用装Python,一个文件就能跑


如果不想在服务器装Python环境,想打一个直接运行的二进制包,可以用PyInstaller打包,适合给客户交付独立服务、轻量工具类FastAPI项目。


打包步骤:

安装PyInstaller:

bash

pip install pyinstaller


在项目根目录新建build.spec配置文件,核心要把静态文件、隐式依赖加进去,不然打包完找不到:

python

import sys

from pathlib import Path


# 你的入口文件

entry_file = "main.py"

# 项目根目录

root = Path(".")


a = Analysis(

    [entry_file],

    pathex=[str(root)],

    # 如果你有静态文件、模板文件夹,要加到这里

    datas=[

        ("static", "static"), 

        ("templates", "templates")

    ],

    hiddenimports=[

        "uvicorn.logging",

        "uvicorn.lifespan",

        "pydantic.deprecated",

    ],

    hookspath=[],

    runtime_hooks=[],

    excludes=[],

    win_no_prefer_redirects=False,

    win_private_assemblies=False,

    cipher=None,

    noarchive=False,

)

pyz = PYZ(a.pure, a.zipped_data, cipher=None)

exe = EXE(

    pyz,

    a.scripts,

    a.binaries,

    a.zipfiles,

    a.datas,

    [],

    name='fastapi-service',

    debug=False,

    bootloader_ignore_signals=False,

    strip=False,

    upx=True,

    upx_exclude=[],

    runtime_tmpdir=None,

    console=True, # 控制台输出日志,调试方便

    disable_windowed_traceback=False,

    target_arch=None,

    codesign_identity=None,

    entitlements_file=None,

)


执行打包:

bash

pyinstaller build.spec



打包完成后,在dist文件夹里会得到一个fastapi-service二进制文件,直接传到服务器运行就行:


bash

./fastapi-service


这个方案的坑&优化:


❌ 坑1:打包后的文件特别大,几十M很正常——因为把整个Python环境都打进去了,接受不了就用UPX压缩,能小一半

❌ 坑2:动态导入的模块会找不到——一定要在hiddenimports里加进去,比如你用了sqlalchemy,就要把相关模块加进去

✅ 优点:不用装Python,一个文件就能跑,部署简单

❌ 缺点:文件大,跨平台打包麻烦(本地Mac打包的不能在Linux跑),不适合中大型项目


方案三:Docker容器化打包——生产环境首选,一次打包到处运行


这是现在生产环境FastAPI的标准打包方案,彻底解决“环境不一致”的问题,不管你在哪开发,打包完镜像在哪都能跑起来。


标准Dockerfile写法(带优化):


别用网上那种几行的基础写法,那种打包出来镜像几个G,我们用多阶段构建,最后镜像能控制在100M以内:


dockerfile

# 第一阶段:构建依赖,只装需要的包,缓存分层

FROM python:3.11-slim AS builder


# 设置pip镜像源,加速下载

RUN pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple


# 新建工作目录

WORKDIR /app


# 先复制requirements,利用Docker缓存,没改依赖就不用重新装

COPY requirements.txt .

RUN pip install --user -r requirements.txt


# 第二阶段:运行阶段,只留运行需要的内容,最小化镜像

FROM python:3.11-slim AS final


WORKDIR /app


# 从builder阶段复制装好的依赖过来

COPY --from=builder /root/.local /root/.local

# 复制你的项目代码

COPY . .


# 暴露端口

EXPOSE 8000


# 启动命令,一定要加--host 0.0.0.0

CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]


.dockerignore文件(一定要加,不然镜像会很大):

text

__pycache__

venv

.git

.gitignore

.env

*.pyc

*.pyo

*.pyd

.DS_Store


打包&运行命令:

bash

# 打包镜像,tag命名方便管理

docker build -t fastapi-service:v1 .


# 运行容器,映射端口,后台运行

docker run -d -p 8000:8000 --name fastapi-service fastapi-service:v1


生产级优化:

用非root用户运行‌:避免容器权限风险,在Dockerfile最后加上:

dockerfile

RUN useradd -m appuser

USER appuser


配合docker-compose做多服务编排‌:如果你需要同时连MySQL、Redis,直接写docker-compose.yml一键启动,不用单独一个个装。

开启uvicorn多进程模式‌:利用多核CPU提升性能,启动命令改成:

bash

CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]



workers数量一般设成CPU核心数的2倍+1就行。


✅ 优点:环境一致,部署方便,可扩展,适合生产

❌ 缺点:需要学Docker基础,对新手有一点门槛


三个通用坑,90%的人都踩过


不管用哪个打包方案,这几个坑几乎每个人都遇到过,提前避开省时间:


IP绑定错‌:永远别写--host 127.0.0.1,服务器上这么写,外部根本访问不到,一定要写0.0.0.0

硬编码绝对路径‌:比如你本地把配置文件放在/Users/xxx/project/config.py,传到服务器肯定找不到,永远用相对路径,或者通过环境变量配置路径:

python

from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent

CONFIG_PATH = BASE_DIR / "config.yaml"


端口被占用‌:服务器上启动提示端口已被占用,要么换端口,要么杀掉占用端口的进程:lsof -i:8000找到PID,然后kill -9 PID就行

总结:不同场景选不同方案

表格

场景 推荐方案 优势

新手入门、个人小项目 requirements.txt打包 简单,不用额外工具

独立工具、交付单服务 PyInstaller单文件打包 不用装Python,部署极简

生产环境、中大型项目 Docker容器化 环境一致,易扩展,稳定


只要把打包环节的这几件事做对,FastAPI基本不会再出现“本地好好的,线上跑不起来”的问题,选对适合自己项目的方案,比瞎折腾半天有用多了。


Powered By Z-BlogPHP 1.7.3

三公机器人,牛牛机器人,三公撑船机器人,微信牛牛机器人