Lora 动态加载#

LoRA 模型适配器支持对于提高大型语言模型 (LLM) 的模型密度和降低推理成本至关重要。通过实现 LoRA 适配器的动态加载和卸载,它允许在共享基础设施上更高效地部署多个模型。

这通过在不同任务中重用基础模型,同时为特定模型调整轻量级 LoRA 适配器来减少资源消耗。该方法优化了 GPU 内存使用,缩短了冷启动时间,并增强了可扩展性,使其成为生产环境中高密度部署和经济高效推理的理想选择。

高层设计#

模型适配器控制器#

我们开发了一个 ModelAdapter 控制器来管理 lora 模型适配器的生命周期。用户可以提交一个 lora 自定义资源,控制器将注册到匹配的 pod,配置服务发现并暴露适配器状态。

lora-controller-workflow

ModelAdapter 生命周期和阶段转换#

ModelAdapter 在其生命周期中会经历几个不同的阶段。了解这些阶段有助于用户监控和排查其 LoRA 部署的问题。

阶段转换流程

Pending → Scheduled → Loading → Bound → Running
   ↓         ↓         ↓        ↓        ↓
Starting  Pod      Adapter   Service   Ready for
reconcile Selected  Loading   Created   Inference

阶段详情

  1. Pending:ModelAdapter 首次创建时的初始状态。控制器开始协调并验证配置。

  2. Scheduled:控制器已成功识别并选择了符合 podSelector 标准的合适 pod。在选择之前,会验证 pod 的就绪性和稳定性。

  3. Loading:控制器正在积极地将 LoRA 适配器加载到选定的 pod 上。这包括:

    • 从指定的 artifactURL 下载适配器

    • 向 vLLM 引擎注册适配器

    • 如果加载失败,处理带指数退避的重试机制

  4. Bound:LoRA 适配器已成功加载到 pod 上,控制器正在为服务发现创建关联的 Kubernetes Service 和 EndpointSlice 资源。

  5. Running:ModelAdapter 完全运行并准备好服务推理请求。LoRA 模型可以通过网关使用适配器名称进行访问。

错误处理和可靠性功能

  • 重试机制:每个 pod 最多重试 5 次,带指数退避(从 5 秒开始)

  • Pod 切换:如果在初始 pod 上加载失败,自动选择替代 pod

  • Pod 健康验证:在调度适配器之前,确保 pod 处于就绪和稳定状态

  • 连接错误处理:优雅处理常见的启动错误,例如“连接被拒绝”

监控阶段转换

您可以使用以下方式监控当前阶段和详细状态:

kubectl describe modeladapter <adapter-name>

状态部分将显示当前阶段和转换历史记录,以及每个状态更改的时间戳和原因。

模型适配器服务发现#

我们的目标是重用 Kubernetes Service 作为每个 lora 模型的抽象层。传统上,单个 pod 属于一个服务。然而,对于 LoRA 场景,一个 pod 中有多个 lora 适配器,这打破了 Kubernetes 的原生设计。为了以 Kubernetes 原生方式支持 lora 案例,我们自定义了 lora 端点,并允许一个带有不同 LoRA 的单个 pod 属于多个服务。

vLLM 引擎更改#

高密度 Lora 支持不能仅仅在控制平面侧完成,我们还撰写了一份 RFC,关于改进 LoRA 元数据可见性动态加载和卸载远程注册表支持可观测性,以增强生产级服务的 LoRA 管理。请查看 [RFC]: Enhancing LoRA Management for Production Environments in vLLM 了解更多详情。大部分更改已在 vLLM 中完成,我们只需使用最新的 vLLM 镜像即可投入生产。

示例#

这是一个如何创建 lora 适配器的示例。

先决条件#

  1. 您在同一命名空间中部署了一个基础模型。

  2. vLLM 引擎需要启用 VLLM_ALLOW_RUNTIME_LORA_UPDATING 功能标志。

  3. 您有一个托管在 Huggingface 或兼容 S3 存储上的 lora 模型。

创建基础模型#

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    model.aibrix.ai/name: qwen-coder-1-5b-instruct # Note: The label value `model.aibrix.ai/name` here must match with the service name.
    model.aibrix.ai/port: "8000"
    adapter.model.aibrix.ai/enabled: "true" # Required for LoRA adapter support
  name: qwen-coder-1-5b-instruct
  namespace: default
