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,操作符会创建一个ServiceMonitorCR,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-configJSON。自动计算 L1 缓存大小的资源请求/限制
默认将
nodeSelector设置为nvidia.com/gpu.present: \"true\"
备注
该操作符将容器镜像默认设置为 lmcache/vllm-openai:latest。可以通过 spec.image.repository 和 spec.image.tag 来覆盖,以固定特定版本。
连接 vLLM#
操作符创建一个名为 <engine-name>-connection 的 ConfigMap,其中包含 kv-transfer-config JSON。将其挂载到您的 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处理路由。
验证部署#
# 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 规格参考#
镜像#
字段 |
默认 |
描述 |
|---|---|---|
|
|
容器镜像仓库。 |
|
|
容器镜像标签。 |
|
|
|
|
-- |
镜像拉取密钥引用。 |
服务器#
字段 |
默认 |
描述 |
|---|---|---|
|
|
ZMQ 监听端口 (1024--65535)。 |
|
|
Token 分块大小。 |
|
|
ZMQ 请求的工作线程。 |
|
|
|
L1 缓存#
字段 |
默认 |
描述 |
|---|---|---|
|
必需 |
L1 缓存大小(以 GB 为单位)。必须大于 0。 |
逐出#
字段 |
默认 |
描述 |
|---|---|---|
|
|
仅支持 |
|
|
触发逐出的使用比例 (0.0--1.0]。 |
|
|
逐出比例 (0.0--1.0]。 |
Prometheus#
字段 |
默认 |
描述 |
|---|---|---|
|
|
对外暴露 Prometheus 指标。 |
|
|
|
|
|
创建一个 ServiceMonitor CR。 |
|
|
抓取间隔。 |
|
-- |
ServiceMonitor 上的附加标签。 |
L2 存储#
字段 |
默认 |
描述 |
|---|---|---|
|
-- |
L2 后端列表 ( |
调度#
字段 |
默认 |
描述 |
|---|---|---|
|
GPU 节点 |
默认为 |
|
-- |
Pod 亲和性规则。 |
|
-- |
Pod 容忍度规则。 |
|
-- |
用于 Pods 的优先级类。 |
覆盖与额外选项#
字段 |
默认 |
描述 |
|---|---|---|
|
|
|
|
-- |
覆盖自动计算的资源。 |
|
-- |
额外的环境变量。 |
|
-- |
额外的卷。 |
|
-- |
额外的卷挂载。 |
|
-- |
额外的 Pod 注解。 |
|
-- |
额外的 Pod 标签。 |
|
-- |
Pod 使用的 ServiceAccount。 |
|
-- |
额外的 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 的内存传输。
TCP socket 探测 -- 启动(初始 5 秒,30 次失败)、存活(10 秒)和就绪(5 秒)探测在服务器端口上。
备注
操作符不在 /dev/shm 挂载 emptyDir。使用 hostIPC: true 时,容器直接访问主机的 /dev/shm。挂载 emptyDir 会用私有 tmpfs 进行遮蔽,从而破坏 CUDA IPC。
创建的资源#
对于名为 my-cache 的 LMCacheEngine:
资源 |
名称 |
目的 |
|---|---|---|
DaemonSet |
|
运行 LMCache 服务器 Pod。 |
服务 (ClusterIP) |
|
节点本地发现( |
无头服务 |
|
Prometheus 抓取目标。 |
ConfigMap |
|
供 vLLM 使用的 |
ServiceMonitor |
|
启用后由 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:
Pending、Running、Degraded或Failed。readyInstances / desiredInstances: 实例计数。
endpoints: 每个节点的连接信息(节点名称、主机 IP、Pod 名称、端口、就绪状态)。
条件:
Available-- 至少有一个实例已就绪。AllInstancesReady-- 所有预期实例均已就绪。ConfigValid-- Spec 验证通过。
验证规则#
操作符在 apply 时验证 CR 的 Spec:
字段 |
规则 |
|---|---|
|
必需,必须 > 0。 |
|
必须是 |
|
必须在 (0.0, 1.0] 之间。 |
|
必须在 (0.0, 1.0] 之间。 |
|
必须在 [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 镜像。有关该技术的详细信息,请参见 混合。
它由两个部分组成,操作符同时管理它们:
a GPU-resident CacheBlend V3 engine (
lmcache server --engine-type blend), deployed as a DaemonSet with the same GPU model asLMCacheEngine(privileged+runtimeClassName: nvidia+NVIDIA_VISIBLE_DEVICES=all+hostIPC, and nonvidia.com/gpuclaim) so it shares the vLLM GPU for same-device CUDA IPC; andvLLM 侧插件,由 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-config 的 my-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 注入插件初始化容器、PYTHONPATH、hostIPC、私有镜像拉取密钥,以及所需的 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 参考),并新增了:
字段 |
默认 |
描述 |
|---|---|---|
|
|
计算 Token 重要性评分所在的层( |
|
|
非前缀命中 Token 被重新计算的比例( |
|
必需 |
(私有)cacheblend-plugin 初始化容器镜像( |
|
-- |
追加到 vLLM Pod 的私有负载镜像拉取密钥。 |
|
第一个容器 |
要注入的 vLLM 容器的名称。 |
|
|
|
server.chunkSize 的默认值为 256,并且必须等于 256(混合匹配器要求 chunk_size == vLLM --block-size * 4)。
LMCacheCoordinator#
The LMCacheCoordinator CRD runs the mp coordinator -- a fleet-wide HTTP
service that tracks mp server instances, evicts those whose heartbeats lapse,
performs L2 quota eviction, and hosts the global CacheBlend fingerprint
directory. It is a plain (non-GPU) Deployment exposed through a ClusterIP
Service; engines reach it via coordinator.ref or coordinator.url.
Deploying a Coordinator#
A ready-to-edit manifest lives at
config/samples/lmcache_v1alpha1_lmcachecoordinator.yaml in the operator
repo. A minimal coordinator:
apiVersion: lmcache.lmcache.ai/v1alpha1
kind: LMCacheCoordinator
metadata:
name: my-coordinator
spec:
port: 9300
kubectl get lmcc my-coordinator # shortName: lmcc
Connecting an Engine#
Point an LMCacheEngine / CacheBlendEngine at the coordinator through its
coordinator block. Use ref to name a coordinator in the same namespace
(the operator resolves it to the in-cluster Service URL), or url for an
explicit endpoint:
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
Coordinator CRD Spec Reference#
Topology#
字段 |
默认 |
描述 |
|---|---|---|
|
|
Coordinator pods. The registry is per-process in-memory, so >1 only makes sense behind a shared durable backend. Must be >= 0. |
|
shared engine image |
Runs the same lmcache binary as the engines. |
|
-- |
镜像拉取密钥引用。 |
HTTP Server#
字段 |
默认 |
描述 |
|---|---|---|
|
|
Address the coordinator's HTTP server binds to. |
|
|
HTTP port (1--65535). |
Membership & Health#
字段 |
默认 |
描述 |
|---|---|---|
|
|
Seconds without a heartbeat after which an instance is evicted. Set
comfortably above the engines' |
|
|
Seconds between health-check sweeps; |
L2 Quota Eviction#
字段 |
默认 |
描述 |
|---|---|---|
|
|
Seconds between L2 eviction sweeps; |
|
|
Fraction of tracked keys (by count) to evict per cycle, [0.0, 1.0]. |
|
|
Usage fraction of the quota that fires eviction, (0.0, 1.0]. |
Global CacheBlend Directory#
字段 |
默认 |
描述 |
|---|---|---|
|
|
Tokens per chunk for the global CacheBlend directory (the match unit). Must equal the LMCache chunk size the blend servers use. Must be > 0. |
|
|
Positions between match probes. |
Prometheus, Scheduling & Overrides#
字段 |
默认 |
描述 |
|---|---|---|
|
|
Expose the metrics container port. See the note below. |
|
|
Metrics port. |
|
|
Create a ServiceMonitor CR (and headless metrics Service). |
|
|
抓取间隔。 |
|
|
|
|
-- |
Pod resource requests/limits (no auto-compute; the coordinator is CPU/memory light). |
|
-- |
Pod scheduling controls. |
|
-- |
Standard pod-shaping fields. |
|
-- |
Extra CLI flags (appended last, can override any auto-generated flag). |
备注
The coordinator process does not yet expose a /metrics endpoint. The
Prometheus wiring is present for parity but is only useful once metrics are
added; serviceMonitor.enabled defaults to false.
Coordinator Resources Created#
For an LMCacheCoordinator named my-coordinator:
资源 |
名称 |
目的 |
|---|---|---|
Deployment |
|
Runs the coordinator HTTP server pods. |
服务 (ClusterIP) |
|
Fleet-wide discovery on the HTTP port. |
无头服务 |
|
Prometheus scrape target (when |
ServiceMonitor |
|
Prometheus Operator integration (when |
The status endpoint other components use to reach the coordinator is
http://<name>.<namespace>.svc:<port> (e.g.
http://my-coordinator.default.svc:9300).
Coordinator Status & Conditions#
状态部分包括:
phase:
Pending、Running、Degraded或Failed。replicas / readyReplicas: Pod counts from the Deployment.
endpoint: In-cluster URL for reaching the coordinator.
observedGeneration: Most recent reconciled generation.
条件:
Available-- At least one replica is ready.AllInstancesReady-- All desired replicas are ready.ConfigValid-- Spec 验证通过。
Coordinator Validation Rules#
字段 |
规则 |
|---|---|
|
Must be in [1, 65535]. |
|
Must be >= 0. |
|
Must be > 0. |
|
Must be >= 0. |
|
Must be in [0.0, 1.0]. |
|
必须在 (0.0, 1.0] 之间。 |
|
Must be > 0. |
Operator 与手动部署对比#
对比项 |
手动 DaemonSet |
LMCacheEngine Operator |
|---|---|---|
hostIPC |
必须手动设置 |
自动注入 |
|
必须手动设置 |
自动注入 |
服务发现 |
|
节点本地 ClusterIP 服务 + ConfigMap |
vLLM 配置 |
将 JSON 复制到部署中 |
挂载 |
资源大小调整 |
手动计算 |
从 |
Prometheus |
手动 ServiceMonitor |
|
验证 |
仅限运行时错误 |
|
新的 GPU 节点 |
DaemonSet 处理它 |
DaemonSet 处理它(相同) |
安全注意事项#
hostIPC 将主机的 IPC 命名空间(System V IPC,POSIX 消息队列)暴露给容器。容器中的任何进程都可以与同一主机上其他进程的 IPC 资源进行交互。
仅在受信任的环境中部署。
使用 Pod 安全标准的集群必须为 LMCache 命名空间开启
privileged配置文件——baseline和restricted配置文件均会拒绝hostIPC。
开发#
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