Files
dsh_shenxian/docs/k8s-deployment.md
T
admin cf8b7b1f5c chore(k8s): 下线 K8s 后端形态,移除依赖 @kubernetes/client-node
生产形态是单机 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 命中。
2026-09-15 06:36:20 +08:00

7.1 KiB
Raw Blame History

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. 验收清单

  1. kubectl -n dsh get pods:dsh-orchestrator 3/3、dsh-pg-1 1/1、dsh-files-*/dsh-*(按需出现)。
  2. leader 单活:kubectl -n dsh get lease dsh-orchestrator holder 非空、leaseTransitions 随接管递增。
  3. 域名全链路:注册 → 管理员审核 → 登录 → 桌面 tree/建文件夹/上传 → 启动 DSH → https://<user>.dsh.example.com/ 200。
  4. 模型请求:DSH 里配 key 后能解析并访问 api.deepseek.com(DNS + 443 出站通)。
  5. 隔离:任意非控制面 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。