spec:
  # Increase replicas for better adapter reliability and load distribution
  # Allows multiple LoRA adapters to be distributed across pods
  replicas: 3
  selector:
    matchLabels:
      model.aibrix.ai/name: qwen-coder-1-5b-instruct
  template:
    metadata:
      labels:
        model.aibrix.ai/name: qwen-coder-1-5b-instruct
        adapter.model.aibrix.ai/enabled: "true"
    spec:
      containers:
        - command:
            - python3
            - -m
            - vllm.entrypoints.openai.api_server
            - --host
            - "0.0.0.0"
            - --port
            - "8000"
            - --uvicorn-log-level
            - warning
            - --model
            - Qwen/Qwen2.5-Coder-1.5B-Instruct
            - --served-model-name
            # Note: The `--served-model-name` argument value must also match the Service name and the Deployment label `model.aibrix.ai/name`
            - qwen-coder-1-5b-instruct
            - --enable-lora
          image: vllm/vllm-openai:v0.7.1
          imagePullPolicy: Always
          name: vllm-openai
          env:
            # REQUIRED: Enable runtime LoRA updating for ModelAdapter support
            - name: VLLM_ALLOW_RUNTIME_LORA_UPDATING
              value: "True"
            # Optional: Increase timeout for better reliability during adapter loading
            - name: VLLM_LORA_MODULES_LOADING_TIMEOUT
              value: "300"
          ports:
            - containerPort: 8000
              protocol: TCP
          resources:
            limits:
              nvidia.com/gpu: "1"
            requests:
              nvidia.com/gpu: "1"
          # Health checks for better pod reliability
          livenessProbe:
            httpGet:
              path: /health
              port: 8000
            initialDelaySeconds: 60
            periodSeconds: 30
            timeoutSeconds: 10
            failureThreshold: 3
          readinessProbe:
            httpGet:
              path: /health  
              port: 8000
            initialDelaySeconds: 30
            periodSeconds: 10
            timeoutSeconds: 5
            successThreshold: 1
            failureThreshold: 3
        - name: aibrix-runtime
          image: aibrix/runtime:v0.3.0
          command:
            - aibrix_runtime
            - --port
            - "8080"
          env:
            - name: INFERENCE_ENGINE
              value: vllm
            - name: INFERENCE_ENGINE_ENDPOINT
              value: https://:8000
          ports:
            - containerPort: 8080
              protocol: TCP
          livenessProbe:
            httpGet:
              path: /healthz
              port: 8080
            initialDelaySeconds: 3
            periodSeconds: 2
          readinessProbe:
            httpGet:
              path: /ready
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10

---

apiVersion: v1
kind: Service
metadata:
  labels:
    model.aibrix.ai/name: qwen-coder-1-5b-instruct
    prometheus-discovery: "true"
  annotations:
    prometheus.io/scrape: "true"
    prometheus.io/port: "8080"
  name: qwen-coder-1-5b-instruct # Note: The Service name must match the label value `model.aibrix.ai/name` in the Deployment
  namespace: default
spec:
  ports:
    - name: serve
      port: 8000
      protocol: TCP
      targetPort: 8000
    - name: http
      port: 8080
      protocol: TCP
      targetPort: 8080
  selector:
    model.aibrix.ai/name: qwen-coder-1-5b-instruct
  type: ClusterIP
# Expose endpoint
LB_IP=$(kubectl get svc/envoy-aibrix-system-aibrix-eg-903790dc -n envoy-gateway-system -o=jsonpath='{.status.loadBalancer.ingress[0].ip}')
ENDPOINT="${LB_IP}:80"

# send request to base model
curl -v http://${ENDPOINT}/v1/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "qwen-coder-1-5b-instruct",
        "prompt": "San Francisco is a",
        "max_tokens": 128,
        "temperature": 0
    }'

创建 lora 模型适配器#

apiVersion: model.aibrix.ai/v1alpha1
kind: ModelAdapter
metadata:
  name: qwen-code-lora
  namespace: default
  labels:
    model.aibrix.ai/name: "qwen-code-lora"
    model.aibrix.ai/port: "8000"
