一API接入)
1. 本地 K8s 集群部署 FastGPT 到底難在哪FastGPT 是一個(gè)能上傳文檔、做知識(shí)庫問答、還能編排工作流的開源項(xiàng)目適合想在內(nèi)網(wǎng)跑一套私有 AI 應(yīng)用的人。官方給的 docker-compose 在單機(jī)上很順但一旦搬到 K8s問題就冒出來了MongoDB 要副本集、PostgreSQL 要帶 pgvector 擴(kuò)展、One-API 要單獨(dú)暴露、FastGPT 主進(jìn)程還得知道 sandbox 的集群內(nèi)地址。我第一次照著 compose 文件手搓 YAML 時(shí)Pod 一直 CrashLoopBackOff日志里全是連不上 mongo 的報(bào)錯(cuò)。這篇就按我實(shí)際踩過的路徑來先規(guī)劃命名空間和存儲(chǔ)再把 MongoDB、PostgreSQL、One-API、FastGPT 四個(gè)組件拆成獨(dú)立清單用 ConfigMap 掛載 config.json最后把模型調(diào)用的 Base URL 指向 TaoToken用一次真實(shí)對話驗(yàn)證端到端連通。整套清單可以直接復(fù)制改掉存儲(chǔ)路徑和密鑰就能跑。適合誰看手上有本地 K8s 集群1.20 以上都行、想在內(nèi)網(wǎng)搭一套知識(shí)庫問答、又不想被各家模型 API 的接入細(xì)節(jié)卡住的人。核心檢索詞就三個(gè)K8s 集群部署、FastGPT 本地化、TaoToken 統(tǒng)一 API 接入。下面從命名空間開始一步步來。2. 部署前的命名空間與存儲(chǔ)規(guī)劃命名空間我習(xí)慣按項(xiàng)目隔離這里統(tǒng)一用fastgpt。先建命名空間再準(zhǔn)備 PV/PVC。存儲(chǔ)這塊有個(gè)坑hostPath 類型的 PV 不會(huì)自動(dòng)創(chuàng)建目錄你得先在節(jié)點(diǎn)上把目錄建好否則 Pod 掛載會(huì)失敗。kubectl create namespace fastgpt然后在每個(gè)可能調(diào)度到的節(jié)點(diǎn)上建目錄。我用的是單節(jié)點(diǎn)測試集群多節(jié)點(diǎn)的話建議用 local PV 加 nodeAffinity或者直接上 NFS。sudo mkdir -p /mnt/data/{pg,mongo,mysql,oneapi} sudo chmod -R 777 /mnt/data接下來是 PV 清單。注意persistentVolumeReclaimPolicy: Retain這樣刪 PVC 時(shí)數(shù)據(jù)不會(huì)跟著沒調(diào)試階段很關(guān)鍵。# 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不然動(dòng)態(tài)供給沒配的話會(huì)一直 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應(yīng)用順序很重要先 PV 再 PVC最后才是工作負(fù)載。我試過把 PV 和 Deployment 寫在一個(gè)文件里 apply結(jié)果 PVC 還沒綁定 Pod 就起來了直接掛載失敗。kubectl apply -f pv.yaml kubectl apply -f pvc.yaml kubectl get pvc -n fastgpt看到四個(gè) PVC 都是Bound狀態(tài)存儲(chǔ)這關(guān)就算過了。如果卡在 Pending先kubectl describe pvc看事件多半是 volumeName 寫錯(cuò)或者節(jié)點(diǎn)上目錄權(quán)限不對。3. 依賴組件編排MongoDB、PostgreSQL 與 One-API 的 YAML 清單FastGPT 依賴三個(gè)外部組件MongoDB 存業(yè)務(wù)數(shù)據(jù)、PostgreSQL 帶 pgvector 存向量、One-API 做模型網(wǎng)關(guān)。這三個(gè)必須先起來FastGPT 主進(jìn)程才能正常啟動(dòng)。3.1 MongoDB 副本集配置FastGPT 要求 MongoDB 以副本集模式運(yùn)行單節(jié)點(diǎn)也要rs.initiate。官方鏡像里帶了初始化腳本但 K8s 下得自己用 command 覆蓋啟動(dòng)邏輯。# 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這里有個(gè)細(xì)節(jié)host: mongo:27017用的是 Service 名因?yàn)?headless Service 的 DNS 能解析到 Pod IP。副本集初始化后FastGPT 連接串里要帶replicaSetrs0否則讀寫會(huì)報(bào)NotPrimaryNoSecondaryOk。3.2 PostgreSQL pgvectorFastGPT 的向量檢索依賴 pgvector 擴(kuò)展普通 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 網(wǎng)關(guān)One-API 在這里的角色是模型代理層。FastGPT 不直接調(diào)各家模型而是把請求發(fā)給 One-API由 One-API 統(tǒng)一轉(zhuǎn)發(fā)。這樣換模型、加渠道都只改一處。# 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 存渠道和令牌所以還得補(bǔ)一個(gè) MySQL 清單。這部分和 excerpt 里一致直接復(fù)用即可。# 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三個(gè)組件 apply 完之后用kubectl get pod -n fastgpt確認(rèn)都是 Running。MongoDB 首次啟動(dòng)會(huì)慢一點(diǎn)因?yàn)橐?keyfile 和初始化副本集等 30 秒左右正常。4. FastGPT 主進(jìn)程與 sandbox 的 ConfigMap 掛載FastGPT 分兩個(gè) Deployment主進(jìn)程和 sandbox。sandbox 負(fù)責(zé)執(zhí)行代碼塊主進(jìn)程負(fù)責(zé) API 和前端。主進(jìn)程需要掛一個(gè) 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: {} }這里的關(guān)鍵改動(dòng)是把OPENAI_BASE_URL指向 One-API 的集群內(nèi)地址。注意 Service 名和命名空間要對上oneapi.fastgpt.svc.cluster.local:3001里的 3001 是 Service 端口不是容器端口。CHAT_API_KEY填 One-API 里生成的令牌后面接 TaoToken 時(shí)會(huì)重新生成。apply 之后等 Pod 起來用kubectl logs -n fastgpt deploy/fastgpt看日志。如果看到connect to mongo相關(guān)報(bào)錯(cuò)檢查 MONGODB_URI 里有沒有帶replicaSetrs0。5. 把模型 Base URL 切到 TaoToken 并驗(yàn)證端到端連通前面 One-API 是空殼還沒配渠道。現(xiàn)在把模型調(diào)用指向 TaoToken讓 One-API 轉(zhuǎn)發(fā)過去。TaoToken 提供統(tǒng)一的 OpenAI 兼容接口Base URL 是https://taotoken.net/api模型 ID 按需選。5.1 在 One-API 里加渠道瀏覽器打開http://節(jié)點(diǎn)IP:NodePort用root/123456登錄One-API 默認(rèn)賬號(hào)。進(jìn)「渠道」→「添加渠道」字段值類型OpenAI名稱taotoken分組default模型qwen-max,gpt-4-0125-preview,text-embedding-ada-002代理留空密鑰你的 TaoToken API KeyBase URLhttps://taotoken.net/api保存后點(diǎn)「測試」返回綠色即通。然后去「令牌」頁新建一個(gè)令牌復(fù)制出來這就是 FastGPT 要用的CHAT_API_KEY。5.2 更新 FastGPT 環(huán)境變量把fastgpt.yaml里的CHAT_API_KEY換成新令牌重新 applykubectl apply -f fastgpt.yaml kubectl rollout restart deploy/fastgpt -n fastgpt5.3 用 curl 驗(yàn)證端到端最直接的驗(yàn)證方式是繞過前端直接打 FastGPT 的 OpenAI 兼容接口。先拿 NodePortkubectl get svc fastgpt -n fastgpt假設(shè) NodePort 是 31234節(jié)點(diǎn) IP 是 192.168.1.100發(fā)一個(gè)對話請求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 寫錯(cuò)或網(wǎng)絡(luò)不通。5.4 前端對話驗(yàn)證瀏覽器打開 FastGPT 前端用root/1234登錄新建一個(gè)應(yīng)用選qwen-max模型直接對話。能正常返回內(nèi)容整個(gè)部署就完成了。6. 部署過程中最容易踩的五個(gè)坑坑一MongoDB 副本集沒初始化。表現(xiàn)是 FastGPT 日志報(bào)NotPrimaryNoSecondaryOk。原因是 command 里的rs.initiate沒執(zhí)行成功。排查方法kubectl exec -it deploy/mongo -n fastgpt -- mongo -u root -p 123456 --authenticationDatabase admin --eval rs.status()看 state 是不是 PRIMARY。坑二PVC 一直 Pending。多半是 volumeName 和 PV 名字對不上或者節(jié)點(diǎn)上 hostPath 目錄不存在。kubectl describe pvc -n fastgpt看 Events 里有沒有no volume plugin matched??尤齇ne-API 報(bào)reading choices錯(cuò)誤。這是上游返回格式不對通常是 Base URL 少了/v1或者模型 ID 寫錯(cuò)。TaoToken 的 Base URL 是https://taotoken.net/apiOne-API 會(huì)自動(dòng)補(bǔ)/v1所以填的時(shí)候不要重復(fù)加??铀腇astGPT 連不上 sandbox。表現(xiàn)是代碼塊執(zhí)行超時(shí)。檢查SANDBOX_URL是不是http://sandbox.fastgpt.svc.cluster.local:3000命名空間和 Service 名都要對??游?01 Unauthorized。分兩種FastGPT 前端登錄失敗是密碼不對默認(rèn)1234API 調(diào)用 401 是令牌不對去 One-API 重新生成一個(gè)確保 FastGPT 的CHAT_API_KEY和 One-API 令牌一致。排障時(shí)優(yōu)先看 Pod 日志kubectl logs -n fastgpt deploy/xxx --tail100大部分問題日志里都有線索。如果涉及 One-API 渠道配置去 TaoToken 控制臺(tái)確認(rèn) Key 狀態(tài)和余額再回來對 Base URL。整套跑下來本地 K8s 集群里就有一套完整的 FastGPT 知識(shí)庫問答系統(tǒng)了。模型調(diào)用統(tǒng)一走 TaoToken換模型只改 One-API 渠道FastGPT 本身不用動(dòng)。需要看模型列表或調(diào)試接口可以去 TaoToken 模型對話 直接試要生成和管理 API Key在 API Keys 頁面 操作接入細(xì)節(jié)查 接入文檔。如果后面要長期跑編碼類 Agent可以看看 Coding Plan按用量走更省心。