一个 AI 项目从本地到上线,要经过哪些步骤?全流程讲清楚

0 阅读6分钟

d4741e28-1980-4ed7-bc53-bcd5a399fad1.png

一、故事的开头:本地跑通了,然后呢?

前段时间,我做完了一个 AI 项目—— 学面通AI。前端、后端、数据库、向量库都已经在本地跑得好好的:打开 localhost,功能一切正常。但是要怎样才把这个项目上线?让其他人也能在线上访问

我把这条路走了一遍,发现可以拆成三块:

  1. 基础设施:服务器、域名、证书,先把“地基”打好;
  2. 工程化改造:容器化、网关、数据持久化,让项目具备“上线的资格”;
  3. 部署执行:真正把代码送上去,让服务跑起来。

这篇文章是整个部署系列的总览,先带你把全局地图看清楚,后面的章节再逐个动手实操。

二、第一步:先有一台“永不关机的电脑”——云服务器

本地电脑要关机、要断网、没有公网地址,显然不能拿来对外提供服务。

所以第一件事是购买一台云服务器:它本质上就是一台放在云端、24 小时开机的 Linux 电脑,用来存放代码、运行程序。

小提醒:买完之后记得到安全组里只放行必要端口(通常是 80、443,以及用于登录的 22)。数据库、Redis 等端口不要对公网开放,后面我们会专门处理。

三、第二步:给服务器起个好记的名字——域名与 DNS

服务器买好后,会得到一个公网 IP,比如 47.xx.xx.xx。理论上用 IP 就能访问,但一长串数字既不好记,也不专业。

这就是域名存在的意义:方便用户记忆和访问。

不过这里有个底层原理要搞清楚:互联网通信靠的是 IP 地址,不是域名。浏览器拿到域名后,要先经过 DNS 解析,把域名翻译成服务器的公网 IP,才能真正找到你的机器。

所以这一步的完整动作是:购买域名 → 添加 DNS 解析记录,指向服务器公网 IP。

小提醒:如果服务器在中国大陆,域名需要先完成 ICP 备案才能正常对外提供网站服务,建议尽早办理,因为备案需要时间。

四、第三步:给访问加把锁——HTTPS 证书

现在用户已经能通过域名访问网站了,但浏览器地址栏可能还显示“不安全”。原因是数据在浏览器和服务器之间是明文传输的。

HTTPS 证书的作用,就是让这段传输过程被加密,保障数据安全。

这里有一个容易踩的顺序坑:

⚠️ 证书是和域名绑定的,所以必须先拥有域名,才能申请对应的证书。

到这里,“地基”就打好了:服务器 + 域名 + 证书。接下来,轮到项目本身“动手术”了。

五、第四步:把一堆服务装进“集装箱”——Docker + Docker Compose

我们来数一数学面通在跑的服务:

  • FastAPI:后端业务服务
  • MySQL:关系型数据
  • Redis:缓存
  • MinIO:文件存储
  • Qdrant:向量数据库

如果在服务器上一个个手动安装、配置、启动,光是环境差异就够折腾一整天:版本冲突、依赖缺失、“我本地明明是好的”……

解决办法是容器化:用 Docker 把每个服务封装成独立的容器,一个服务一个容器;再用 Docker Compose 写一份 docker-compose.yml,把所有容器的启动方式统一编排好。

编排完成后,只需要一条命令,就能把整套服务一起拉起来:

docker compose up -d

除了省事,容器化还有个很重要的安全收益:Docker 内置了私有内网,容器之间在内网中互相通信,里面的服务不会直接暴露在公网。比如外网根本访问不到你的 MySQL,这就等于给数据库加了一层天然的保护。

一个精简版的编排骨架大概长这样(仅作示意,实际配置会在后续章节展开):

services:
  nginx:
    image: nginx:stable
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./frontend/dist:/usr/share/nginx/html:ro
      - ./nginx/conf.d:/etc/nginx/conf.d:ro
      - ./certs:/etc/nginx/certs:ro
    depends_on:
      - backend

  backend:            # FastAPI
    build: ./backend
    env_file: .env
    depends_on:
      - mysql
      - redis
      - minio
      - qdrant

  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
    volumes:
      - mysql_data:/var/lib/mysql

  redis:
    image: redis:7
    volumes:
      - redis_data:/data

  minio:
    image: minio/minio
    command: server /data --console-address ":9001"
    volumes:
      - minio_data:/data

  qdrant:
    image: qdrant/qdrant
    volumes:
      - qdrant_data:/qdrant/storage

