Kubernetes Operator#

LMCache Kubernetes 操作符自动化了 LMCache 多进程服务器的部署和生命周期管理。您只需声明一个 LMCacheEngine 自定义资源,操作符将协调所有底层的 Kubernetes 对象,而无需手动编写 DaemonSets、Services 和 ConfigMaps(如手册 部署指南 指南中所述)。

为什么使用 Operator#

手动 DaemonSet 方式可以正常工作,但存在一些操作符已消除的陷阱:

  • 自动注入的 Pod 设置 -- 操作符始终设置 hostIPC: true--host 0.0.0.0。在手动编写的清单中忘记 hostIPC 会导致难以调试的静默 CUDA IPC 失败 (cudaErrorMapBufferObjectFailed)。

  • 节点本地服务发现 -- 操作符创建一个 ClusterIP 服务,并设置 internalTrafficPolicy=Local,同时生成一个连接用 ConfigMap,vLLM Pod 直接挂载即可。无需 hostNetwork,无需 Downward API,也无需 shell 变量替换。

  • 自动计算资源规格 -- 内存请求和限制由 l1.sizeGB 推算得出,避免因资源不足导致 OOM 被杀或因资源过剩浪费节点容量。

  • 声明式 Prometheus 集成 -- 设置 prometheus.serviceMonitor.enabled: true,操作符会创建一个 ServiceMonitor CR,Prometheus 操作符会自动发现它。

  • CRD 验证 -- OpenAPI Schema 验证在 kubectl apply 阶段、Pod 创建之前捕获配置错误(例如 l1.sizeGB <= 0、端口范围无效等)。

前提条件#

  • Kubernetes 1.20+

  • kubectl 配置为访问您的集群

  • (可选) Prometheus Operator 以支持 ServiceMonitor

安装 Operator#

选项 A:从发布版一行安装(推荐)

# Latest stable release
kubectl apply -f https://github.com/LMCache/LMCache/releases/download/operator-latest/install.yaml

# Or nightly build from the dev branch
kubectl apply -f https://github.com/LMCache/LMCache/releases/download/operator-nightly-latest/install.yaml

选项 B:从源代码构建

cd operator
make build
make install
make deploy IMG=<your-registry>/lmcache-operator:latest

部署 LMCacheEngine#

一个最小的 CR 在每个 GPU 节点上部署一个具有 60 GB L1 缓存的 DaemonSet:

apiVersion: lmcache.lmcache.ai/v1alpha1
kind: LMCacheEngine
metadata:
  name: my-cache
spec:
  l1:
    sizeGB: 60
kubectl apply -f lmcache-engine.yaml

操作符自动:

  • 在每个匹配的节点上创建一个运行 LMCache 服务器 Pod 的 DaemonSet

  • 设置 hostIPC: true 并将 --host 0.0.0.0 传递给服务器

  • 为 vLLM 发现创建一个节点本地的 ClusterIP 服务

  • 创建一个连接 ConfigMap (my-cache-connection),其中包含 vLLM 所需的 kv-transfer-config JSON。

  • 自动计算 L1 缓存大小的资源请求/限制

  • 默认将 nodeSelector 设置为 nvidia.com/gpu.present: \"true\"

备注

该操作符将容器镜像默认设置为 lmcache/vllm-openai:latest。可以通过 spec.image.repositoryspec.image.tag 来覆盖,以固定特定版本。

连接 vLLM#

操作符创建一个名为 <engine-name>-connection 的 ConfigMap,其中包含 kv-transfer-config JSON。您可以让操作符的变更 webhook 为您注入它(推荐 -- 这样可以保持您的 vLLM 清单整洁),或者手动挂载它。有关 webhook 流程,请参见下面的 连接注入(Webhook);本节的其余部分描述了其等效的手动挂载。

在你的 vLLM 部署中挂载它:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: vllm
spec:
  replicas: 1
  selector:
    matchLabels:
      app: vllm
  template:
    metadata:
      labels:
        app: vllm
    spec:
      # Required for CUDA IPC between vLLM and LMCache
      hostIPC: true
      containers:
        - name: vllm
          image: lmcache/vllm-openai:latest
          env:
            # Deterministic hashing required by LMCache
            - name: PYTHONHASHSEED
              value: "0"
          command: ["/bin/sh", "-c"]
          args:
            - |
              exec python3 -m vllm.entrypoints.openai.api_server \
                --model <your-model> \
                --port 8000 \
                --gpu-memory-utilization 0.8 \
                --kv-transfer-config "$(cat /etc/lmcache/kv-transfer-config.json)"
          ports:
            - name: http
              containerPort: 8000
          volumeMounts:
            - name: kv-transfer-config
              mountPath: /etc/lmcache
              readOnly: true
          resources:
            limits:
              nvidia.com/gpu: "1"
      volumes:
        - name: kv-transfer-config
          configMap:
            name: my-cache-connection  # <engine-name>-connection

