这一阶段做两件分开的事。KEDA 看 Prometheus 里的排队人数,排队超过 10 时把 Dify 的 worker 从 1 个加到最多 3 个,不动 vLLM。Argo CD 盯着 Git 里的清单,发现和集群不一致就改回 Git 上的样子。网页登录已经在浏览器里走过一遍。
登录口令按现网写在这里。Vault 根令牌、Langfuse 的加密项、Redis 口令、MinIO 口令、kubeadm 加入令牌,以及 Argo CD 用来拉仓库的个人访问令牌,不写进本文。本文只供这台学习机对照,不要发到公网。
整条链路
- 1Prometheus 里已经有 vLLM 的排队人数指标名 vllm:num_requests_waiting,模型 qwen3.6-27b。KEDA 每 15 秒读一次。
- 2排队大于 10,worker 副本往上加目标是 dify/worker,最少 1,最多 3。vLLM 不在伸缩目标里。
- 3现网清单导出到 Git只有 Deployment、Service、ExternalSecret、ScaledObject。Secret 留在集群和 Vault。
- 4Argo CD 的 Application 指向这个仓库自动同步,自愈打开,不删除 Git 里没有的对象。worker 的副本数不跟 Git 打架。
- 5以后改清单,先改 Git,再等同步演示改的是导航页注解。vLLM 镜像没有动。
KEDA 看的是排队,伸缩的是 worker
KEDA 是装在集群里的控制器。它按外部指标改 Deployment 的副本数,底下仍然是一条 HorizontalPodAutoscaler,名字 keda-hpa-dify-worker。这一条的目标是 dify/worker。
触发器是 Prometheus,地址 http://prometheus.observability.svc.cluster.local:9090。查询是:
sum(vllm:num_requests_waiting{model_name="qwen3.6-27b"})
threshold 和 activationThreshold 都是 10。排队人数小于或等于 10 时,触发器不激活,副本停在 1。超过 10 之后,期望副本是排队人数除以 10 再向上取整,并且不超过 3。25 人排队时期望是 3。
写文档时这条 ScaledObject 是 Ready,Active 为 False,worker 就绪副本是 1。查询已经是上面的 sum(),没有留下模拟用的常数。
安装脚本是 scripts/10-安装KEDA.sh。prod102 上 release keda 已经存在,再执行会直接退出。镜像来自 ghcr.dockerproxy.net/kedacore,标签 2.21.0,拉取策略 IfNotPresent。
用常数 25 走了一遍 1 → 3 → 1
没有向 vLLM 灌真实请求。脚本 scripts/11-模拟排队扩容.sh 把查询临时换成 vector(25),并把 HPA 的稳定窗口改成 0,方便在课堂时间里看见副本变化。worker 从 1 个就绪变成 3 个就绪。HPA 上先看到 25/10,三个副本都就绪后又变成大约 8334m/10,也就是 25 除以 3 的平均值。
脚本结束时把查询改回真实的 sum(),副本回到 1。vLLM 的 /health 在这次伸缩前后都是 200。再跑一遍会短时间占用 worker 的副本,不占用 nvidia.com/gpu 名额。复习流程时看本文即可。
Git 里有什么
仓库在 GitLab 项目 gitops/platform,默认分支 main,可见性是私有。集群内地址:
http://gitlab.gitlab.svc.cluster.local:8929/gitops/platform.git
浏览器打开 http://10.0.1.47:8929/gitops/platform。Argo CD 只应用 manifests/ 目录,所以仓库根上的 README 不会被当成 Kubernetes 对象。
导出范围是命名空间 llm、dify、observability 里的 Deployment、Service、ExternalSecret、ScaledObject。Secret 和 ConfigMap 没有导出。kube-root-ca.crt 也跳过了。对象上的 uid、resourceVersion、managedFields、status 已去掉。
分支上有两个提交。第一个把 22 个 Deployment 和其余清单放进去。第二个只给导航页的 Pod 模板加了一行注解。当前修订是 e07c4aa6f11d5740bc1dd0759a0003d2b2d23814。
第一次同步没有换掉 vLLM
纳管之前,用服务器上的 dry-run 和线上 Pod 模板逐个对比过 Deployment。模板一致之后才创建 Application。自动同步打开时,Argo CD 看到的期望和现状相同,所以没有重建 Pod。
Application 的名字是 platform,命名空间 argocd。同步策略:
| 字段 | 值 | 作用 |
|---|---|---|
| prune | false | Git 里删掉的对象,集群里先留着 |
| selfHeal | true | 有人直接改集群时,拉回 Git 上的内容 |
| ApplyOutOfSyncOnly | 打开 | 只提交有差异的对象 |
| ignoreDifferences | dify/worker 的 /spec/replicas | KEDA 改副本数时,Argo CD 不把它改回 1 |
同步完成后,llm、dify、observability 里没有新的 Pod。vLLM 的 Pod 仍是 vllm-67b8d8c9f6-vvfsq,uid 26326358-d9a7-4eec-8b13-df4d800d2ae5。
改一个注解,看同步怎么落地
在 manifests/llm/deploy-nav.yaml 的 Pod 模板上加了 gitops.local/demo=nav-1,提交到 main,再给 Application 打上硬刷新注解。大约 5 秒后,正在跑的导航页 Pod 带上了这行注解,就绪副本仍是 1。导航页的更新策略是 Recreate,所以这次注解会换掉导航页自己的 Pod。vLLM 的 uid 没有变,/health 仍是 200。
以后要改一份清单,顺序是:改 Git 里的文件,推到 main,等 Argo CD 刷新。直接 kubectl edit 会被自愈改回去,dify/worker 的副本数除外。
Argo CD 的登录
页面是 http://10.0.1.47:8080/。账号 admin,密码 Argocd-git-2026。打开根地址后,页面会自己走到登录表单。用这组账号可以进入 Applications,看到 platform。
会话接口接受这组密码。之前浏览器停在 “Checking session...”,是因为反代对每一个请求都写了 Connection: upgrade。现网这份反代只转发 Host、X-Forwarded-For、X-Forwarded-Proto 和 X-Forwarded-Host,并关掉了缓冲。Deployment 的策略是 Recreate,节点 8080 上只有一个代理 Pod。
Argo CD 版本 v3.5.4。界面走的是集群内 argocd-server 的 80 端口,服务器配置里 server.insecure 为 true,对外地址写成 http://10.0.1.47:8080。组件都是 1/1 Running:application-controller、applicationset-controller、dex-server、notifications-controller、redis、repo-server、server,再加上这个代理。
仓库放在 GitLab Community Edition
Git 服务是开源的 GitLab CE,镜像 docker.m.daocloud.io/gitlab/gitlab-ce:19.4.2-ce.0。数据在 /usr/cluster/gitlab,HTTP 用节点端口 8929。容器里的 SSH 没有对节点发布。捆绑的 Prometheus 关掉了,给这台已经在跑模型的机器留内存。内存请求 4Gi,上限 8Gi。
网页登录:
地址 http://10.0.1.47:8929/users/sign_in 用户 root 密码 R3po-Argo-2026
这组密码已经在浏览器里登录,并打开了 gitops/platform。项目是私有的,分支 main,能看到 README 和两个提交。GitLab 拒绝了含有产品名的那组初始口令,所以账号用的是现在这一组。
健康检查没有用 /-/readiness。这版在关掉捆绑监控之后,这个地址返回 404。探针改成登录页 /users/sign_in,返回 200 才算就绪。更新策略是 Recreate,因为 8929 同样只能有一个 Pod 占用。
Argo CD 拉仓库用的是 Secret argocd/gitops-repo,标签 argocd.argoproj.io/secret-type=repository,用户名 oauth2。口令是项目上的个人访问令牌,只放在这个 Secret 里。换仓库地址之后,Application 仍是 Synced、Healthy,修订仍是 e07c4aa。
早先临时用过的 Gitea 工作负载已经删除。它的数据目录还在 /usr/cluster/gitea,当前同步不读那份目录。
写文档时核对到的结果
| 检查 | 结果 |
|---|---|
| KEDA | 三个 Deployment 都是 1/1。ScaledObject Ready,Active 为 False |
| worker | 副本 1,就绪 1。查询是真实的 sum() |
| Argo CD | platform Synced、Healthy,修订 e07c4aa |
| 仓库 | GitLab 集群内地址,登录页 HTTP 200 |
| vLLM | Pod uid 26326358-d9a7-4eec-8b13-df4d800d2ae5,/health 200 |
| 代理 | argocd-ui-proxy 策略 Recreate,就绪 1 |
| Gitea 命名空间 | 已经不在 |
scripts/10-安装KEDA.sh、scripts/12-部署ArgoCD.sh、scripts/13-纳管GitOps.sh 在现网上再执行都会退出。10 看到 KEDA 已安装就停。12 看到 argocd-server 已在就停。13 看到 Application platform 已在就停,避免再滚动导航页。Argo CD 的安装清单在 config/argocd-install.yaml。GitLab 的清单在 config/gitlab.yaml,Application 在 config/argocd-app-platform.yaml。