spec:
  # Base model that this LoRA adapter extends
  baseModel: qwen-coder-1-5b-instruct
  
  # Pod selector to find pods that can host this adapter
  # Pods must have both labels: model.aibrix.ai/name and adapter.model.aibrix.ai/enabled=true
  podSelector:
    matchLabels:
      model.aibrix.ai/name: qwen-coder-1-5b-instruct
      adapter.model.aibrix.ai/enabled: "true"
  
  # URL for the LoRA adapter artifact
  # Supported formats: huggingface://, s3://, or absolute local path
  artifactURL: huggingface://ai-blond/Qwen-Qwen2.5-Coder-1.5B-Instruct-lora
  
  # Replicas controls adapter distribution across pods:
  # - nil (omitted): Load adapter on ALL matching pods (recommended)
  # - 1: Load adapter on a single pod selected by the scheduler
  # Only nil or 1 are supported. Other values will be rejected.
  # replicas: 1
  
  # Optional: Scheduler to use for pod selection (default: "default")
  # Available schedulers: "default", "least-adapters"
  schedulerName: default

  # Lifecycle phases: Pending → Scheduled → Loading → Bound → Running
  # - Pending: Starting reconciliation
  # - Scheduled: Pods selected and validated for readiness
  # - Loading: Adapter being downloaded and loaded (with retry mechanism)
  # - Bound: Successfully loaded, creating service resources
  # - Running: Ready for inference requests

