📎 配套脚本附件正文未内嵌 · 共 12 个 · 点开可在线查看
📂 查看全部 126 个脚本附件 →
⚠️ 脚本内含明文凭据(与本页正文一致),请勿在公网环境直接运行。
CI/CD · KEDA + GitOps

用 KEDA 按排队扩容 Worker,并用 GitLab 与 Argo CD 纳管工作负载

KEDA 按 vLLM 排队数把 Dify worker 从 1 扩到最多 3 个副本;Argo CD 把 llm / dify / observability 的工作负载收进 GitLab 私有仓库自动同步。

用 KEDA 按排队扩容 Worker,并用 GitLab 与 Argo CD 纳管工作负载

目录

  1. 一、这三样各自做什么
  2. 二、动手前现网是什么样
  3. 三、安装 KEDA
  4. 四、模拟一次排队
  5. 五、安装 Argo CD
  6. 六、把现有工作负载收进 Git
  7. 七、GitLab CE
  8. 八、做完时的核对
  9. 九、文件

本文记录这一阶段在现网上的做法:安装 KEDA 2.21.0,让 Dify 的 worker 在 vLLM 排队超过 10 时扩到最多 3 个副本;安装 Argo CD 3.5.4,把 llm、dify、observability 的工作负载收进 GitLab CE 的私有仓库,由 Application 自动同步。本章目录是 cicd。机器是 prod102,地址 10.0.1.47。集群、探针、GPU Operator 和 Vault 写在同级目录 k8s-从零部署、k8s-迁移、k8s-探针与密钥。流程对照页是同目录的《走一遍 GitOps:KEDA、GitLab 和 Argo CD.html》。

scripts/10、scripts/12、scripts/13 发现现网已经装过就会停住。不要在这台机器上再执行一遍。scripts/11 会短时间把 worker 扩到 3 再缩回 1,复习时看记录即可。

登录口令沿用现网值。Vault 根令牌、Langfuse 的 NEXTAUTH_SECRET、SALT、ENCRYPTION_KEY、Redis 口令、MinIO 口令、kubeadm 加入令牌,以及 Argo CD 仓库 Secret 里的个人访问令牌,不写进本文。不要把本文发到公网。

一、这三样各自做什么

请求路径没有变:浏览器打开 Dify,对话从 Dify 到 New-API,再到 vLLM 的 qwen3.6-27b。这一阶段在这条路径旁边加了两层控制。

1. KEDA

KEDA 按外部指标修改 Deployment 的副本数。本机的指标来自 Prometheus,查询是:

text
sum(vllm:num_requests_waiting{model_name="qwen3.6-27b"})

Prometheus 地址是 http://prometheus.observability.svc.cluster.local:9090。threshold 和 activationThreshold 都是 "10"。排队人数小于或等于 10 时触发器不激活,dify/worker 保持 1 个副本。超过 10 之后,期望副本是排队人数除以 10 再向上取整,上限 3。伸缩对象是 worker,不包括 vLLM,也不包括 worker-beat。

KEDA 会创建 HPA keda-hpa-dify-worker。副本下限已经是 1,又没有空闲副本,KEDA 提示 pollingInterval 和 cooldownPeriod 不参与伸缩,改副本数的是这条 HPA。

2. Argo CD

Argo CD 把 Git 仓库里的 YAML 当成集群的期望状态。Application platform 盯着仓库的 manifests 目录,发现差异就提交到集群。selfHeal 为 true,有人直接改集群时会拉回 Git 上的内容。prune 为 false,Git 里没有的对象不会被删掉。

dify/worker 的 /spec/replicas 写在 ignoreDifferences 里。KEDA 把副本改成 2 或 3 时,Argo CD 不会把它改回 Git 里的 1。

3. GitLab CE

Git 仓库放在 GitLab Community Edition 19.4.2。这是 GitLab 的开源版本。网页是 http://10.0.1.47:8929,登录 root / R3po-Argo-2026。项目 gitops/platform 是私有的,默认分支 main。

Argo CD 在集群内使用:

text
http://gitlab.gitlab.svc.cluster.local:8929/gitops/platform.git

