ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

LMCache 的 K3s 构建基 CI Harness 架构:单节点 Kubernetes 之上的 GPU 测试集群设计与实现

LMCache 的 K3s 构建基 CI Harness 架构:单节点 Kubernetes 之上的 GPU 测试集群设计与实现 LMCache 的 K3s 构建基 CI Harness 架构单节点 Kubernetes 之上的 GPU 测试集群设计与实现【免费下载链接】LMCacheLMCache: Supercharge Your LLM with the Fastest KV Cache Layer项目地址: https://gitcode.com/GitHub_Trending/lm/LMCache本文系统梳理 LMCache 项目中基于 K3s 的 Buildkite CI HarnessCI 基架的整体架构它如何在任意一台裸机 Linux GPU 机器上通过一条脚本拉起一套完整的 CI 测试集群并以临时 Pod方式执行每个测试任务。读完本文你将掌握这套 CI 体系的核心设计决策GPU Operator、agent-stack-k8s、本地基础镜像、共享卷、节点初始化与 CI 执行的完整流程以及 setup 脚本、环境准备脚本、GPU 监控与 teardown 的实操细节可以直接复用到自己的 GPU CI 场景。一、为什么 LMCache 需要一套 K3s CI HarnessLMCache 是一个面向 LLM 的 KV Cache 层其 CI 需要频繁在真实 GPU 上跑 vLLM 集成测试、多进程测试与各类正确性验证。在引入这套 K3s 方案之前传统的裸机 Buildkite agent 方式存在明显的痛点ARCHITECTURE.md 总结了四点核心动机易于搭建Ease of Setup希望在任何一台裸机 Linux GPU 机器上仅凭一个脚本setup-cluster.sh就能拉起一个功能完整的 CI 节点避免手动配置依赖或维护常驻的 Buildkite agent。与机器无关Machine Agnostic不再依赖机器专属脚本例如自定义的pick-free-gpu.sh。任何带 NVIDIA GPU 和 Docker 的机器上CI 都以相同的方式运行。干净环境Clean Environments消除测试运行之间的状态泄漏——没有共享的 pip/uv 缓存没有残留文件每个任务都拿到一个全新的环境。自动化资源管理Automated Resource Management借助标准 Kubernetes 原语完成 GPU 分配、卷挂载与清理而不是靠手写脚本去锁 GPU。二、五项核心设计决策1. K3s NVIDIA GPU OperatorCI 集群采用K3s——一个轻量级、单节点的 Kubernetes 发行版。NVIDIA GPU Operator自动配置容器运行时并把 GPU 暴露给 K8s抽象掉底层硬件差异、自动完成 GPU 发现。从 setup-cluster.sh 可以看到GPU Operator 通过 Helm 安装并显式设置driver.enabledfalse宿主机已装驱动与toolkit.enabledtrue随后等待 device-plugin daemonset 就绪再用kubectl get node -o jsonpath{.items[0].status.allocatable.nvidia\.com/gpu}确认可分配的 GPU 数量。2. 基于临时 Pod 的执行agent-stack-k8s不使用常驻的buildkite-agent二进制而是采用 Buildkite 官方的agent-stack-k8s一个 controller Pod 在 K3s 内轮询 Buildkite 队列动态地为每个任务拉起一个临时的 K8s Pod 执行任务任务结束后 Pod 被销毁。因此机器上不存在任何常驻 agent也就没有 agent 生命周期管理、没有跨任务的环境污染。3. 声明式 GPU 分配与自动并行每个 pipeline step 在 Kubernetes Pod 规格中显式声明它需要的 GPU 数量resources: limits: nvidia.com/gpu: 2 # 请求 2 张 GPU由于 Kubernetes 负责原子化的资源调度多 GPU 节点上的任务会自动并行。文档给出了一个直观的例子若节点有 4 张 GPU三个任务分别请求 1、2、1 张 GPUK8s 会把它们同时调度运行若再来一个请求 2 张 GPU 的任务它会排队等待资源释放。这彻底消除了手动 GPU 锁机制例如仓库中旧有的pick-free-gpu.sh、pick-free-gpu-amd.sh这类脚本的需求。真实的 pipeline 用法可参考 unit/pipeline.ymlstep 通过kubernetes插件指定podSpec在limits.nvidia.com/gpu声明 GPU 数量并用requests/limits声明 CPU 与内存。4. 本地基础镜像与临时环境准备为避免对 Docker registry 的依赖setup-cluster.sh会自动检测宿主 GPU 的计算能力compute capability本地构建lmcache/ci-base:latest镜像并直接导入 K3s 的 containerd。每个任务 Pod 使用该基础镜像在运行时通过setup-env.sh动态安装 vLLM 与 LMCache。镜像本身不包含 vLLM/LMCache见 ci-base.Dockerfile 的注释说明只提供 CUDA 13.0.2 Ubuntu 24.04 Python 3.12 uv 构建依赖并把requirements/*.txt中不常变的依赖预先装好。5. 共享宿主机卷像 HuggingFace 模型权重、数据集这类体积大、读多写少的目录通过hostPath挂载进 Pod避免重复下载、加速测试同时任务环境本身保持无状态。在 unit/pipeline.yml 中可以看到三种典型卷/data/huggingface挂到/root/.cache/huggingface模型缓存、/data/gds-scratch挂到/scratchGDS 临时目录注释特别说明不能用 subPath 否则会破坏 cuFile 的 fs-type 检测、以及一个 16 GiB 的 tmpfsemptyDir挂到/dev/shm规避 K8s 默认 64 MiB shm 导致 shm_allocator 测试 SIGBUS 的问题。三、整体架构流程节点初始化一次性 setup[ Raw Linux Host NVIDIA GPU ] | | (run setup-cluster.sh) v ----------------------------------------------------- | K3s Cluster | | | | 1. Install K3s | | 2. Install Helm - Deploy NVIDIA GPU Operator | | 3. Build CI Base Image (lmcache/ci-base:latest) | | 4. Import Base Image to K3s containerd | ----------------------------------------------------- | | (run install-agent-stack.sh) v [ agent-stack-k8s Controller Pod (Watches queue) ]对应的落地脚本是 setup-cluster.sh它被设计为幂等脚本头部注释明确 Safe to re-runK3s 已运行则跳过安装GPU Operator 已安装则跳过基础镜像已导入 containerd 则跳过构建。关键细节包括安装 K3s 时使用--disabletraefikCI 场景不需要 ingress与--write-kubeconfig-mode644并把KUBECONFIG/etc/rancher/k3s/k3s.yaml持久化到~/.bashrc通过nvidia-smi --query-gpucompute_cap自动探测计算能力生成TORCH_CUDA_ARCH_LIST${COMPUTE_CAP}PTX作为docker build的 build-arg确保镜像中的 torch/CUDA 扩展与宿主机 GPU 匹配镜像构建后用docker save | k3s ctr images import -直接灌入 K3s containerd全程不依赖外部 registry末尾创建共享宿主机卷目录/data/huggingface与/data/datasets并打印集群就绪摘要K3s 版本、GPU Operator 版本、GPU 数量与型号、arch list、镜像名。CI 执行流程Buildkite Web UI | | 1. Job pushed to k8s queue v agent-stack-k8s Controller (in K3s) | | 2. Reads job, creates ephemeral Pod requesting GPUs v ------------------------------------------------------------- | Job Pod (e.g., limits: nvidia.com/gpu: 1) | | | | - Mounts /data/huggingface from host | | - Runs setup-env.sh (Installs vLLM, LMCache) | | - Executes test script (e.g., pytest) | ------------------------------------------------------------- | | 3. Test finishes (Pass/Fail) v agent-stack-k8s Controller | | 4. Reports result to Buildkite | 5. Destroys the Pod (wipes environment) v Buildkite Web UI四、与 Buildkite 的集成方式README.md 详细说明了这套方案与传统裸机 agent 的区别机器上没有常驻 agent。agent-stack-k8s 的 controller Pod 轮询 Buildkite 队列有任务出现就创建 Pod任务结束就删除 Pod。在 Buildkite Web UI 侧需要准备三件事创建一个队列进入 Organization Settings → Default cluster → Queues → New Queue创建名为k8s的队列名字可自选。队列不需要任何配置也不要注册任何 agent获取 agent token从 cluster 设置页复制 agent token获取 GitHub token创建对仓库有读写权限的 PAT或 fine-grained token用于 HTTPS checkout 以及向benchmarks-main分支推送 baseline。然后执行 install-agent-stack.sh.buildkite/k3_harness/install-agent-stack.sh BUILDKITE_AGENT_TOKEN GITHUB_TOKEN若想使用k8s以外的队列名通过环境变量指定BUILDKITE_QUEUEmy-queue .buildkite/k3_harness/install-agent-stack.sh AGENT_TOKEN GITHUB_TOKEN该脚本内部做了两件事一是创建名为buildkite-git-creds的 K8s secret包含两个键——.git-credentials供 agent-stack-k8s 的 checkout 容器做 HTTPS clone前缀点号对应 git-credential-store 的约定与GITHUB_TOKEN注入任务容器供 git push 使用二是通过 Helm 从oci://ghcr.io/buildkite/helm/agent-stack-k8s安装/升级agent-stack-k8s版本 0.38.0设置agentToken、config.queue并通过config.default-checkout-params.gitCredentialsSecret让 checkout 走 HTTPS。Pipeline step 通过如下方式指向该队列agents: queue: k8s # must match the queue name五、每个任务的环境准备setup-env.sh 深度拆解每个 CI 任务都会先 source setup-env.sh 来安装 vLLM 与 LMCachecommand: | source .buildkite/k3_harness/setup-env.sh bash .buildkite/scripts/my-test.sh每个 Pod 拥有独立的临时文件系统任务结束后被完全清空——没有共享 pip/uv 缓存没有跨 Pod 争用。这个脚本远比装两个包复杂它沉淀了大量真实 CI 踩坑经验值得逐段理解GPU 健康预检脚本开头调用helpers.sh中的check_gpu_health 80见 helpers.sh。若 Pod 分到的 GPU 空闲内存低于 80%通常由宿主机上的残留进程导致任务立即失败并给出明确信息而不是在 setup 之后才撞上晦涩的 CUDA OOM。运行时架构重探测基础镜像可能在不同 GPU 主机上构建例如 H200 的 sm_90 镜像无法在 A100 的 sm_80 上加载内核因此脚本用nvidia-smi重新获取运行时 GPU 的计算能力并导出TORCH_CUDA_ARCH_LIST覆盖镜像构建时的值。合并 PR 目标分支调用merge_pr_base_branchhelpers.sh 中定义在任务 Pod 内把 PR 分支合并进目标分支再测试。vLLM 版本解析source resolve-pinned-vllm.sh按优先级解析要装的 vLLM nightly显式PINNED_VLLM_VERSION环境变量 从buildkite_latest_tested_vllm分支拉取的latest_tested_vllm.txtcanary 构建最近验证过的版本 空值回退到最新 nightly。pin 文件除了裸版本号还携带short_sha、full_sha、archive_index_url等元数据使安装侧无需额外 API 调用USE_PINNED_VLLMfalse可跳过 pincanary 构建自身使用避免自我确认。字节码/缓存驱逐CI 中曾出现ImportError: cannot import name GenerationConfig from transformers——即使已安装文件明确包含该符号同一安装配方在全新 venv 中总能成功说明故障与基础镜像文件系统状态残留__pycache__、overlayfs 部分升级有关。因此脚本在安装前后各执行一次find ... -name __pycache__ -exec rm -rf和uv cache clean。vLLM nightly 安装钉死 cu130 索引基础镜像是nvidia/cuda:13.0.2-devel-ubuntu24.04系统 nvcc 13。vLLM 通用 nightly 索引可能随机解析到 cu128 或 cu130 的 torch wheel当解析到 cu128 时torch.utils.cpp_extension._check_cuda_version会因 CUDA 版本不匹配13.0 vs 12.8中止 LMCache 的可编辑安装。因此脚本强制使用--extra-index-url https://wheels.vllm.ai/nightly/cu130与https://download.pytorch.org/whl/cu130并配合--reinstall-package transformers/tokenizers/huggingface-hub/safetensors/vllm强制重装绕开基础镜像中的文件系统级不一致。若启用 pin则优先使用archive_index_url指向的 commit 归档索引vLLM nightly 索引只保留最新 wheel一两天就滚动下线但wheels.vllm.ai/full-commit-sha/cuda/是永久保留的 PEP 503 索引旧格式 pin 文件则通过 GitHub commits API 展开短 SHA。vLLM CLI 探测与自愈通过子进程执行vllm --help来完整探测vllm serve的导入链vllm.entrypoints.cli.main.main()会在函数体内触发from transformers import GenerationConfig, PretrainedConfig仅import vllm.entrypoints.cli.main不会执行函数体无法发现问题。探测失败且为ModuleNotFoundError时自动安装缺失模块最多 5 次如 vLLM nightly 中未声明的pandas其他错误则输出一份完整的 transformers 诊断 dump包版本、目录、_import_structure、_class_to_module等并退出。torch/nvcc CUDA 版本一致性检查python片段对比torch.version.cuda与系统nvcc的主版本号不匹配立即失败——否则这个错误会在 ninja 编译深处以晦涩的cusparse.h: No such file or directory出现。LMCache 从源码可编辑安装设置SETUPTOOLS_SCM_PRETEND_VERSION_FOR_LMCACHE0.0.0ci仓库带有nightly、nightly-cu13等非 PEP-440 tag会击穿较新的 vcs_versioning 后端uv pip install -e . --no-build-isolation后安装requirements/proto.txt并运行lmcache/v1/multiprocess/transport/grpc_impl/_proto_gen/_generate.py生成 gRPC 绑定安装前后各uv pip freeze | sort一次并 diff展示 LMCache 安装对依赖的改动。安装后二次 CLI 探测LMCache 可编辑安装可能为了满足requirements/common.txt的版本上限而降级传递依赖破坏 vLLM CLI 导入链。脚本再次执行probe_vllm_cli失败则打印 traceback 与uv pip freeze直接退出而不是让每个测试 harness 在wait_for_server超时 180 秒后才暴露问题。最终脚本以python -c import vllm; import lmcache; ...验证环境就绪。此外仓库还提供 setup-lmcache-only-env.sh不需要 vLLM 的轻量任务如单元测试与 setup-sglang-env.sh、setup-blend-env.sh特定任务场景等变体。六、共享卷与 GPU 分配细节README 中给出了挂载进每个 Pod 的共享卷清单HostContainerWhat/data/huggingface/root/.cache/huggingface模型权重读密集、写一次/data/datasets/root/correctness测试数据集下载后只读GPU 分配方式为每个 pipeline step 显式声明plugins: - kubernetes: podSpec: containers: - resources: limits: nvidia.com/gpu: 2 # 1 或 2GPU 的原子化分配由 K8s device plugin 完成不再需要pick-free-gpu.sh之类的脚本。七、CI 基础镜像的构建与重建ci-base.Dockerfile 基于nvidia/cuda:13.0.2-devel-ubuntu24.04安装 ccache、git、curl、jq、lsof、ffmpeg、libnuma1、libcudart12 等系统依赖安装 uv创建/opt/venv并预装requirements/cuda.txt与requirements/build.txt。TORCH_CUDA_ARCH_LIST作为 build-arg 在构建时写入环境变量与 CI 机器的 GPU 匹配。基础镜像默认由setup-cluster.sh自动构建并导入 K3s containerd无需 registry。修改requirements/*.txt或ci-base.Dockerfile后需要强制重建REBUILD_IMAGE1 .buildkite/k3_harness/setup-cluster.sh八、集群验证、GPU 监控与 teardown冒烟测试smoke-test.sh 用于验证集群就绪检查节点、检查可分配 GPU 数少于 1 则失败随后提交一个请求nvidia.com/gpu: 1的nvidia/cuda:12.8.0-base-ubuntu24.04Pod 执行nvidia-smi等待其 Succeeded 后输出日志并清理。双层 GPU 监控这套体系对 GPU 健康做了双层防护任务级每个 CI 任务启动时通过check_gpu_health默认要求 80% 空闲内存快速失败宿主机级gpu-monitor.sh 每 10 分钟扫描一次通过遍历/sys/fs/cgroup/*/kubepods*的 cgroup.procs、以及crictl ps/crictl inspect收集 K8s 容器 PID与nvidia-smi --query-compute-appspid的 GPU 进程集合做差集找出不属于任何 K8s Pod 的残留 GPU 进程并记录 PID、命令、GPU bus、显存占用与进程年龄从/proc/$pid/stat的 start time 推算输出到/var/log/gpu-monitor.log。安装方式# 安装每 10 分钟检查一次残留进程的 cron 任务 sudo bash .buildkite/k3_harness/setup-gpu-monitor.shsetup-gpu-monitor.sh会同时配置 logrotate每日轮转、保留 7 份、压缩。查看日志与移除 cron# 查看监控日志 tail -f /var/log/gpu-monitor.log # 移除 cron 任务 crontab -l 2/dev/null | grep -v gpu-monitor.sh | crontab -完整 teardownteardown.sh 按序卸载 agent-stack-k8s、GPU Operator含命名空间最后调用k3s-uninstall.sh移除 K3s。/data/*宿主数据卷被保留便于下次重建集群后继续复用模型与数据集缓存。九、k3_harness 目录速览.buildkite/k3_harness/ ├── ci-base.Dockerfile # CI 基础镜像定义CUDA 13 Python 3.12 uv不含 vLLM/LMCache ├── setup-cluster.sh # 一次性K3s GPU Operator 基础镜像构建与导入幂等 ├── install-agent-stack.sh # 一次性安装 agent-stack-k8s需要 agent token GitHub token ├── values.yaml # 参考 Helm values仅文档用途 ├── setup-env.sh # 每任务安装 vLLM LMCache含 GPU 健康检查与多级自检 ├── resolve-pinned-vllm.sh # 解析 vLLM nightly pin 版本 ├── setup-lmcache-only-env.sh / setup-sglang-env.sh / setup-blend-env.sh # 场景化环境准备变体 ├── smoke-test.sh # 验证 GPU Pod 能在 K3s 中运行 ├── gpu-monitor.sh # 宿主机级检测非 K8s 的残留 GPU 进程 ├── setup-gpu-monitor.sh # 将 gpu-monitor.sh 安装为 cron 任务 └── teardown.sh # 卸载全部组件保留 /data/*配合 k3_tests 目录下的各测试套件unit、comprehensive、integration、multiprocess、correctness、blend、sglang、amd、musa、xpu 等以及 pipelines 下的clean.yml、comprehensive-tests.yml、end-to-end-tests.yml、multiprocessing-test.yml这套 K3s harness 构成了 LMCache 在真实 GPU 上持续验证的核心基座任何机器、一条脚本、干净的临时环境、由 Kubernetes 原生保证的 GPU 并行与隔离。【免费下载链接】LMCacheLMCache: Supercharge Your LLM with the Fastest KV Cache Layer项目地址: https://gitcode.com/GitHub_Trending/lm/LMCache创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表