如果您运行 `kubectl describe modeladapter qwen-code-lora,您将看到 lora 适配器状态通过不同阶段进展

阶段 1:Pending

$ kubectl describe modeladapter qwen-code-lora
Status:
  Conditions:
    Last Transition Time:  2025-02-16T19:14:50Z
    Message:               Starting reconciliation
    Reason:                ModelAdapterPending
    Status:                Unknown
    Type:                  Initialized
  Phase:  Pending

阶段 2:Scheduled

$ kubectl describe modeladapter qwen-code-lora
Status:
  Conditions:
    Last Transition Time:  2025-02-16T19:14:50Z
    Message:               Starting reconciliation
    Reason:                ModelAdapterPending
    Status:                Unknown
    Type:                  Initialized
    Last Transition Time:  2025-02-16T19:14:52Z
    Message:               ModelAdapter default/qwen-code-lora has selected 1 pods for scheduling: [qwen-coder-1-5b-instruct-5587f4c57d-kml6s]
    Reason:                Scheduled
    Status:                True
    Type:                  Scheduled
  Phase:  Scheduled

阶段 3-5:Loading → Bound → Running

$ kubectl describe modeladapter qwen-code-lora
Status:
  Conditions:
    Last Transition Time:  2025-02-16T19:14:50Z
    Message:               Starting reconciliation
    Reason:                ModelAdapterPending
    Status:                Unknown
    Type:                  Initialized
    Last Transition Time:  2025-02-16T19:14:52Z
    Message:               ModelAdapter default/qwen-code-lora has selected 1 pods for scheduling: [qwen-coder-1-5b-instruct-5587f4c57d-kml6s]
    Reason:                Scheduled
    Status:                True
    Type:                  Scheduled
    Last Transition Time:  2025-02-16T19:14:55Z
    Message:               ModelAdapter default/qwen-code-lora is ready
    Reason:                ModelAdapterAvailable
    Status:                True
    Type:                  Ready
  Instances:
    qwen-coder-1-5b-instruct-5587f4c57d-kml6s
  Phase:  Running

使用 lora 模型名称向网关发送请求。

# send request to base model
curl -v http://${ENDPOINT}/v1/completions \
    -H "Content-Type: application/json" \
    -d '{
        "model": "qwen-code-lora",
        "prompt": "San Francisco is a",
        "max_tokens": 128,
        "temperature": 0
    }'

以下是与 lora 自定义资源关联的已创建资源。

lora-service-discovery-resources
  1. 将创建一个新的 Kubernetes 服务,其名称与 ModelAdapter 名称完全相同。

2. podSelector 用于过滤匹配的 pod。在这种情况下,它将匹配带有标签 model.aibrix.ai/name=qwen-coder-1-5b-instruct 的 pod。请确保您的基础模型具有此标签。这可确保 LoRA 适配器与正确的 pod 正确关联。

注意

注意:这仅适用于 vLLM 引擎。如果您使用其他引擎,请随意提出问题。

故障排除阶段转换#

如果您的 ModelAdapter 停滞在某个特定阶段,以下是常见问题和解决方案:

停滞在 Pending 阶段

  • 检查是否存在匹配 podSelector 的 pod 并且正在运行

  • 验证 pod 是否具有正确的标签(model.aibrix.ai/nameadapter.model.aibrix.ai/enabled=true

  • 确保 pod 处于 Ready 状态

停滞在 Scheduled 阶段

  • 这是早期版本中的已知问题,已修复

  • 检查控制器日志中是否存在任何加载错误:kubectl logs -n aibrix-system deployment/aibrix-controller-manager

  • 验证 vLLM pod 是否已启用 VLLM_ALLOW_RUNTIME_LORA_UPDATING

停滞在 Loading 阶段

  • 检查 artifactURL 是否可访问且有效

  • 对于 Hugging Face 模型,确保模型路径存在

  • 如果使用私有仓库,请检查身份验证

  • 查看控制器日志中特定的加载错误

  • 控制器将重试最多 5 次,并进行指数退避,然后切换到替代 pod

未能达到 Running 阶段

  • 检查 Kubernetes Service 创建是否成功:kubectl get svc <adapter-name>

  • 验证 EndpointSlice 创建:kubectl get endpointslices

  • 检查 pod 就绪性和健康状态

有用的调试命令

# Check ModelAdapter status
kubectl describe modeladapter <adapter-name>

# Check controller logs
kubectl logs -n aibrix-system deployment/aibrix-controller-manager

# Check pod logs
kubectl logs <pod-name>

# Check services and endpoints
kubectl get svc,endpointslices -l model.aibrix.ai/name=<adapter-name>

可靠性功能#

AIBrix ModelAdapter 包含几个高级可靠性功能,以确保在生产环境中部署健壮的 LoRA 适配器。

自动重试机制#

控制器实现了智能的适配器加载重试系统:

  • 每个 pod 最多重试 5 次,并进行指数退避

  • 基本间隔为 5 秒,每次重试加倍(5 秒、10 秒、20 秒、40 秒、80 秒)

  • 针对可重试和不可重试错误进行智能错误检测

  • 优雅处理常见的启动错误,例如“连接被拒绝”

# Retry behavior is automatic - no configuration needed
# Controller tracks retry state via annotations:
# - adapter.model.aibrix.ai/retry-count.<pod-name>
# - adapter.model.aibrix.ai/last-retry-time.<pod-name>

Pod 切换和故障转移#

当适配器在初始 pod 上达到最大重试次数后加载失败时:

  • 自动选择替代健康 pod

  • 通过切换到可用 pod 保持所需的副本数

  • 保留调度器偏好(最少适配器、默认)用于新选择

  • 确保最终一致性 - 适配器将加载到健康的 pod 上

Pod 健康验证#

控制器实现全面的 pod 健康检查:

  • 就绪性验证:Pod 在选择前必须处于 Ready 状态

  • 稳定性要求:Pod 必须稳定(就绪 5 秒以上)以避免抖动

  • 持续监控:不健康的 pod 会自动从实例列表中移除

  • 启动容忍度:优雅处理 pod 启动延迟

连接错误处理#

针对各种网络和启动条件进行健壮的错误处理

Retriable Errors (will trigger retry):
- "connection refused"
- "connection reset"
- "timeout"
- "no route to host"
- "network is unreachable"
- "temporary failure"
- "service unavailable"
- "bad gateway"

Non-Retriable Errors (will fail immediately):
- Authentication errors
- Invalid model format
- Configuration errors

高级配置示例#

多副本高可用性设置

这是一个生产就绪的配置,演示了跨多个 pod 的负载均衡

apiVersion: model.aibrix.ai/v1alpha1
kind: ModelAdapter
metadata:
  name: sample-lora-multi-replica
  namespace: default
  labels:
    model.aibrix.ai/name: "sample-lora-multi-replica"
    model.aibrix.ai/port: "8000"
spec:
  # REQUIRED: Base model that this LoRA adapter extends
  baseModel: qwen-coder-1-5b-instruct
  
  # Do not specify the replicas for the adapter
  # The adapter will be loaded on all pods
  # Provides high availability and load distribution
  # replicas: 1
  
  # Pod selector to identify which pods can host this adapter
  # Requires pods to have both labels for proper selection
  podSelector:
    matchLabels:
      model.aibrix.ai/name: qwen-coder-1-5b-instruct
      adapter.model.aibrix.ai/enabled: "true"
  
  # URL for the LoRA adapter artifact
  # Using a real Hugging Face model for this example
  artifactURL: "huggingface://ai-blond/Qwen-Qwen2.5-Coder-1.5B-Instruct-lora"
  
  # Optional: Scheduler for pod selection (defaults to "default")
  # "least-adapters" scheduler distributes adapters evenly across pods
  schedulerName: least-adapters

测试命令

# 1. Apply the multi-replica adapter:
kubectl apply -f samples/adapter/adapter-multi-replica.yaml

# 2. Monitor phase transitions:
watch kubectl describe modeladapter sample-lora-multi-replica

# 3. Check controller logs for retry behavior:
kubectl logs -n aibrix-system deployment/aibrix-controller-manager -f

# 4. Test pod failure scenario (delete a pod to trigger switching):
kubectl delete pod <pod-name>
# Watch how controller handles pod loss and reschedules

# 5. Verify final state:
kubectl get modeladapter sample-lora-multi-replica -o yaml

监控和可观测性#

阶段监控

可靠性功能通过标准的 ModelAdapter 状态透明

# Monitor real-time phase transitions
watch kubectl describe modeladapter <adapter-name>

# Check for retry annotations (during loading failures)
kubectl get modeladapter <adapter-name> -o yaml | grep -A 5 annotations

控制器日志

监控控制器日志中的重试行为和 pod 切换

# View retry attempts and pod switching
kubectl logs -n aibrix-system deployment/aibrix-controller-manager -f | grep -E "(retry|switching|pod)"

# Example log entries:
# I0830 03:55:42.221143 1 modeladapter_controller.go:557] "Selected pods for adapter scheduling" ModelAdapter="default/my-lora" selectedPods=["pod-1"]
# I0830 03:55:45.331456 1 modeladapter_controller.go:987] "Retriable error loading adapter" pod="pod-1" error="connection refused"
# I0830 03:55:50.445789 1 modeladapter_controller.go:1120] "Successfully loaded adapter on pod" pod="pod-2" ModelAdapter="default/my-lora"

事件和条件

可靠性事件记录在 ModelAdapter 状态条件中

kubectl describe modeladapter <adapter-name>

# Example events showing retry and recovery:
Events:
  Type    Reason                 Message
  ----    ------                 -------
  Normal  Scheduled              ModelAdapter has selected 1 pods for scheduling: [pod-1]
  Warning MaxRetriesExceeded     Max retries exceeded for pod pod-1: connection refused
  Normal  Scheduled              ModelAdapter has selected 1 pods for scheduling: [pod-2]
  Normal  Loaded                 Successfully loaded adapter on pod pod-2

生产最佳实践#

  1. 部署多个基础模型副本

    # Ensure multiple pods are available for failover
    spec:
      replicas: 3  # At least 3 pods for reliability
    
  2. 使用多个适配器副本

    # Distribute adapter across all pods
    spec:
      # Load adapter on all pods by omitting replicas field
      # replicas: 1
    
  3. 配置适当的健康检查

    # In base model deployment
    livenessProbe:
      httpGet:
        path: /health
        port: 8000
      initialDelaySeconds: 60
      periodSeconds: 30
      failureThreshold: 3
    
  4. 监控适配器健康状况

    # Regular health monitoring
    kubectl get modeladapters -o wide
    kubectl describe modeladapter <name>
    
    # Set up alerts on phase transitions
    kubectl get events --field-selector involvedObject.kind=ModelAdapter
    

更多配置#

模型注册表#

目前,我们支持 Huggingface 模型注册表、S3 兼容存储和本地文件系统。

  1. 如果您的模型托管在 Huggingface 上,您可以使用带有 huggingface:// 前缀的 artifactURL 来指定模型 URL。vLLM 将从 Huggingface 下载模型并在运行时将其加载到 pod 中。

  2. 如果您将模型放在 S3 兼容存储中,您必须同时使用 AIBrix AI Runtime。您可以使用带有 s3:// 前缀的 artifactURL 来指定模型 URL。AIBrix AI Runtime 将在 pod 上从 S3 下载模型,并使用 vLLM 中的 local model path 加载它。

  3. 如果您使用 NFS 等共享存储,您可以使用带有 / 绝对路径的 artifactURL 来指定模型 URL(例如 /models/yard1/llama-2-7b-sql-lora-test)。确保模型已挂载到 pod 是用户的责任。

模型 API 密钥认证#

用户可以通过参数 --api-key 或环境变量 VLLM_API_KEY 来启用服务器检查请求头中的 API 密钥。

python3 -m vllm.entrypoints.openai.api_server --api-key sk-kFJ12nKsFakefVmGpj3QzX65s4RbN2xJqWzPYCjYu7wT3BFake

我们已经有一个示例,您可以 kubectl apply -f samples/adapter/adapter-with-key.yaml

在这种情况下,lora 模型适配器无法正确查询 vLLM 服务器,显示 {"error":"Unauthorized"} 错误。您需要更新 additionalConfig 字段以传递 API 密钥。

apiVersion: model.aibrix.ai/v1alpha1
kind: ModelAdapter
metadata:
  name: qwen-code-lora-with-key
  namespace: default
  labels:
    model.aibrix.ai/name: "qwen-code-lora-with-key"
    model.aibrix.ai/port: "8000"
spec:
  baseModel: qwen-coder-1-5b-instruct
  podSelector:
    matchLabels:
      model.aibrix.ai/name: qwen-coder-1-5b-instruct
      adapter.model.aibrix.ai/enabled: "true"
  artifactURL: huggingface://ai-blond/Qwen-Qwen2.5-Coder-1.5B-Instruct-lora
  additionalConfig:
    api-key: sk-kFJ12nKsFakefVmGpj3QzX65s4RbN2xJqWzPYCjYu7wT3BFake
  schedulerName: default

您需要发送带有 --header 'Authorization: Bearer your-api-key' 的请求。

# send request to base model
curl -v http://${ENDPOINT}/v1/completions \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer sk-kFJ12nKsFakefVmGpj3QzX65s4RbN2xJqWzPYCjYu7wT3BFake" \
    -d '{
        "model": "qwen-code-lora-with-key",
        "prompt": "San Francisco is a",
        "max_tokens": 128,
        "temperature": 0
    }'

运行时支持 Sidecar#

从 v0.2.0 开始,控制器管理器默认会与运行时 sidecar 通信以首先注册 lora,然后运行时 sidecar 将与推理引擎同步以完成最终注册。这用于在控制器管理器和推理引擎之间构建抽象。如果您想直接与 vLLM 同步以加载 lora,您可以更新控制器管理器 kubectl edit deployment aibrix-controller-manager -n aibrix-system 并删除 ``

  spec:
    containers:
    - args:
      - --leader-elect
      - --health-probe-bind-address=:8081
      - --metrics-bind-address=0
      - --enable-runtime-sidecar # this line should be removed

私有工件存储支持#

AIBrix 支持从私有云存储后端加载 LoRA 适配器,包括 AWS S3、Google Cloud Storage (GCS) 和 Volcano Engine TOS。此功能需要 AIBrix 运行时 sidecar 来处理工件委托 - 从私有存储下载工件并将其转发到推理引擎。

支持的存储后端

  • AWS S3: s3://bucket/path/to/adapter

  • Google Cloud Storage: gs://bucket/path/to/adapter

  • Volcano Engine TOS: tos://bucket/path/to/adapter

  • 私有 HuggingFace: huggingface://org/private-model (带令牌)

  • 带身份验证的 HTTP(S): 任何带有自定义头的 URL

工作原理

Without Runtime (Direct Mode):
Controller → Inference Engine (port 8000)
✓ Public HTTP(S), public HuggingFace
✗ Private S3, GCS (not supported)

With Runtime (Artifact Delegation):
Controller → Runtime (port 8080) → Downloads Artifact → Engine
✓ S3, GCS, private HuggingFace, all storage types

运行时 sidecar

  1. 从控制器接收工件 URL 和凭据

  2. 从私有存储下载工件到本地文件系统

  3. 将本地路径转发到推理引擎

  4. 管理工件生命周期(卸载时清理)

先决条件

  1. 与推理引擎一同部署的 AIBrix 运行时 sidecar

  2. 控制器标志 --enable-runtime-sidecar=true 已启用

  3. 配置了存储凭据的 Kubernetes secrets

  4. 运行时容器和引擎容器之间共享卷

设置:AWS S3 存储#

步骤 1:创建 S3 凭据 Secret

apiVersion: v1
kind: Secret
metadata:
  name: s3-credentials
  namespace: default
type: Opaque
stringData:
  aws_access_key_id: "AKIAIOSFODNN7EXAMPLE"
  aws_secret_access_key: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
  aws_region: "us-west-2"

步骤 2:部署带运行时 Sidecar 的 Pod

apiVersion: v1
kind: Pod
metadata:
  name: vllm-llama3
  labels:
    model.aibrix.ai/name: llama-3
    adapter.model.aibrix.ai/enabled: "true"
spec:
  containers:
  # Inference engine
  - name: vllm
    image: vllm/vllm-openai:latest
    ports:
    - containerPort: 8000
    env:
    - name: VLLM_ALLOW_RUNTIME_LORA_UPDATING
      value: "True"
    volumeMounts:
    - name: adapter-storage
      mountPath: /tmp/aibrix/adapters

  # AIBrix runtime sidecar
  - name: aibrix-runtime
    image: aibrix/runtime:latest
    ports:
    - containerPort: 8080
    env:
    - name: INFERENCE_ENGINE
      value: "vllm"
    - name: INFERENCE_ENGINE_ENDPOINT
      value: "https://:8000"
    volumeMounts:
    - name: adapter-storage
      mountPath: /tmp/aibrix/adapters
    - name: credentials
      mountPath: /var/run/secrets/aibrix
      readOnly: true

  volumes:
  - name: adapter-storage
    emptyDir: {}
  - name: credentials
    secret:
      secretName: s3-credentials

步骤 3:使用 S3 URL 创建 ModelAdapter

apiVersion: model.aibrix.ai/v1alpha1
kind: ModelAdapter
metadata:
  name: sql-lora-s3
spec:
  baseModel: llama-3
  podSelector:
    matchLabels:
      model.aibrix.ai/name: llama-3
  # S3 artifact URL
  artifactURL: s3://my-company-bucket/lora-adapters/sql-adapter/
  # Reference to S3 credentials
  credentialsSecretRef:
    name: s3-credentials
  replicas: 1

步骤 4:验证工件委托

# Check ModelAdapter status
kubectl describe modeladapter sql-lora-s3

# Should show: Phase: Running
# Controller logs will show:
# "Using runtime path for artifact delegation"

# Runtime logs will show download progress:
kubectl logs <pod-name> -c aibrix-runtime
# "Downloading artifact from s3://... to /tmp/aibrix/adapters/sql-lora-s3"
# "Successfully downloaded artifact for sql-lora-s3"
# "Forwarding load request to engine with local path"

设置:Google Cloud Storage (GCS)#

步骤 1:创建 GCS 凭据 Secret

apiVersion: v1
kind: Secret
metadata:
  name: gcs-credentials
type: Opaque
stringData:
  gcp_service_account_json: |
    {
      "type": "service_account",
      "project_id": "my-project",
      "private_key_id": "key-id",
      "private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n",
      "client_email": "service-account@my-project.iam.gserviceaccount.com",
      "client_id": "123456789",
      "auth_uri": "https://#/o/oauth2/auth",
      "token_uri": "https://oauth2.googleapis.com/token",
      "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs"
    }

步骤 2:使用 GCS URL 创建 ModelAdapter

apiVersion: model.aibrix.ai/v1alpha1
kind: ModelAdapter
metadata:
  name: code-lora-gcs
spec:
  baseModel: llama-3
  podSelector:
    matchLabels:
      model.aibrix.ai/name: llama-3
  # GCS artifact URL
  artifactURL: gs://my-gcs-bucket/lora-adapters/code-adapter/
  credentialsSecretRef:
    name: gcs-credentials
  replicas: 1

设置:私有 HuggingFace 模型#

步骤 1:创建 HuggingFace 令牌 Secret

apiVersion: v1
kind: Secret
metadata:
  name: huggingface-credentials
type: Opaque
stringData:
  huggingface_token: "hf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

步骤 2:使用私有 HuggingFace URL 创建 ModelAdapter

apiVersion: model.aibrix.ai/v1alpha1
kind: ModelAdapter
metadata:
  name: private-hf-lora
spec:
  baseModel: llama-3
  podSelector:
    matchLabels:
      model.aibrix.ai/name: llama-3
  # Private HuggingFace model
  artifactURL: huggingface://my-org/private-lora-adapter
  credentialsSecretRef:
    name: huggingface-credentials
  replicas: 1

故障排除工件委托#

运行时未接收到请求

# Check controller is configured for runtime
kubectl get deployment aibrix-controller-manager -n aibrix-system -o yaml | grep enable-runtime-sidecar
# Should show: - --enable-runtime-sidecar=true

# Check runtime pod is running
kubectl get pods -l app=vllm
kubectl logs <pod-name> -c aibrix-runtime

下载失败

# Check runtime logs for specific errors
kubectl logs <pod-name> -c aibrix-runtime

# Common issues:
# - "Access denied": Check credentials in secret
# - "Not found": Verify artifact URL is correct
# - "Invalid credentials": Verify secret format matches expected keys

凭据问题

# Verify secret exists and has correct keys
kubectl get secret s3-credentials -o yaml

# For S3, required keys:
# - aws_access_key_id
# - aws_secret_access_key
# - aws_region (optional)

# For GCS, required keys:
# - gcp_service_account_json

引擎连接错误

# Verify runtime can reach engine
kubectl exec <pod-name> -c aibrix-runtime -- curl https://:8000/health

# Check shared volume is mounted correctly
kubectl describe pod <pod-name>
# Both containers should have /tmp/aibrix/adapters mounted

支持的 URL 方案摘要

URL 方案

示例

需要运行时

需要凭据

s3://

s3://bucket/path/

gs://

gs://bucket/path/

huggingface:// (私有)

huggingface://org/model

是 (令牌)

huggingface:// (公开)

huggingface://meta-llama/model

http:// / https://

https://example.com/adapter

可选

最佳实践

  1. 按存储类型使用单独的 Secrets:为 S3、GCS 凭据创建专用 secrets,而不是混合使用

  2. 先测试凭据:在创建 ModelAdapter 之前,通过手动从存储下载来验证凭据是否有效

  3. 监控运行时日志:在首次部署期间观察运行时日志,以尽早发现凭据或连接问题

  4. 共享存储卷:确保 adapter-storage 卷在运行时容器和引擎容器之间正确共享

  5. 工件大小:大型工件可能需要时间下载;如果需要,请调整超时值

运行时指标配置#

AIBrix 运行时提供灵活的指标转换选项,以处理不同的推理引擎(vLLM、SGLang)并确保兼容性。您可以使用环境变量控制指标行为:

默认模式(推荐)

# Enable metrics transformation (default: enabled)
export METRICS_ENABLE_TRANSFORMATION=1

# Disable raw passthrough mode (default: disabled)
export METRICS_RAW_PASSTHROUGH_MODE=0

此模式将不同引擎的指标标准化为通用的 aibrix: 命名空间

  • vllm:num_requests_waitingaibrix:queue_size

  • sglang:num_queue_reqsaibrix:queue_size

  • vllm:prompt_tokens_totalaibrix:prompt_tokens_total

  • sglang:prompt_tokens_totalaibrix:prompt_tokens_total

原始直通模式(调试/回退)

# Return raw engine metrics unchanged
export METRICS_RAW_PASSTHROUGH_MODE=1

在以下情况下使用此模式:

  • 调试指标转换问题

  • 不同引擎存在规模/语义差异

  • 您需要保留引擎特定的指标名称

  • 转换错误期间的回退

完全禁用转换(紧急情况)

# Disable all transformation (forces raw passthrough)
export METRICS_ENABLE_TRANSFORMATION=0

这是最安全的后备选项,无论出现任何错误,都能保证原始指标。

自动错误恢复

如果指标转换遇到错误,运行时会自动回退到原始直通模式,确保指标收集永远不会完全失败。

配置优先级

  1. METRICS_ENABLE_TRANSFORMATION=0 强制原始直通(最高优先级)

  2. METRICS_RAW_PASSTHROUGH_MODE=1 在启用转换时启用原始模式

  3. 转换错误时自动回退(最低优先级)

此配置会影响 AIBrix 运行时 sidecar 暴露的 /metrics 端点。