vLLM Pod 的关键要求:

  • hostIPC: true -- CUDA IPC (cudaIpcOpenMemHandle) 需要在 vLLM 和 LMCache 之间共享 IPC 命名空间。

  • PYTHONHASHSEED=0 -- 确保 Token 哈希的确定性,使 vLLM 与 LMCache 生成一致的缓存键。

  • ConfigMap 挂载 -- $(cat ...) 模式以内联方式读取连接 JSON。ConfigMap 名称始终为 <LMCacheEngine name>-connection

  • 无需 hostNetwork -- 操作符的节点本地服务通过 internalTrafficPolicy=Local 处理路由。

连接注入(Webhook)#

手动连接 ConfigMap 挂载和 $(cat ...) 参数替换在 vLLM 部署中是重复的。一个随操作员提供的 变更入场 webhook 可以为您完成此操作,从而保持 vLLM 清单的整洁。它镜像了 CacheBlend webhook(参见 CacheBlend),并使用 lmcache- 注释/标签区分符,以便两个注入器不会在同一 pod 上相互干扰。

当在一个已选择的 pod 上调用且存在 <engine>-connection ConfigMap 时,webhook 会在入场时修改 pod 以添加:

  • --kv-transfer-config <JSON> -- LMCacheMPConnector 配置,逐字读取自引擎的 <engine>-connection ConfigMap,并内联到 vLLM 容器的 args 中(无需卷挂载);

  • hostIPC: true 在 pod 规格中(与节点本地服务器的 CUDA IPC);

  • PYTHONHASHSEED=0 在 vLLM 容器环境中,仅在缺失时设置 -- 它保留您已经设置的值。

与 CacheBlend 注入器不同,它**不**咨询引擎 CR:整个连接器配置位于连接 ConfigMap 中,LMCacheEngine 没有注入子规范。它在失败时保持开放(failurePolicy: Ignore),并且是幂等的(携带 lmcache.ai/lmcache-injected 标记的重新接纳 Pod 允许保持不变)。

前提条件#

  • cert-manager + make deploy``(不是 ``make run,后者仅限控制器并通过 ENABLE_WEBHOOKS=false 禁用 webhook)-- 与 CacheBlend webhook 相同;每个集群安装一次(请参见 CacheBlend "附加先决条件")。

  • Pod 安全标准 -- 注入的 hostIPCbaseline / restricted PSS 配置文件拒绝,因此 vLLM pod 的命名空间必须标记为 pod-security.kubernetes.io/enforce=privileged

  • 引擎在同一命名空间中协调 -- webhook 直接读取 <engine>-connection ConfigMap,因此 LMCacheEngine 必须已经存在于 vLLM pod 的命名空间中。

为 vLLM Pod 启用注入#