拉仓库的用户名是 oauth2,口令是个人访问令牌,放在 Secret argocd/gitops-repo。令牌本身不写进本文。

二、动手前现网是什么样

vLLM、Dify、监控已经在跑,环境变量已经由 Vault 和 External Secrets 同步。节点可分配的 nvidia.com/gpu 是 1。vLLM、Xinference 和宿主机 Python 都不申请这个资源。

写 ScaledObject 和导出清单时,没有改 vLLM 镜像,没有给 vLLM 加上 nvidia.com/gpu,也没有重启 New-API。

三、安装 KEDA

Helm release 名 keda,命名空间 keda,chart 版本 2.21.0。三个镜像都在 ghcr.dockerproxy.net/kedacore,标签 2.21.0,拉取策略 IfNotPresent。安装时三个 Pod 各重启过一次,随后保持 1/1。

config/scaledobject-dify-worker.yaml 就是现网对象。scripts/10-安装KEDA.sh 在 prod102 上发现 release 已存在会退出。

四、模拟一次排队

scripts/11-模拟排队扩容.sh 把查询临时写成 vector(25),并把 HPA 的扩容、缩容稳定窗口设为 0。worker 从 1 个就绪变成 3 个就绪。HPA 先显示 25/10,三个副本就绪后显示约 8334m/10。脚本退出时把查询改回真实的 sum(),副本回到 1。vLLM 的 /health 保持 200。

现网查询已经是真实的 sum()。不要把 vector(25) 留在 ScaledObject 上。

五、安装 Argo CD

版本 v3.5.4。安装对象都在 config/argocd-install.yaml,这是官方 install.yaml 换过镜像之后的同一份,大约 3.4 万行,CRD 占了绝大部分。提交时用 kubectl apply --server-side --force-conflicts,因为客户端 apply 会在 applicationsets.argoproj.io 的注解长度上失败。镜像:

组件镜像
argocdm.daocloud.io/quay.io/argoproj/argocd:v3.5.4
dexghcr.dockerproxy.net/dexidp/dex:v2.45.1
redisdocker.m.daocloud.io/redis:8.2.3-alpine

上游清单里的 imagePullPolicy: Always 已改成 IfNotPresent。argocd-cmd-params-cm 里 server.insecure 为 "true"。argocd-cm 的调和超时是 30 秒,对外地址是 http://10.0.1.47:8080,管理员账号允许登录。

scripts/12-部署ArgoCD.sh 看到 argocd-server 已在就会退出。

网页不直接暴露 argocd-server。config/argocd-ui-proxy.yaml 用 nginx 把节点 8080 转到 argocd-server.argocd.svc.cluster.local:80。转发的头是 Host、X-Forwarded-For、X-Forwarded-Proto、X-Forwarded-Host。Deployment 策略是 Recreate,同一时间只有一个 Pod 占用 8080。

登录:http://10.0.1.47:8080 ,admin / Argocd-git-2026。这组账号的会话接口返回 200,浏览器也能进入 Applications。

六、把现有工作负载收进 Git

导出程序是 scripts/export_gitops.py。范围是三个命名空间里的 Deployment、Service、ExternalSecret、ScaledObject。Secret 不导出。对象上的 uid、resourceVersion、managedFields 和 status 会去掉。

创建 Application 之前,用 dry-run 对比过每个 Deployment 的 Pod 模板。模板一致,第一次同步没有新建 Pod。vLLM 的 Pod 仍是 vllm-67b8d8c9f6-vvfsq,uid 26326358-d9a7-4eec-8b13-df4d800d2ae5。

演示提交只改了导航页模板注解 gitops.local/demo=nav-1。硬刷新后,导航页 Pod 带上这行注解。导航页策略是 Recreate,所以换的是导航页自己的 Pod。vLLM 没有换。/health 仍是 200。

作业里更换 vLLM 镜像那一步没有做。那两个标签和现网镜像对不上,改镜像会重启正在服务的模型。

scripts/13-纳管GitOps.sh 看到 Application platform 已在就会退出。现网不要再跑它。

