实验:从 GPU 节点到可观测推理服务¶
本实验面向已经有一台 NVIDIA GPU Worker 的 Kubernetes 集群。目标不是安装全部 AI 平台,而是建立一条可重复的最小验证路径:节点库存、GPU 容器、模型服务、监控关联、终止行为和证据记录。
示例 Manifest 同时保存在仓库的 examples/gpu-platform-baseline。
1. 前提和安全说明¶
需要:
- Kubernetes 1.34 或更新版本;
kubectl;- 至少一个已经安装驱动和 NVIDIA Device Plugin 的节点;
- 能拉取公开测试镜像;
- 有权限创建 Namespace、Pod、Deployment、Service 和 NetworkPolicy;
- 可选 Prometheus/DCGM Exporter。
示例镜像和版本用于演示。生产环境必须固定镜像 Digest、核对驱动兼容并使用内部 Registry。
不要在承载重要训练或生产推理的节点上直接进行故障实验。
2. 建立实验 Namespace¶
apiVersion: v1
kind: Namespace
metadata:
name: ai-lab
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/audit: restricted
pod-security.kubernetes.io/warn: restricted
kubectl apply -f examples/gpu-platform-baseline/namespace.yaml
kubectl get namespace ai-lab --show-labels
预期:Namespace 为 Active,Pod Security 标签存在。
3. 检查 GPU 库存¶
kubectl get nodes -o custom-columns='NAME:.metadata.name,GPU:.status.capacity.nvidia\.com/gpu,ALLOCATABLE:.status.allocatable.nvidia\.com/gpu'
检查目标节点:
kubectl describe node <gpu-node>
kubectl get pods -A -o wide --field-selector spec.nodeName=<gpu-node>
记录:
- GPU Capacity/Allocatable;
- GPU 产品和拓扑标签;
- Taint;
- Device Plugin、DCGM 和 CNI DaemonSet;
- 已分配 GPU;
- CPU、内存和临时存储。
如果 GPU 列为空,先修复 Driver/Device Plugin,不继续模型实验。
4. 运行 GPU Smoke Test¶
apiVersion: v1
kind: Pod
metadata:
name: gpu-smoke-test
namespace: ai-lab
spec:
restartPolicy: Never
containers:
- name: vector-add
image: nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda12.5.0
resources:
requests:
cpu: "1"
memory: 512Mi
nvidia.com/gpu: "1"
limits:
cpu: "1"
memory: 512Mi
nvidia.com/gpu: "1"
如果 GPU 节点有专用 Taint,在 Manifest 中加入与平台约定一致的 Toleration,不要用宽泛 operator: Exists 绕过所有 Taint。
kubectl apply -f examples/gpu-platform-baseline/gpu-smoke-test.yaml
kubectl wait --for=jsonpath='{.status.phase}'=Succeeded pod/gpu-smoke-test -n ai-lab --timeout=5m
kubectl logs -n ai-lab gpu-smoke-test
kubectl describe pod -n ai-lab gpu-smoke-test
预期日志包含测试通过信息。保存 Pod YAML、Event 和日志作为验收证据。
5. 观察设备归属¶
Smoke Test 运行时或对长运行测试,检查:
kubectl get pod -n ai-lab -o wide
kubectl get pod -n ai-lab gpu-smoke-test -o jsonpath='{.metadata.uid}{"\n"}'
如果安装 DCGM Exporter,在 Prometheus 中确认指标能关联:
- Node;
- Namespace;
- Pod;
- Container;
- GPU UUID/Index。
只看到节点级 GPU 利用率还不足以完成多租户计费和排障。
6. 部署最小推理服务¶
以下示例使用 vLLM 和小模型,只表达 Deployment 基线。GPU 显存、镜像 Tag 和引擎参数必须按实际环境调整。
apiVersion: apps/v1
kind: Deployment
metadata:
name: llm-server
namespace: ai-lab
spec:
replicas: 1
selector:
matchLabels:
app: llm-server
template:
metadata:
labels:
app: llm-server
spec:
terminationGracePeriodSeconds: 120
containers:
- name: vllm
image: vllm/vllm-openai:v0.11.1
args:
- --model=Qwen/Qwen2.5-0.5B-Instruct
- --served-model-name=lab-model
- --max-model-len=4096
ports:
- name: http
containerPort: 8000
startupProbe:
httpGet:
path: /health
port: http
periodSeconds: 10
failureThreshold: 60
readinessProbe:
httpGet:
path: /health
port: http
periodSeconds: 5
resources:
requests:
cpu: "2"
memory: 8Gi
nvidia.com/gpu: "1"
limits:
cpu: "2"
memory: 8Gi
nvidia.com/gpu: "1"
volumeMounts:
- name: dshm
mountPath: /dev/shm
volumes:
- name: dshm
emptyDir:
medium: Memory
sizeLimit: 2Gi
---
apiVersion: v1
kind: Service
metadata:
name: llm-server
namespace: ai-lab
spec:
selector:
app: llm-server
ports:
- name: http
port: 8000
targetPort: http
kubectl apply -f examples/gpu-platform-baseline/vllm-deployment.yaml
kubectl rollout status deployment/llm-server -n ai-lab --timeout=15m
kubectl get pod -n ai-lab -o wide
kubectl logs -n ai-lab deployment/llm-server --tail=100
首次启动需要拉取模型。不要把本实验的公网下载方式直接用于生产。
7. 发送请求¶
另一个终端:
curl -sS http://127.0.0.1:8000/v1/models
curl -sS http://127.0.0.1:8000/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "lab-model",
"messages": [{"role": "user", "content": "用一句话解释 Kubernetes。"}],
"max_tokens": 64,
"temperature": 0
}'
验证:HTTP 状态、返回模型名、首 Token、完成原因和 Token 使用量。
Port Forward 仅用于功能验证,不能代表生产 Gateway 的性能。
8. 记录冷启动¶
删除 Pod 触发重建:
kubectl get pod -n ai-lab -l app=llm-server
kubectl delete pod -n ai-lab -l app=llm-server
kubectl get pod -n ai-lab -l app=llm-server -w
记录:
- scheduler 到节点时间;
- Image Pull;
- 模型下载;
- 模型加载;
- Startup/Readiness 成功;
- Service Endpoint Ready。
第一次是缓存冷启动,第二次可能命中镜像和模型缓存。两者都要保存。
9. 验证终止行为¶
在持续流式请求期间执行:
kubectl rollout restart deployment/llm-server -n ai-lab
kubectl rollout status deployment/llm-server -n ai-lab --timeout=15m
观察:
- 旧 Pod 何时离开 Service Endpoint;
- 流式请求是否完成或明确失败;
- SIGTERM 到进程退出时间;
- 新 Pod 何时 Ready;
- 是否出现同时无 Ready 副本。
单副本实验会有中断风险。生产应使用多个副本、PDB、拓扑分散和受控滚动策略。
10. 基础 NetworkPolicy¶
本实验可以应用默认拒绝入站,再仅允许同 Namespace:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: llm-server-ingress
namespace: ai-lab
spec:
podSelector:
matchLabels:
app: llm-server
policyTypes: [Ingress]
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: ai-lab
ports:
- protocol: TCP
port: 8000
确认 CNI 实际支持并执行 NetworkPolicy。生产还应限制出站、对象存储、DNS 和元数据服务。
11. 证据模板¶
Date:
Cluster / Kubernetes:
Node / GPU:
OS / kernel / driver:
Device Plugin / GPU Operator:
Runtime image digest:
Model revision:
Smoke test result:
Cold start (cold cache):
Cold start (warm cache):
TTFT / TPOT baseline:
GPU metrics mapping:
Rollout/termination result:
NetworkPolicy result:
Known deviations:
Evidence location:
12. 清理¶
确认实验 Pod、Service、NetworkPolicy 和临时模型缓存已按平台策略清理。本地节点缓存是否保留由缓存控制器决定。
13. 通过标准¶
- Kubernetes 正确报告 GPU Capacity/Allocatable。
- GPU Smoke Test 完成并保存日志/Event。
- GPU 指标能关联到 Pod 和物理设备。
- 推理服务只有模型真正加载后才 Ready。
- 一次请求通过 OpenAI-Compatible API 成功完成。
- 冷/热启动各阶段有时间数据。
- 滚动发布和流式请求行为已经观察。
- NetworkPolicy 的允许与拒绝路径均验证。
- 所有镜像和模型版本记录在证据中。
- 实验资源能够完整清理。
下一步¶
完成本实验后,可以依次加入:
- Kueue 队列和 GPU Flavor;
- KServe InferenceService;
- LocalModelCache 或 OCI Modelcar;
- KEDA 自定义指标扩缩容;
- Gateway API Inference Extension;
- 多副本故障和节点 Drain;
- 真实模型负载基准。