将 opt-in 标签和 engine-binding 注释添加到 pod 模板中,并通过镜像 ENTRYPOINT 启动 vLLM(仅参数)-- 跳过 command: [\"/bin/sh\", \"-c\", ...] 包装器(webhook 会标记 lmcache.ai/lmcache-skip-reason=command-override,因为附加的参数不会到达 vllm serve):

apiVersion: apps/v1
kind: Deployment
metadata:
  name: vllm-lmcache
spec:
  replicas: 1
  selector:
    matchLabels:
      app: vllm-lmcache
  template:
    metadata:
      labels:
        app: vllm-lmcache
        lmcache.ai/lmcache-inject: "true"        # opt-in (webhook objectSelector)
      annotations:
        lmcache.ai/lmcache-engine: "my-cache"    # bind to the engine (same namespace)
        # Optional -- name the vLLM container if it is not the first one:
        # lmcache.ai/lmcache-container: "vllm"
    spec:
      runtimeClassName: nvidia
      # Do NOT set hostIPC here or mount an emptyDir at /dev/shm -- the
      # webhook injects hostIPC=true; an emptyDir would shadow the host's
      # /dev/shm and break cudaIpcOpenMemHandle.
      containers:
        - name: vllm
          image: lmcache/vllm-openai:latest
          # Args-only launch (image ENTRYPOINT is ["vllm", "serve"]). The
          # webhook appends --kv-transfer-config; do NOT add it yourself
          # (a user-supplied one stamps skip-reason=kv-transfer-config-present).
          args: ["<your-model>", "--port", "8000", "--gpu-memory-utilization", "0.8"]
          ports:
            - name: http
              containerPort: 8000
          resources:
            limits:
              nvidia.com/gpu: "1"

可编辑的清单位于 operator/config/samples/vllm_lmcache_deployment.yaml

验证注入#

该 webhook 修改的是 Pods,而不是 Deployment,因此请检查一个 pod(而不是 Deployment 规格):

kubectl get pod -l app=vllm-lmcache -o yaml | \
  grep -E "hostIPC|kv-transfer-config|lmcache-injected|lmcache-skip-reason"

如果没有任何内容被注入,请检查 Pod 的 lmcache.ai/lmcache-skip-reason 注解:

  • command-override -- pod 使用 sh -c 包装器,因此注入的参数无法到达 vllm serve

  • kv-transfer-config-present -- 用户已经提供了 --kv-transfer-config;该 webhook 不会覆盖它。

  • engine-not-found -- <engine>-connection ConfigMap 缺失(引擎尚未协调,或命名空间错误,或名称错误)。

  • target-container-not-found -- lmcache.ai/lmcache-container 注解指定了一个 pod 中不存在的容器。

使用 failurePolicy: Ignore 时,webhook / 证书问题也会使 pod 静默未被修改 -- 确认操作员 pod 处于 Running 状态,并且 MutatingWebhookConfiguration 存在。

使用最新的(或固定的)LMCache#

默认情况下,vLLM pod 运行其镜像中内置的 lmcache。要运行 不同 的 lmcache 构建,例如将最新的 lmcache 部署到较旧的稳定 vLLM 镜像上,或保持 vLLM 客户端与其 LMCacheEngine 服务器运行的确切构建相同,请在引擎上设置 spec.injection.payloadImage。然后,网络钩子会将该镜像的 lmcache 树额外分阶段到每个选择加入的 pod 中:一个 emptyDir + 一个初始化容器将树复制进去,一个只读挂载,以及 PYTHONPATH=/lmcache-payload,以便 vLLM 导入分阶段的 lmcache 而不是内置的版本。无需重建 vLLM 镜像。

1. 构建负载镜像。 它在启动时将解压缩的 lmcache 树放在 /payload 下,并将其复制到 $SHARED_DIRdocker/Dockerfile.payload 通过从 lmcache 镜像中提取与 ABI 匹配的 lmcache 来构建它(SOURCE_IMAGE 构建参数选择版本):

docker build -f docker/Dockerfile.payload \
  --build-arg SOURCE_IMAGE=lmcache/vllm-openai:latest-nightly \
  -t <registry>/lmcache-payload:latest .
docker push <registry>/lmcache-payload:latest

2. 指向引擎。 payloadImage.repository 没有有效的默认值(继承的镜像默认值不是有效负载),因此需要明确设置;保持 injection 未设置将仅保留连接线。

apiVersion: lmcache.lmcache.ai/v1alpha1
kind: LMCacheEngine
metadata:
  name: my-cache-versioned
spec:
  l1:
    sizeGB: 60
  injection:
    payloadImage:
      repository: <registry>/lmcache-payload
      tag: latest
      pullPolicy: Always          # :latest moves -- re-pull for the current build
    # imagePullSecrets:            # private payload registry only
    #   - name: my-registry-secret

绑定到此引擎的选择性 Pod(如上所述的标签 + 注释)无需更改——Webhook 会自动处理有效负载。可应用的示例:config/samples/lmcache_v1alpha1_lmcacheengine_injection.yamlconfig/samples/vllm_lmcache_injection_deployment.yaml

备注

有效负载的 lmcache 必须与导入它的 vLLM 镜像 **ABI 兼容**(相同的 Python 次版本和兼容的 torch)——它包含编译的扩展。如果它们不一致,import lmcache 在 vLLM pod 中会因 undefined symbol 错误而失败。从与您的 vLLM 镜像接近的 lmcache 镜像构建有效负载可以保持它们的兼容性。

3. 验证正在运行的 pod 上的交换 -- 将正常导入与忽略注入的 PYTHONPATH 的导入进行对比:

POD=$(kubectl get pod -l app=vllm-lmcache-versioned -o name | head -1)

# imports the STAGED build (from /lmcache-payload):
kubectl exec $POD -c vllm -- python3 -c \
  "import lmcache; print(lmcache.__version__, lmcache.__file__)"

# PYTHONPATH stripped -> the image's baked-in build (site-packages):
kubectl exec $POD -c vllm -- env -u PYTHONPATH python3 -c \
  "import lmcache; print(lmcache.__version__, lmcache.__file__)"

两个不同来源的相同模块确认了交换。如果没有任何内容被预先准备,请检查 lmcache.ai/lmcache-skip-reason 在 pod 上的内容。

验证部署#

# Check LMCacheEngine status
kubectl get lmc

预期输出:

NAME       PHASE     READY   DESIRED   AGE
my-cache   Running   3       3         5m
# Check the connection ConfigMap
kubectl get configmap my-cache-connection -o yaml

# Check LMCache pods
kubectl get pods -l app.kubernetes.io/managed-by=lmcache-operator

# Check detailed status with endpoints
kubectl describe lmc my-cache

CRD 规格参考#

镜像#

字段

默认

描述

image.repository

lmcache/vllm-openai

容器镜像仓库。

image.tag

latest

容器镜像标签。

image.pullPolicy

IfNotPresent

Always, Never, 或 IfNotPresent

imagePullSecrets

--

镜像拉取密钥引用。

服务器#

字段

默认

描述

server.port

5555

ZMQ 监听端口 (1024--65535)。

server.chunkSize

256

Token 分块大小。

server.maxWorkers

1

ZMQ 请求的工作线程。

server.hashAlgorithm

blake3

builtin, sha256_cbor, 或 blake3

server.httpPort

8080

健康检查和缓存管理的 HTTP 前端端口(1024--65535)。

L1 缓存#

字段

默认

描述

l1.sizeGB

必需

L1 缓存大小(以 GB 为单位)。必须大于 0。

逐出#

字段

默认

描述

eviction.policy

LRU

LRUnoop。在仅缓冲模式下,使用 noopl2Backend.storePolicy: skip_l1

eviction.triggerWatermark

0.8

触发逐出的使用比例 (0.0--1.0]。

eviction.evictionRatio

0.2

逐出比例 (0.0--1.0]。

Prometheus#

字段

默认

描述

prometheus.enabled

true

对外暴露 Prometheus 指标。

prometheus.port

9090

/metrics 端点端口。

prometheus.serviceMonitor.enabled

false

创建一个 ServiceMonitor CR。

prometheus.serviceMonitor.interval

30s

抓取间隔。

prometheus.serviceMonitor.labels

--

ServiceMonitor 上的附加标签。

L2 存储#

字段

默认

描述

l2Backend

--

L2 后端列表 (type + config)。请参阅 二级 KV 存储

GPU 和安全性#

字段

默认

描述

gpuVendor

nvidia

GPU 供应商:nvidia``(使用 ``nvidia RuntimeClass)或 ``amd``(在默认运行时上运行)。

privileged

false

在特权模式下运行引擎容器。在大多数集群中,runtimeClassName: nvidia + NVIDIA_VISIBLE_DEVICES=all 已经可以在没有它的情况下授予 GPU 可见性;仅在引擎无法看到 GPU 的情况下设置为 true。对于 gpuVendor: amd 是必需的(没有 RuntimeClass 设备注入,因此特权是访问 /dev/kfd//dev/dri 的唯一途径)。启用它需要命名空间允许 privileged Pod 安全标准。

调度#

字段

默认

描述

nodeSelector

GPU 节点

默认为 nvidia.com/gpu.present: \"true\"

affinity

--

Pod 亲和性规则。

tolerations

--

Pod 容忍度规则。

priorityClassName

--

用于 Pods 的优先级类。

覆盖与额外选项#

字段

默认

描述

logLevel

INFO

DEBUG, INFO, WARNING, ERROR

resourceOverrides

--

覆盖自动计算的资源。

env

--

额外的环境变量。

volumes

--

额外的卷。

volumeMounts

--

额外的卷挂载。

podAnnotations

--

额外的 Pod 注解。

podLabels

--

额外的 Pod 标签。

serviceAccountName

--

Pod 使用的 ServiceAccount。

extraArgs

--

额外的 CLI 标志(最后附加,可以覆盖)。

自动计算资源#

spec.resourceOverrides 未设置时,操作符从 l1.sizeGB 派生资源:

  • CPU 请求: 4 核心

  • 内存请求: ceil(l1.sizeGB + 5) Gi

  • 内存限制: ceil(memoryRequest * 1.5) Gi

例如,l1.sizeGB: 60 会产生 65 Gi 的请求和 98 Gi 的限制。

自动注入的 Pod 设置#

操作符始终将这些注入到 Pod 规格中(它们无法通过 CRD 配置):

  • hostIPC: true -- 这是在 LMCache 和 vLLM 之间进行 CUDA IPC 所必需的。

  • --host 0.0.0.0 -- 将服务器绑定到所有接口,以便节点本地服务可以路由到它。

  • NVIDIA_VISIBLE_DEVICES=all -- 确保 GPU 可用于基于 IPC 的内存传输。

  • NVIDIA_DRIVER_CAPABILITIES=all -- 将所有驱动程序功能(计算、实用程序等)暴露给容器。

  • TCP socket 探测 -- 启动(初始 5 秒,30 次失败)、存活(10 秒)和就绪(5 秒)探测在服务器端口上。

备注

操作符/dev/shm 挂载 emptyDir。使用 hostIPC: true 时,容器直接访问主机的 /dev/shm。挂载 emptyDir 会用私有 tmpfs 进行遮蔽,从而破坏 CUDA IPC。

创建的资源#

对于名为 my-cacheLMCacheEngine

资源

名称

目的

DaemonSet

my-cache

运行 LMCache 服务器 Pod。

服务 (ClusterIP)

my-cache

节点本地发现(internalTrafficPolicy=Local)。

无头服务

my-cache-metrics

Prometheus 抓取目标。

ConfigMap

my-cache-connection

供 vLLM 使用的 kv-transfer-config JSON。

ServiceMonitor

my-cache

启用后由 Prometheus Operator 集成使用。

连接 ConfigMap 包含:

{
  "kv_connector": "LMCacheMPConnector",
  "kv_role": "kv_both",
  "kv_connector_extra_config": {
    "lmcache.mp.host": "tcp://my-cache.default.svc.cluster.local",
    "lmcache.mp.port": "5555"
  }
}

状态与条件#

kubectl describe lmc my-cache

状态部分包括:

  • phase: PendingRunningDegradedFailed

  • readyInstances / desiredInstances: 实例计数。

  • endpoints: 每个节点的连接信息(节点名称、主机 IP、Pod 名称、端口、就绪状态)。

  • 条件

    • Available -- 至少有一个实例已就绪。

    • AllInstancesReady -- 所有预期实例均已就绪。

    • ConfigValid -- Spec 验证通过。

验证规则#

操作符在 apply 时验证 CR 的 Spec:

字段

规则

l1.sizeGB

必需,必须 > 0。

eviction.policy

必须是 LRU``noop``(如果设置)。

eviction.triggerWatermark

必须在 (0.0, 1.0] 之间。

eviction.evictionRatio

必须在 (0.0, 1.0] 之间。

server.port

必须在 [1024, 65535] 之间。

示例#

仅针对 GPU 节点#

使用 nodeSelector 将 LMCache 限定在 GPU 节点上运行。新加入的 GPU 节点会自动获得一个 LMCache Pod:

apiVersion: lmcache.lmcache.ai/v1alpha1
kind: LMCacheEngine
metadata:
  name: my-cache
spec:
  nodeSelector:
    nvidia.com/gpu.present: "true"
  l1:
    sizeGB: 60

备注

当未指定时,操作符默认将 nodeSelector 设置为 nvidia.com/gpu.present: \"true\",因此最小化的 CR 默认已针对 GPU 节点。

自定义服务器端口#

如果默认端口(5555)与其他服务冲突:

apiVersion: lmcache.lmcache.ai/v1alpha1
kind: LMCacheEngine
metadata:
  name: my-cache
spec:
  server:
    port: 6555
  l1:
    sizeGB: 60

连接 ConfigMap 会自动更新 —— vLLM Pod 重启后即可使用新端口。

集成 Prometheus 监控的生产环境配置#

apiVersion: lmcache.lmcache.ai/v1alpha1
kind: LMCacheEngine
metadata:
  name: production-cache
  namespace: llm-serving
spec:
  nodeSelector:
    nvidia.com/gpu.present: "true"
  image:
    repository: lmcache/standalone
    tag: v0.1.0
  server:
    port: 6555
    chunkSize: 256
    maxWorkers: 4
  l1:
    sizeGB: 60
  eviction:
    triggerWatermark: 0.8
    evictionRatio: 0.2
  prometheus:
    enabled: true
    port: 9090
    serviceMonitor:
      enabled: true
      labels:
        release: kube-prometheus-stack
  podAnnotations:
    prometheus.io/scrape: "true"
    prometheus.io/port: "9090"
  priorityClassName: system-node-critical

请参阅 可观察性 以获取指标名称和 Grafana 配置。

覆盖自动计算的资源#

apiVersion: lmcache.lmcache.ai/v1alpha1
kind: LMCacheEngine
metadata:
  name: my-cache
spec:
  l1:
    sizeGB: 60
  resourceOverrides:
    requests:
      memory: "70Gi"
      cpu: "8"
    limits:
      memory: "100Gi"

CacheBlend#

CacheBlend 通过重新计算一小部分 Token 来复用偏移(非前缀)位置的缓存 KV。该操作符将其作为第二个 CRD CacheBlendEngine 进行管理,并通过一个 变更准入 Webhook 将纯 Python 的 lmcache-cacheblend vLLM 插件注入到您的服务 Pod 中,因此您 无需 重新构建 vLLM 镜像。有关该技术的详细信息,请参见 混合

它由两个部分组成,操作符同时管理它们:

  • 一个驻留在 GPU 上的 CacheBlend V3 引擎 (lmcache server --engine-type blend),作为 DaemonSet 部署, LMCacheEngine 相同的 GPU 型号 (runtimeClassName: nvidia + NVIDIA_VISIBLE_DEVICES=all + hostIPC,当设置了 spec.privileged 时加上 privileged,并且**没有** nvidia.com/gpu 声明),以便共享同设备的 CUDA IPC 的 vLLM GPU;并且

  • vLLM 侧插件,由 Webhook 注入到已选择启用的 Pod 中。

附加先决条件#

除上述操作符前提条件外,还需满足:

  • cert-manager -- webhook 的服务证书由 cert-manager Issuer + Certificate 颁发。在 make deploy 之前安装它:

    kubectl apply -f https://github.com/cert-manager/cert-manager/releases/latest/download/cert-manager.yaml
    kubectl -n cert-manager wait --for=condition=Available deploy --all --timeout=180s
    
  • 使用 Webhook 部署 -- 使用 make deploy(而不是 make run,后者仅为控制器并通过 ENABLE_WEBHOOKS=false 禁用 Webhook)。

  • Pod 安全标准 -- webhook 注入 hostIPC/privileged,而 baseline/restricted 配置文件会拒绝这些,因此将引擎和 vLLM pod 的命名空间标记为 pod-security.kubernetes.io/enforce=privileged

部署 CacheBlendEngine#

apiVersion: lmcache.lmcache.ai/v1alpha1
kind: CacheBlendEngine
metadata:
  name: my-cacheblend
spec:
  l1:
    sizeGB: 60
  injection:
    # The (private) cacheblend-plugin init-container image -- repository/tag/
    # pullPolicy, like spec.image.  Set repository to YOUR image; the
    # inherited engine-image default is not a valid payload.
    payloadImage:
      repository: <registry>/cacheblend-plugin
      tag: <tag>
    # Appended to the vLLM pod so the private payload image can pull; the
    # Secret must exist in the vLLM pod's namespace.
    imagePullSecrets:
      - name: my-registry-secret

该引擎以 DaemonSet 方式运行 lmcache server --engine-type blend,并生成一个包含 CBKVConnector kv-transfer-configmy-cacheblend-connection ConfigMap(操作符将节点本地服务的主机/端口和 cb.* 可调参数连接起来)。

为 vLLM Pod 启用注入#

为 Pod 模板打上 webhook 所需的标签,并按名称将其绑定到引擎。通过镜像 ENTRYPOINT 启动 vLLM(仅传参数)——应跳过 command: [\"/bin/sh\", \"-c\", ...] 包装器,否则附加的参数无法传递给 vllm serve

apiVersion: apps/v1
kind: Deployment
metadata:
  name: vllm-cacheblend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: vllm-cacheblend
  template:
    metadata:
      labels:
        app: vllm-cacheblend
        lmcache.ai/cacheblend-inject: "true"          # opt-in (webhook objectSelector)
      annotations:
        lmcache.ai/cacheblend-engine: "my-cacheblend" # bind to the engine
    spec:
      runtimeClassName: nvidia
      containers:
        - name: vllm
          image: lmcache/vllm-openai:<pinned-tag>
          args: ["<your-model>", "--port", "8000", "--gpu-memory-utilization", "0.8"]
          resources:
            limits:
              nvidia.com/gpu: "1"

Webhook 注入插件初始化容器、PYTHONPATHhostIPC、私有镜像拉取密钥,以及所需的 CacheBlend vLLM 标志(--attention-backend CUSTOM--kv-transfer-config 来自引擎的连接 ConfigMap、--block-size 64--pipeline-parallel-size 1--no-enable-chunked-prefill--no-async-scheduling--enforce-eager)。您只需提供模型和非 CacheBlend 标志。

验证注入#

该 Webhook 变更的是 Pod,而非 Deployment,因此请检查 Pod:

kubectl get pod -l app=vllm-cacheblend -o yaml | \
  grep -E "initContainers|cb-plugin|PYTHONPATH|attention-backend|cacheblend-injected|skip-reason"

若未注入任何内容,请检查 Pod 的 lmcache.ai/cacheblend-skip-reason 注解:command-override(使用了 sh -c 包装器)、kv-transfer-config-present(已自行设置了该配置)、engine-not-found(缺少 <name>-connection ConfigMap)、payload-image-unset(引擎的 injection.payloadImage 未设置仓库),或 target-container-not-found(所请求的 targetContainer / cacheblend-container 注解指向了 Pod 中不存在的容器)。在 failurePolicy: Ignore 的情况下,Webhook 或证书问题也会使 Pod 静默地保持未变更 —— 请确认操作符 Pod 处于 Running 状态,且 MutatingWebhookConfiguration 已存在。

CacheBlendEngine 字段#

CacheBlendEngineSpec 包含 LMCacheEngineSpec 的全部字段(见上方 CRD Spec 参考),并新增了:

字段

默认

描述

blend.checkLayer

1

计算 Token 重要性评分所在的层(cb.check_layer)。

blend.recompRatio

0.15

非前缀命中 Token 被重新计算的比例(cb.recomp_ratio)。

injection.payloadImage

必需

(私有)cacheblend-plugin 初始化容器镜像(repository / tag / pullPolicy)。必须设置 repository——继承自引擎镜像的默认值并非有效的负载镜像。

injection.imagePullSecrets

--

追加到 vLLM Pod 的私有负载镜像拉取密钥。

injection.targetContainer

第一个容器

要注入的 vLLM 容器的名称。

injection.cudagraph

eager

eager | piecewise | full_decode_only(不可使用 full)。

server.chunkSize 的默认值为 256,并且必须等于 256(混合匹配器要求 chunk_size == vLLM --block-size * 4)。

LMCacheCoordinator#

LMCacheCoordinator CRD 运行 mp coordinator -- 一个跨集群的 HTTP 服务,跟踪 mp 服务器实例,逐出心跳超时的实例,执行 L2 配额逐出,并托管全局 CacheBlend 指纹目录。它是一个普通的 (非 GPU) Deployment,通过 ClusterIP 服务暴露;引擎通过 coordinator.refcoordinator.url 访问它。

部署协调器#

一个可以编辑的清单位于操作员仓库中的 config/samples/lmcache_v1alpha1_lmcachecoordinator.yaml。一个最小的协调器:

apiVersion: lmcache.lmcache.ai/v1alpha1
kind: LMCacheCoordinator
metadata:
  name: my-coordinator
spec:
  port: 9300
kubectl get lmcc my-coordinator   # shortName: lmcc

连接引擎#

通过其 coordinator 块将 LMCacheEngine / CacheBlendEngine 指向协调器。使用 ref 在同一命名空间中命名协调器(操作符将其解析为集群内服务 URL),或使用 url 指定明确的端点:

spec:
  coordinator:
    ref:
      name: my-coordinator       # or: url: http://my-coordinator.default.svc:9300
    heartbeatInterval: 5          # seconds; must be > 0
    l2EventReporting: false       # report L2 store/lookup events for fleet eviction

协调器 CRD 规格参考#

拓扑#

字段

默认

描述

replicas

1

协调器 Pod。注册表是每个进程的内存中,因此大于 1 仅在共享持久后端后面才有意义。必须大于或等于 0。

image.repository / image.tag / image.pullPolicy

共享引擎镜像

运行与引擎相同的 lmcache 二进制文件。

imagePullSecrets

--

镜像拉取密钥引用。

HTTP 服务器#

字段

默认

描述

host

0.0.0.0

协调器的 HTTP 服务器绑定的地址。

port

9300

HTTP 端口 (1--65535)。

成员资格与健康#

字段

默认

描述

instanceTimeout

30

在没有心跳的情况下,经过的秒数后,实例将被逐出。设置应高于引擎的 coordinator.heartbeatInterval

healthCheckInterval

10

健康检查扫描之间的秒数;0 禁用循环。

L2 配额逐出#

字段

默认

描述

evictionCheckInterval

5

L2 逐出清扫之间的秒数;0 禁用循环。

evictionRatio

0.2

每个周期逐出的跟踪键的比例(按数量计算),范围为 [0.0, 1.0]。

triggerWatermark

1.0

触发逐出的配额使用比例,(0.0, 1.0]。

全局 CacheBlend 目录#

字段

默认

描述

blendChunkSize

256

全局 CacheBlend 目录中每个块的令牌数(匹配单位)。必须等于 混合服务器使用的 LMCache 块大小。必须大于 0。

blendProbeStride

1

在匹配探针之间的位置。1 在每个偏移量处探测以获得完整的召回;提高它以在召回和协调器 CPU 之间进行权衡。必须大于 0。

Prometheus、调度与覆盖#

字段

默认

描述

prometheus.enabled

true

暴露指标容器端口。请参见下面的说明。

prometheus.port

9090

指标端口。

prometheus.serviceMonitor.enabled

false

创建一个 ServiceMonitor CR(和无头指标服务)。

prometheus.serviceMonitor.interval

30s

抓取间隔。

logLevel

INFO

DEBUG | INFO | WARNING | ERROR.

resourceOverrides

--

Pod 资源请求/限制(无自动计算;协调器轻量级 CPU/内存)。

nodeSelector / affinity / tolerations / priorityClassName

--

Pod 调度控制。

env / volumes / volumeMounts / podAnnotations / podLabels / serviceAccountName

--

标准的 Pod 形状字段。

extraArgs

--

额外的 CLI 标志(最后附加,可以覆盖任何自动生成的标志)。

备注

协调器进程尚未暴露/metrics端点。虽然存在Prometheus的连接,但只有在添加指标后才有用;serviceMonitor.enabled默认为false

创建协调器资源#

对于名为 my-coordinatorLMCacheCoordinator

资源

名称

目的

部署

my-coordinator

运行协调器 HTTP 服务器 Pod。

服务 (ClusterIP)

my-coordinator

在 HTTP 端口上进行全舰队发现。

无头服务

my-coordinator-metrics

serviceMonitor.enabled 时的 Prometheus 抓取目标。

ServiceMonitor

my-coordinator

Prometheus Operator 集成(当 serviceMonitor.enabled 时)。

其他组件用来访问协调器的状态 endpointhttp://<name>.<namespace>.svc:<port>(例如 http://my-coordinator.default.svc:9300)。

协调器状态与条件#

状态部分包括:

  • phase: PendingRunningDegradedFailed

  • 副本 / 就绪副本: 来自部署的 Pod 数量。

  • endpoint: 集群内用于访问协调器的 URL。

  • observedGeneration: 最近一次已调和的版本。

  • 条件

    • Available -- 至少一个副本已准备好。

    • 所有实例已准备好 -- 所有期望的实例均已准备好。

    • ConfigValid -- Spec 验证通过。

协调器验证规则#

字段

规则

port

必须在 [1, 65535] 之间。

replicas

必须 >= 0。

instanceTimeout

必须 > 0。

healthCheckInterval / evictionCheckInterval

必须 >= 0。

evictionRatio

必须在 [0.0, 1.0] 之间。

triggerWatermark

必须在 (0.0, 1.0] 之间。

blendChunkSize / blendProbeStride

必须 > 0。

Operator 与手动部署对比#

对比项

手动 DaemonSet

LMCacheEngine Operator

hostIPC

必须手动设置

自动注入

--host 0.0.0.0

必须手动设置

自动注入

服务发现

hostNetwork + status.hostIP

节点本地 ClusterIP 服务 + ConfigMap

vLLM 配置

将 JSON 复制到部署中

挂载 <name>-connection ConfigMap

资源大小调整

手动计算

l1.sizeGB 自动计算

Prometheus

手动 ServiceMonitor

serviceMonitor.enabled: true

验证

仅限运行时错误

kubectl apply 拒绝无效的规格

新的 GPU 节点

DaemonSet 处理它

DaemonSet 处理它(相同)

安全注意事项#

hostIPC 将主机的 IPC 命名空间(System V IPC,POSIX 消息队列)暴露给容器。容器中的任何进程都可以与同一主机上其他进程的 IPC 资源进行交互。

  • 仅在受信任的环境中部署。

  • 使用 Pod 安全标准的集群必须为 LMCache 命名空间开启 privileged 配置文件——baselinerestricted 配置文件均会拒绝 hostIPC

  • spec.privileged 默认为 false。启用后(对于 gpuVendor: amd 是必需的),引擎容器将以特权模式运行,授予其完全的设备访问权限——仅在 GPU 可见性需要时启用。

开发#

make generate     # Generate DeepCopy methods
make manifests    # Generate CRD YAML + RBAC
make build        # Compile operator binary
make fmt          # go fmt
make vet          # go vet
make test         # Run unit tests
make lint         # Run golangci-lint

推送自定义 Operator 镜像:

# Docker Hub
make docker-build docker-push IMG=docker.io/<your-user>/lmcache-operator:latest
make deploy IMG=docker.io/<your-user>/lmcache-operator:latest

# Multi-platform (amd64 + arm64)
make docker-buildx IMG=<your-registry>/lmcache-operator:latest

如果您的集群需要拉取凭据:

kubectl create secret docker-registry regcred \
  --docker-server=<your-registry> \
  --docker-username=<username> \
  --docker-password=<password> \
  -n lmcache-operator-system