volumes:
  mysql_data:
  redis_data:
  minio_data:
  qdrant_data:

注意:只有 nginx 对外暴露了端口,其余服务都藏在内网里。

六、第五步:给所有请求装一个“前台”——Nginx 统一网关

服务都在内网里了,用户的请求怎么进来?

答案是:所有请求都先经过 Nginx。它就像公司的前台,统一接待所有访客,再按需求分流:

用户请求Nginx 的处理方式
前端静态资源(页面、JS、CSS)直接返回,速度快
后端 API 调用反向代理,转发到内网的后端服务
文件请求同样转发处理

同时,Nginx 还会读取服务器上的证书,完成 HTTPS 的加解密。也就是说,加密、分流、转发这些“共同操作”,都在统一入口一次性解决,既方便管理,也提升了安全性。

核心配置的思路大致如下:

server {
    listen 80;
    server_name your-domain.com;
    return 301 https://$host$request_uri;   # HTTP 自动跳转 HTTPS
}

server {
    listen 443 ssl;
    server_name your-domain.com;

    ssl_certificate     /etc/nginx/certs/your-domain.com.pem;
    ssl_certificate_key /etc/nginx/certs/your-domain.com.key;

    # 前端静态资源
    location / {
        root /usr/share/nginx/html;
        try_files $uri $uri/ /index.html;
    }

    # 后端 API 反向代理
    location /api/ {
        proxy_pass http://backend:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

这里的 backend 就是 Compose 里的服务名——容器在同一个内网中,可以直接用服务名互相访问。

七、第六步:容器删了,数据可不能丢——数据持久化

容器化带来一个新问题:容器是“可丢弃”的。一旦容器被删除重建,里面的数据也会跟着消失,MySQL 里的用户数据、Qdrant 里的向量,岂不是全没了?

解决方案是命名数据卷(named volume)。回头看上面的 Compose 骨架,你会发现每个有状态的服务都挂了一个卷,比如 mysql_data、redis_data。

这样一来,数据实际保存在 Linux 服务器的磁盘上,而不是容器内部。即使容器重启、甚至被删除重建,原有数据依然完好。

八、真正的部署:把代码送上云端

“装备”都备齐了,终于可以动手部署了。整个执行流程如下:

  1. 配置 .gitignore:把 node_modules、本地缓存、密钥等不需要上传的文件忽略掉;
  2. 前端打包:运行打包命令,生成 dist 目录,交给 Nginx 托管;
  3. 准备环境变量文件:把数据库密码、各类密钥等配置到 .env(注意不要提交到 Git);
  4. 上传代码到云服务器:可以通过 Git 拉取,或用 scp / rsync 上传;
  5. 构建并启动容器:在服务器上执行 Compose 命令,自动拉取镜像、安装依赖:
docker compose up -d --build
  1. 数据库迁移:容器启动后,MySQL 里还是一片空白。通过 Alembic 迁移命令,自动在 MySQL 容器中创建所需的数据表:
docker compose exec backend alembic upgrade head

到这一步,访问你的域名,就能看到线上的学面通了。

九、串起来看:一个请求的完整旅程

当用户在浏览器输入域名并发起操作,整个链路是这样的:

用户 → 输入域名访问
        ↓  DNS 解析为服务器公网 IP
      Nginx(统一入口,HTTPS 解密)
        ↓
  ┌─────┴──────────────┐
静态资源               API 请求
直接返回               转发给 FastAPI 后端
                          ↓
          MySQL / Redis / MinIO / Qdrant
                  (分工完成不同任务)
                          ↓
                结果原路返回浏览器
  • 静态资源:Nginx 直接返回;
  • API 请求:转发给后端,后端连接 MySQL、Redis、MinIO、Qdrant,各司其职完成任务;
  • 响应:结果沿原路返回给用户。

十、总结:部署的三个重点

回头看,整条链路可以浓缩成三件事:

  1. 基础设施先到位:购买服务器、域名并解析、申请 HTTPS 证书(先有域名,再申请证书);
  2. Docker + Docker Compose 容器化编排:多个服务统一写进一份配置文件,一条命令启动全部服务,依赖自动下载,不用手动逐个安装;
  3. Nginx 统一网关 + 数据卷持久化:统一入口做 HTTPS、分流与代理,保障安全;命名数据卷保证数据不丢失。