config/argocd-app-platform.yaml:

yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: platform
  namespace: argocd
spec:
  project: default
  source:
    repoURL: http://gitlab.gitlab.svc.cluster.local:8929/gitops/platform.git
    targetRevision: main
    path: manifests
    directory:
      recurse: true
  destination:
    server: https://kubernetes.default.svc
    namespace: default
  syncPolicy:
    automated:
      prune: false
      selfHeal: true
    syncOptions:
      - ApplyOutOfSyncOnly=true
      - RespectIgnoreDifferences=true
  ignoreDifferences:
    - group: apps
      kind: Deployment
      name: worker
      namespace: dify
      jsonPointers:
        - /spec/replicas

七、GitLab CE

镜像 docker.m.daocloud.io/gitlab/gitlab-ce:19.4.2-ce.0。数据目录 /usr/cluster/gitlab 挂到容器的 /var/opt/gitlab、/var/log/gitlab、/etc/gitlab。节点端口 8929。容器内 SSH 不对节点发布。捆绑 Prometheus 关闭。内存请求 4Gi,上限 8Gi。/dev/shm 用 512Mi 的内存卷。

/-/readiness 在这版、并且关闭捆绑监控之后返回 404。探针使用 /users/sign_in,HTTP 200 才算就绪。更新策略是 Recreate。

GitLab 拒绝了含有产品名的初始口令。网页账号是 root / R3po-Argo-2026。浏览器已经用这组账号打开 gitops/platform。注册已关闭。

仓库 main 上有两个提交,当前修订 e07c4aa6f11d5740bc1dd0759a0003d2b2d23814。Application 指向 GitLab 之后仍是 Synced、Healthy,vLLM 的 uid 没有变。

早先的 Gitea 工作负载已经删除。数据目录 /usr/cluster/gitea 还在磁盘上,当前同步不读它。

清单在 config/gitlab.yaml。prod102 上 GitLab 已经在跑,不要再提交一份会滚动它的安装。

八、做完时的核对

检查结果
KEDAkeda-operator、metrics-apiserver、admission-webhooks 均为 1/1
ScaledObjectReady 为 True,Active 为 False,查询为真实 sum()
worker副本 1,就绪 1
Argo CD各组件 1/1。platform Synced、Healthy,修订 e07c4aa
仓库GitLab 集群内地址。登录页 HTTP 200
代理argocd-ui-proxy 策略 Recreate,就绪 1
vLLMuid 26326358-d9a7-4eec-8b13-df4d800d2ae5,/health 为 200
Gitea 命名空间已删除

再看一眼:

bash
kubectl -n dify get scaledobject dify-worker
kubectl -n dify get deploy worker
kubectl -n argocd get application platform
kubectl -n gitlab get pods
kubectl -n llm get pod -l app=vllm
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/health
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8080/
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8929/users/sign_in

九、文件

文件作用
config/keda-values.yamlKEDA 2.21.0 的镜像和副本数
config/scaledobject-dify-worker.yaml现网 ScaledObject,查询必须保持真实 sum()
scripts/10-安装KEDA.sh安装 KEDA 并提交 ScaledObject。release 已在时退出
scripts/11-模拟排队扩容.sh用 vector(25) 扩到 3 再缩回 1,结束时恢复真实查询
config/argocd-install.yamlArgo CD 3.5.4 的安装清单。镜像、明文访问和对外地址已经写在里面
config/argocd-ui-proxy.yaml节点 8080 到 argocd-server 的反代,策略 Recreate
config/argocd-app-platform.yamlApplication platform,仓库指向 GitLab
config/gitlab.yamlGitLab CE。数据在 /usr/cluster/gitlab,端口 8929
scripts/12-部署ArgoCD.sh安装 Argo CD 3.5.4。server 已在时退出
scripts/13-纳管GitOps.sh早期纳管步骤。Application 已在时退出,现网不要再跑
scripts/export_gitops.py导出 Deployment、Service、ExternalSecret、ScaledObject
走一遍 GitOps:KEDA、GitLab 和 Argo CD.html按真实结果整理的流程说明