生产形态是单机 local(DEFAULT_DEPLOY_MODE=local,env 未覆盖)⇒ K8s 分支
在 local 下本来不可达;且该形态与官方 dsh 基座、插件体系均无关
=> 整体下线,并移除该形态唯一的第三方依赖。
移除(备份在 D:/github/_dsh_shenxian_K8s后端备份_20260915/,含还原命令与
「集群化方案要复用的模板清单」):
src/supervisor/{k8s-spawner,leader,reconcile}.ts
src/fs/k8s-user-fs.ts · src/tcp-bridge.ts · src/web/file-service.ts
test/{k8s-spawner,leader}.test.mjs · scripts/smoke-file-service.mjs
改写调用方:cli.ts(5 条 import / 选主块 / file-service 与 tcp-bridge 两个
子命令 / dispatch / HELP)、web/server.ts(改为 fail-loud 守卫 + 恒用
LocalSpawner)、fs/provider.ts(只留 LocalUserFs)、package.json(测试与
smoke 入口),外加 3 处指向已删类型的悬空 JSDoc。
保留(集群化方案列为未来可选):deploy/ · poc/01-04 · Dockerfile.dsh ·
docs/k8s*.md(已加「代码已下线」状态横幅)· config.ts 的 K8s 配置字段与
DeployMode 联合类型。
验证:tsc --noEmit exit 0;npm test 36 测试 / 35 通过 / 0 失败 / 1 跳过;
npm run verify exit 0;依赖与被删符号全仓 0 命中。
7.1 KiB
K8s 部署教程(模式 B)— DSH 服务端登录插件
⚠️ 2026-09-15:模式 B 的 K8s 后端代码已从本仓下线(
k8s-spawner/leader/reconcile/k8s-user-fs/tcp-bridge/web/file-service六个模块 + 2 个测试 + 1 个脚本)。备份:D:\github\_dsh_shenxian_K8s后端备份_20260915\。本文按「历史设计稿 + 未来可选路线」保留;文中的dshs file-service/dshs tcp-bridge两条子命令现已不存在,照着敲会command not found。> ⚠️ 2026-09-15:模式 B 的 K8s 后端代码已从本仓下线(k8s-spawner/leader/reconcile/k8s-user-fs/tcp-bridge/web/file-service六个模块 + 2 个测试 + 1 个脚本)。备份:D:\github\_dsh_shenxian_K8s后端备份_20260915\。本文按「历史设计稿 + 未来可选路线」保留;文中的dshs file-service/dshs tcp-bridge两条子命令现已不存在,照着敲会command not found。 🧭 ← 返回 README · 卡住了:踩坑记录 · 模式 A 教程:deployment
把
dshs部署成多机 HA、每用户独立 Pod 的形态。本文是可复制的分步部署教程; 实机逐条踩坑与根因排查见 k8s-deploy.md。实测环境:阿里云 ACK 智能托管(华东2)+ CNFS(NAS) + CloudNativePG + 私有 ACR。
0. 前置条件
- 一个 ACK 智能托管集群(网络插件 DataPath V2 / 勾选 NetworkPolicy;节点 ≥ 3 或启用自动扩容)。
- 一个 NAS 文件系统,并在集群里建 CNFS(控制台「容器网络文件系统」,名字记为
nas)。 - 一个 私有 ACR 仓库(本文用
registry.example.com/dsh作占位)。 - 一个域名(本文用
dsh.example.com作占位)+ 通配 TLS 证书(cert-manager 或 LB 证书)。
已安装:kubectl、cnpg operator(kubectl apply --server-side -f cnpg.yaml)。
1. 镜像
两种方式二选一:
- CI(推荐):推代码到 master,GitHub Actions 自动 build + Trivy + push 两个镜像到 ACR。
- 手动:
docker build -t <acr>/dshs:0.2.0 . docker build -t <acr>/dsh:0.1.1-rc.2 -f Dockerfile.dsh . docker push <acr>/dshs:0.2.0 docker push <acr>/dsh:0.1.1-rc.2
2. Namespace + Postgres
kubectl apply -f deploy/00-namespace.yaml
kubectl apply -f deploy/01-dsh-pg.yaml
# 等 healthy:
kubectl -n dsh wait --for=condition=Ready cluster/dsh-pg --timeout=600s
读连接串(后面建 dsh-pg secret 用):
kubectl -n dsh get secret dsh-pg-app -o jsonpath='{.data.uri}' | base64 -d
# postgresql://dsh:<password>@dsh-pg-rw.dsh:5432/dsh
3. Secrets(含动态值,不进 YAML)
# ① ACR 拉镜像凭证(生成 Pod 拉私有镜像用)
kubectl -n dsh create secret docker-registry dsh-acr-pull \
--docker-server=registry.example.com \
--docker-username='<ACR_USERNAME>' --docker-password='<ACR_PASSWORD>'
# ② 共享加密密钥(迁移时填旧 dataRoot/secret.key 内容,否则已加密的 API key 解不开)
kubectl -n dsh create secret generic dsh-secret --from-literal=key='<32字节hex>'
# ③ Postgres DSN(用 §2 读到的 uri)
kubectl -n dsh create secret generic dsh-pg --from-literal=url='postgresql://dsh:[email protected]:5432/dsh'
4. RBAC + 控制面
kubectl apply -f deploy/03-rbac.yaml # SA + Role(含 leases + list/watch,leader election 需要)
kubectl apply -f deploy/02-control-plane.yaml
kubectl -n dsh rollout status deploy/dsh-orchestrator --timeout=300s
初始化管理员:
kubectl -n dsh exec deploy/dsh-orchestrator -- node lib/cli.js bootstrap-admin --username admin --password '<强密码>'
控制面 3 副本,只有 leader 跑 reconcile(Lease 选主)。
deploy/02-control-plane.yaml里把DSHS_BASE_DOMAIN/DSHS_COOKIE_DOMAIN/ 镜像地址改成你自己的。
5. 存储:NAS(CNFS) + PVC + bootstrap + PSA(严格时序)
⚠️ 顺序不能乱:先建 PVC → 特权 bootstrap
chmod 1777→ 最后打 PSA restricted。先打 PSA, 非 root 的 initContainer 就写不了 PVC 根,用户目录永远建不出来。
# ① StorageClass(引用控制台建好的 CNFS `nas`)
kubectl apply -f deploy/05-storage.yaml
# ② 每用户共享 RWX PVC
kubectl apply -f deploy/04-pvc.yaml
kubectl -n dsh wait --for=jsonpath='{.status.phase}=Bound' pvc/dsh-users --timeout=300s
# ③ 特权 bootstrap:PVC 根 chmod 1777(world-writable + sticky)
kubectl apply -f deploy/08-bootstrap.yaml
kubectl -n dsh wait --for=condition=complete job/dsh-users-bootstrap --timeout=180s
# ④ 打 PSA restricted(放在最后)
kubectl apply -f deploy/07-psa.yaml
# ⑤ 配额(防单用户耗尽集群)
kubectl apply -f deploy/06-quota.yaml
6. 入口(域名 + TLS)
- 暴露控制面:给
dsh-orchestrator加一个 LoadBalancer Service(port 80 → targetPort 3080), 或用 Ingress(Traefik / nginx-ingress)统一入口。 - DNS:把
dsh.example.com与*.dsh.example.com解析到 LB 的 IP(或 Ingress 域名)。 - TLS:cert-manager 签通配证书(DNS-01),或直接用 LB/ALB 的证书。
- ⚠️ 域名经阿里云公网 SLB/ALB 暴露时需先做 ICP 备案,否则 80/443 会被备案校验拦(403)。
LoadBalancer Service 参考:
apiVersion: v1
kind: Service
metadata: { name: dsh-orchestrator-lb, namespace: dsh }
spec:
type: LoadBalancer
selector: { app: dsh-orchestrator }
ports: [{ port: 80, targetPort: 3080 }]
7. 验收清单
kubectl -n dsh get pods:dsh-orchestrator3/3、dsh-pg-11/1、dsh-files-*/dsh-*(按需出现)。- leader 单活:
kubectl -n dsh get lease dsh-orchestratorholder 非空、leaseTransitions随接管递增。 - 域名全链路:注册 → 管理员审核 → 登录 → 桌面 tree/建文件夹/上传 → 启动 DSH →
https://<user>.dsh.example.com/200。 - 模型请求:DSH 里配 key 后能解析并访问
api.deepseek.com(DNS + 443 出站通)。 - 隔离:任意非控制面 Pod 访问某用户 DSH 的 8081/8082 被 NetworkPolicy 拒。
8. 配置参考(控制面 env)
| env | 默认 | 说明 |
|---|---|---|
DSHS_DEPLOY_MODE |
local |
k8s 启用每用户 Pod |
DSHS_DB_URL |
空 | Postgres DSN(k8s 必填) |
DSHS_SECRET |
空 | 共享加密密钥 |
DSHS_NAMESPACE |
dsh |
每用户资源命名空间 |
DSHS_DSH_IMAGE |
空 | 每用户 DSH 镜像 |
DSHS_CONTROL_PLANE_IMAGE |
空 | file sidecar / tcp-bridge 镜像 |
DSHS_IMAGE_PULL_SECRET |
dsh-acr-pull |
生成 Pod 的拉镜像 secret |
DSHS_BASE_DOMAIN |
空 | 子域路由基域 |
DSHS_COOKIE_DOMAIN |
空 | cookie Domain |
DSHS_SECURE_COOKIES |
false |
HTTPS 设 true |
DSHS_EGRESS_CIDRS |
空 | 443 出站白名单(空=0.0.0.0/0) |
9. 常见问题 → k8s-deploy.md
- 部署顺序、NAS/CNFS、uid 错位、就绪探针、代理端口、leader 接管、DNS、备案、keepAlive 502 等全部踩坑与根因已记录在
k8s-deploy.md§5–§8。