
1. 本地 K8s 集群部署 FastGPT 到底难在哪FastGPT 是一个能上传文档、做知识库问答、还能编排工作流的开源项目适合想在内网跑一套私有 AI 应用的人。官方给的 docker-compose 在单机上很顺但一旦搬到 K8s问题就冒出来了MongoDB 要副本集、PostgreSQL 要带 pgvector 扩展、One-API 要单独暴露、FastGPT 主进程还得知道 sandbox 的集群内地址。我第一次照着 compose 文件手搓 YAML 时Pod 一直 CrashLoopBackOff日志里全是连不上 mongo 的报错。这篇就按我实际踩过的路径来先规划命名空间和存储再把 MongoDB、PostgreSQL、One-API、FastGPT 四个组件拆成独立清单用 ConfigMap 挂载 config.json最后把模型调用的 Base URL 指向 TaoToken用一次真实对话验证端到端连通。整套清单可以直接复制改掉存储路径和密钥就能跑。适合谁看手上有本地 K8s 集群1.20 以上都行、想在内网搭一套知识库问答、又不想被各家模型 API 的接入细节卡住的人。核心检索词就三个K8s 集群部署、FastGPT 本地化、TaoToken 统一 API 接入。下面从命名空间开始一步步来。2. 部署前的命名空间与存储规划命名空间我习惯按项目隔离这里统一用fastgpt。先建命名空间再准备 PV/PVC。存储这块有个坑hostPath 类型的 PV 不会自动创建目录你得先在节点上把目录建好否则 Pod 挂载会失败。kubectl create namespace fastgpt然后在每个可能调度到的节点上建目录。我用的是单节点测试集群多节点的话建议用 local PV 加 nodeAffinity或者直接上 NFS。sudo mkdir -p /mnt/data/{pg,mongo,mysql,oneapi} sudo chmod -R 777 /mnt/data接下来是 PV 清单。注意persistentVolumeReclaimPolicy: Retain这样删 PVC 时数据不会跟着没调试阶段很关键。# pv.yaml apiVersion: v1 kind: PersistentVolume metadata: name: pg-pv spec: capacity: storage: 10Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain hostPath: path: /mnt/data/pg --- apiVersion: v1 kind: PersistentVolume metadata: name: mongo-pv spec: capacity: storage: 10Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain hostPath: path: /mnt/data/mongo --- apiVersion: v1 kind: PersistentVolume metadata: name: mysql-pv spec: capacity: storage: 10Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain hostPath: path: /mnt/data/mysql --- apiVersion: v1 kind: PersistentVolume metadata: name: oneapi-pv spec: capacity: storage: 10Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain hostPath: path: /mnt/data/oneapiPVC 部分要显式指定volumeName不然动态供给没配的话会一直 Pending。# pvc.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pg-pvc namespace: fastgpt spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi volumeName: pg-pv --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mongo-pvc namespace: fastgpt spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi volumeName: mongo-pv --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: mysql-pvc namespace: fastgpt spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi volumeName: mysql-pv --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: oneapi-pvc namespace: fastgpt spec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi volumeName: oneapi-pv应用顺序很重要先 PV 再 PVC最后才是工作负载。我试过把 PV 和 Deployment 写在一个文件里 apply结果 PVC 还没绑定 Pod 就起来了直接挂载失败。kubectl apply -f pv.yaml kubectl apply -f pvc.yaml kubectl get pvc -n fastgpt看到四个 PVC 都是Bound状态存储这关就算过了。如果卡在 Pending先kubectl describe pvc看事件多半是 volumeName 写错或者节点上目录权限不对。3. 依赖组件编排MongoDB、PostgreSQL 与 One-API 的 YAML 清单FastGPT 依赖三个外部组件MongoDB 存业务数据、PostgreSQL 带 pgvector 存向量、One-API 做模型网关。这三个必须先起来FastGPT 主进程才能正常启动。3.1 MongoDB 副本集配置FastGPT 要求 MongoDB 以副本集模式运行单节点也要rs.initiate。官方镜像里带了初始化脚本但 K8s 下得自己用 command 覆盖启动逻辑。# mongo.yaml apiVersion: v1 kind: Service metadata: name: mongo namespace: fastgpt spec: ports: - port: 27017 name: mongo clusterIP: None selector: app: mongo --- apiVersion: apps/v1 kind: Deployment metadata: name: mongo namespace: fastgpt spec: replicas: 1 selector: matchLabels: app: mongo template: metadata: labels: app: mongo spec: containers: - name: mongo image: registry.cn-hangzhou.aliyuncs.com/fastgpt/mongo:5.0.18 ports: - containerPort: 27017 env: - name: MONGO_INITDB_ROOT_USERNAME value: root - name: MONGO_INITDB_ROOT_PASSWORD value: 123456 volumeMounts: - name: mongo-pvc mountPath: /data/db resources: limits: cpu: 1000m memory: 1024Mi requests: cpu: 250m memory: 250Mi command: - bash - -c - | if [ ! -f /data/mongodb.key ]; then openssl rand -base64 128 /data/mongodb.key chmod 400 /data/mongodb.key chown 999:999 /data/mongodb.key fi if [ ! -f /data/initReplicaSet.js ]; then echo const isInited rs.status().ok 1 if(!isInited){ rs.initiate({ _id: rs0, members: [ { _id: 0, host: mongo:27017 } ] }) } /data/initReplicaSet.js fi exec docker-entrypoint.sh mongod --keyFile /data/mongodb.key --replSet rs0 until mongo -u root -p 123456 --authenticationDatabase admin --eval print(waited for connection) /dev/null 21; do echo Waiting for MongoDB to start... sleep 2 done mongo -u root -p 123456 --authenticationDatabase admin /data/initReplicaSet.js wait $! volumes: - name: mongo-pvc persistentVolumeClaim: claimName: mongo-pvc这里有个细节host: mongo:27017用的是 Service 名因为 headless Service 的 DNS 能解析到 Pod IP。副本集初始化后FastGPT 连接串里要带replicaSetrs0否则读写会报NotPrimaryNoSecondaryOk。3.2 PostgreSQL pgvectorFastGPT 的向量检索依赖 pgvector 扩展普通 postgres 镜像不行得用官方打包好的pgvector:v0.7.0。# pg.yaml apiVersion: apps/v1 kind: Deployment metadata: name: pg namespace: fastgpt spec: replicas: 1 selector: matchLabels: app: pg template: metadata: labels: app: pg spec: containers: - name: pg image: registry.cn-hangzhou.aliyuncs.com/fastgpt/pgvector:v0.7.0 ports: - containerPort: 5432 env: - name: POSTGRES_USER value: username - name: POSTGRES_PASSWORD value: password - name: POSTGRES_DB value: postgres volumeMounts: - mountPath: /var/lib/postgresql/data name: pg-pvc resources: limits: cpu: 1000m memory: 1024Mi requests: cpu: 250m memory: 250Mi volumes: - name: pg-pvc persistentVolumeClaim: claimName: pg-pvc --- apiVersion: v1 kind: Service metadata: name: pg namespace: fastgpt spec: ports: - port: 5432 selector: app: pg3.3 One-API 网关One-API 在这里的角色是模型代理层。FastGPT 不直接调各家模型而是把请求发给 One-API由 One-API 统一转发。这样换模型、加渠道都只改一处。# oneapi.yaml apiVersion: apps/v1 kind: Deployment metadata: name: oneapi namespace: fastgpt spec: selector: matchLabels: app: oneapi replicas: 1 template: metadata: labels: app: oneapi spec: containers: - name: oneapi image: ghcr.io/songquanpeng/one-api:latest ports: - containerPort: 3000 env: - name: SQL_DSN value: root:oneapimmysqltcp(mysql:3306)/oneapi - name: SESSION_SECRET value: oneapikey - name: MEMORY_CACHE_ENABLED value: true - name: BATCH_UPDATE_ENABLED value: true - name: BATCH_UPDATE_INTERVAL value: 10 - name: INITIAL_ROOT_TOKEN value: fastgpt volumeMounts: - mountPath: /var/lib/oneapi/data name: oneapi-pvc resources: limits: cpu: 500m memory: 512Mi requests: cpu: 50m memory: 51Mi volumes: - name: oneapi-pvc persistentVolumeClaim: claimName: oneapi-pvc --- apiVersion: v1 kind: Service metadata: name: oneapi namespace: fastgpt spec: type: NodePort ports: - port: 3001 targetPort: 3000 selector: app: oneapiOne-API 自己需要 MySQL 存渠道和令牌所以还得补一个 MySQL 清单。这部分和 excerpt 里一致直接复用即可。# mysql.yaml apiVersion: apps/v1 kind: Deployment metadata: name: mysql namespace: fastgpt spec: selector: matchLabels: app: mysql replicas: 1 template: metadata: labels: app: mysql spec: containers: - name: mysql image: docker.m.daocloud.io/mysql:8.0.36 ports: - containerPort: 3306 env: - name: MYSQL_ROOT_PASSWORD value: oneapimmysql - name: MYSQL_DATABASE value: oneapi volumeMounts: - mountPath: /var/lib/mysql name: mysql-pvc resources: limits: cpu: 500m memory: 512Mi requests: cpu: 250m memory: 512Mi volumes: - name: mysql-pvc persistentVolumeClaim: claimName: mysql-pvc --- apiVersion: v1 kind: Service metadata: name: mysql namespace: fastgpt spec: ports: - port: 3306 selector: app: mysql三个组件 apply 完之后用kubectl get pod -n fastgpt确认都是 Running。MongoDB 首次启动会慢一点因为要生成 keyfile 和初始化副本集等 30 秒左右正常。4. FastGPT 主进程与 sandbox 的 ConfigMap 挂载FastGPT 分两个 Deployment主进程和 sandbox。sandbox 负责执行代码块主进程负责 API 和前端。主进程需要挂一个 config.json里面定义可用模型列表。# fastgpt.yaml apiVersion: apps/v1 kind: Deployment metadata: name: sandbox namespace: fastgpt spec: selector: matchLabels: app: sandbox replicas: 1 template: metadata: labels: app: sandbox spec: containers: - name: sandbox image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt-sandbox:v4.8.3 ports: - containerPort: 3000 resources: limits: cpu: 1000m memory: 1024Mi requests: cpu: 250m memory: 512Mi --- apiVersion: v1 kind: Service metadata: name: sandbox namespace: fastgpt spec: ports: - port: 3000 selector: app: sandbox --- apiVersion: apps/v1 kind: Deployment metadata: name: fastgpt namespace: fastgpt spec: selector: matchLabels: app: fastgpt replicas: 1 template: metadata: labels: app: fastgpt spec: containers: - name: fastgpt image: registry.cn-hangzhou.aliyuncs.com/fastgpt/fastgpt:v4.8.3 ports: - containerPort: 3000 env: - name: DEFAULT_ROOT_PSW value: 1234 - name: OPENAI_BASE_URL value: http://oneapi.fastgpt.svc.cluster.local:3001/v1 - name: CHAT_API_KEY value: sk-你的OneAPI令牌 - name: DB_MAX_LINK value: 30 - name: TOKEN_KEY value: any - name: ROOT_KEY value: root_key - name: FILE_TOKEN_KEY value: filetoken - name: MONGODB_URI value: mongodb://root:123456mongo:27017/fastgpt?authSourceadminreplicaSetrs0 - name: PG_URL value: postgresql://username:passwordpg:5432/postgres - name: SANDBOX_URL value: http://sandbox.fastgpt.svc.cluster.local:3000 volumeMounts: - mountPath: /app/data/config.json name: config-volume subPath: config.json resources: limits: cpu: 1000m memory: 1024Mi requests: cpu: 250m memory: 512Mi volumes: - name: config-volume configMap: name: fastgpt-config --- apiVersion: v1 kind: Service metadata: name: fastgpt namespace: fastgpt spec: type: NodePort ports: - port: 3000 selector: app: fastgpt --- apiVersion: v1 kind: ConfigMap metadata: name: fastgpt-config namespace: fastgpt data: config.json: | { feConfigs: { lafEnv: https://laf.dev }, systemEnv: { openapiPrefix: fastgpt, vectorMaxProcess: 15, qaMaxProcess: 15, pgHNSWEfSearch: 100 }, llmModels: [ { model: qwen-max, name: qwen, maxContext: 16000, avatar: /imgs/model/openai.svg, maxResponse: 4000, quoteMaxToken: 13000, maxTemperature: 1.2, charsPointsPrice: 0, censor: false, vision: false, datasetProcess: true, usedInClassify: true, usedInExtractFields: true, usedInToolCall: true, usedInQueryExtension: true, toolChoice: true, functionCall: true, defaultConfig: {} }, { model: gpt-4-0125-preview, name: gpt-4-turbo, avatar: /imgs/model/openai.svg, maxContext: 125000, maxResponse: 4000, quoteMaxToken: 100000, maxTemperature: 1.2, charsPointsPrice: 0, censor: false, vision: false, datasetProcess: false, usedInClassify: true, usedInExtractFields: true, usedInToolCall: true, usedInQueryExtension: true, toolChoice: true, functionCall: false, defaultConfig: {} } ], vectorModels: [ { model: text-embedding-ada-002, name: Embedding-2, avatar: /imgs/model/openai.svg, charsPointsPrice: 0, defaultToken: 512, maxToken: 3000, weight: 100, dbConfig: {}, queryConfig: {} } ], reRankModels: [], audioSpeechModels: [], whisperModel: {} }这里的关键改动是把OPENAI_BASE_URL指向 One-API 的集群内地址。注意 Service 名和命名空间要对上oneapi.fastgpt.svc.cluster.local:3001里的 3001 是 Service 端口不是容器端口。CHAT_API_KEY填 One-API 里生成的令牌后面接 TaoToken 时会重新生成。apply 之后等 Pod 起来用kubectl logs -n fastgpt deploy/fastgpt看日志。如果看到connect to mongo相关报错检查 MONGODB_URI 里有没有带replicaSetrs0。5. 把模型 Base URL 切到 TaoToken 并验证端到端连通前面 One-API 是空壳还没配渠道。现在把模型调用指向 TaoToken让 One-API 转发过去。TaoToken 提供统一的 OpenAI 兼容接口Base URL 是https://taotoken.net/api模型 ID 按需选。5.1 在 One-API 里加渠道浏览器打开http://节点IP:NodePort用root/123456登录One-API 默认账号。进「渠道」→「添加渠道」字段值类型OpenAI名称taotoken分组default模型qwen-max,gpt-4-0125-preview,text-embedding-ada-002代理留空密钥你的 TaoToken API KeyBase URLhttps://taotoken.net/api保存后点「测试」返回绿色即通。然后去「令牌」页新建一个令牌复制出来这就是 FastGPT 要用的CHAT_API_KEY。5.2 更新 FastGPT 环境变量把fastgpt.yaml里的CHAT_API_KEY换成新令牌重新 applykubectl apply -f fastgpt.yaml kubectl rollout restart deploy/fastgpt -n fastgpt5.3 用 curl 验证端到端最直接的验证方式是绕过前端直接打 FastGPT 的 OpenAI 兼容接口。先拿 NodePortkubectl get svc fastgpt -n fastgpt假设 NodePort 是 31234节点 IP 是 192.168.1.100发一个对话请求curl -X POST http://192.168.1.100:31234/api/v1/chat/completions \ -H Authorization: Bearer 你的FastGPT令牌 \ -H Content-Type: application/json \ -d { model: qwen-max, messages: [{role: user, content: 用一句话说明K8s是什么}], stream: false }返回里如果有choices[0].message.content说明 FastGPT → One-API → TaoToken → 模型 这条链路全通了。如果返回 401检查 FastGPT 令牌如果返回local proxy failed多半是 One-API 的 Base URL 写错或网络不通。5.4 前端对话验证浏览器打开 FastGPT 前端用root/1234登录新建一个应用选qwen-max模型直接对话。能正常返回内容整个部署就完成了。6. 部署过程中最容易踩的五个坑坑一MongoDB 副本集没初始化。表现是 FastGPT 日志报NotPrimaryNoSecondaryOk。原因是 command 里的rs.initiate没执行成功。排查方法kubectl exec -it deploy/mongo -n fastgpt -- mongo -u root -p 123456 --authenticationDatabase admin --eval rs.status()看 state 是不是 PRIMARY。坑二PVC 一直 Pending。多半是 volumeName 和 PV 名字对不上或者节点上 hostPath 目录不存在。kubectl describe pvc -n fastgpt看 Events 里有没有no volume plugin matched。坑三One-API 报reading choices错误。这是上游返回格式不对通常是 Base URL 少了/v1或者模型 ID 写错。TaoToken 的 Base URL 是https://taotoken.net/apiOne-API 会自动补/v1所以填的时候不要重复加。坑四FastGPT 连不上 sandbox。表现是代码块执行超时。检查SANDBOX_URL是不是http://sandbox.fastgpt.svc.cluster.local:3000命名空间和 Service 名都要对。坑五401 Unauthorized。分两种FastGPT 前端登录失败是密码不对默认1234API 调用 401 是令牌不对去 One-API 重新生成一个确保 FastGPT 的CHAT_API_KEY和 One-API 令牌一致。排障时优先看 Pod 日志kubectl logs -n fastgpt deploy/xxx --tail100大部分问题日志里都有线索。如果涉及 One-API 渠道配置去 TaoToken 控制台确认 Key 状态和余额再回来对 Base URL。整套跑下来本地 K8s 集群里就有一套完整的 FastGPT 知识库问答系统了。模型调用统一走 TaoToken换模型只改 One-API 渠道FastGPT 本身不用动。需要看模型列表或调试接口可以去 TaoToken 模型对话 直接试要生成和管理 API Key在 API Keys 页面 操作接入细节查 接入文档。如果后面要长期跑编码类 Agent可以看看 Coding Plan按用量走更省心。