把AI应用跑起来和把它跑成生产级服务,中间隔着一道巨大的鸿沟。Docker把应用装进了容器,解决了"环境一致性"的问题;但真正让应用能抗住流量洪峰、自动恢复故障、弹性伸缩的,是Kubernetes这套云原生的调度系统。
这篇文章从AI应用的特殊性出发,走一遍从Docker到K8s的完整演进路径,并给出可直接复用的代码和配置示例。
一、AI应用容器化的特殊之处
普通的Web应用打镜像,就是把代码和依赖装进去。但AI应用有几个让人头疼的地方:
依赖复杂 :CUDA版本、Python包、推理引擎(vLLM、Triton等)------这些组合稍有偏差镜像就启动不起来。根据实践,官方推荐的策略是基于vLLM等推理框架的预构建镜像进行二次扩展,例如使用 vllm/vllm-openai:latest-cu124 作为基础镜像。
镜像巨大:模型文件动辄几十GB。如果在每次构建时把模型也打包进镜像,构建和推送都会慢到怀疑人生。因此业界通常采用两种方案:模型挂在PVC(持久卷)上,新Pod直接挂载无需重新下载;或者使用专门优化的Dockerfile分层构建。
GPU资源调度:容器需要明确知道自己能用哪些GPU,不能自己抢资源。
二、Docker阶段:打包AI应用
这是起点。以下是一个基于vLLM的Dockerfile示例,用于封装一个兼容OpenAI API的推理服务:
dockerfile
# 基于vLLM官方镜像,CUDA 12.4
FROM vllm/vllm-openai:latest-cu124
WORKDIR /app
# 模型文件通过PVC挂载,不打包进镜像(推荐方式)
# 若需打包小模型,可COPY ./model /app/model
EXPOSE 8000
# 启动vLLM服务
CMD ["python", "-m", "vllm.entrypoints.openai.api_server", \
"--model", "/app/model", \
"--tensor-parallel-size", "1", \
"--max-model-len", "131072", \
"--gpu-memory-utilization", "0.95"]
关键参数说明:
--tensor-parallel-size:单卡为1;多卡按实际GPU数调整--max-model-len:受显存限制,24GB显存建议设为128K--gpu-memory-utilization:vLLM内存池占用比例,推荐0.85~0.95
构建与推送:
bash
docker build -t my-registry/ai-agent:latest .
docker push my-registry/ai-agent:latest
三、Kubernetes基础部署:让Agent跑在集群里
3.1 GPU调度配置
在K8s里调度GPU,首先需要安装NVIDIA设备插件。Kubernetes通过Device Plugin机制将GPU暴露为可调度资源,如nvidia.com/gpu。
GPU Pod示例:
yaml
apiVersion: v1
kind: Pod
metadata:
name: gpu-test
spec:
containers:
- name: cuda-container
image: nvcr.io/nvidia/cuda:12.0-base
resources:
limits:
nvidia.com/gpu: 1 # 请求1个GPU
command: ["nvidia-smi"]
重要限制 :GPU资源只能在
limits中指定,不能在requests中单独申请------Kubernetes默认将limit值作为request。两者可以同时设置但必须相等。
3.2 部署AI Agent服务
将前述Docker镜像部署为K8s Deployment,并配上Service和探针:
yaml
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: ai-agent
labels:
app: ai-agent
spec:
replicas: 3
selector:
matchLabels:
app: ai-agent
template:
metadata:
labels:
app: ai-agent
spec:
containers:
- name: agent
image: my-registry/ai-agent:latest
ports:
- containerPort: 8000
env:
- name: OPENAI_API_KEY
valueFrom:
secretKeyRef:
name: api-secrets
key: openai-api-key
resources:
limits:
nvidia.com/gpu: 1
memory: "32Gi"
cpu: "8"
requests:
memory: "16Gi"
cpu: "4"
livenessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /ready
port: 8000
initialDelaySeconds: 5
periodSeconds: 5
探针的作用 :livenessProbe在容器僵死时触发重启;readinessProbe确保只有健康实例接收流量,二者配合实现服务的自愈能力。
配套Service将Pod暴露为稳定的网络入口:
yaml
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: ai-agent-service
spec:
type: LoadBalancer
selector:
app: ai-agent
ports:
- protocol: TCP
port: 80
targetPort: 8000
四、弹性伸缩:让Agent能扛住流量洪峰
单靠固定副本数,流量高峰时扛不住,低谷时又浪费资源。Kubernetes提供了HorizontalPodAutoscaler(HPA)实现自动扩缩容。
4.1 基于CPU/内存的HPA
最简单的场景:CPU超过70%就扩容,低于阈值就缩容:
yaml
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: ai-agent-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: ai-agent
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: 80
4.2 基于自定义指标的HPA(针对LLM场景)
CPU和内存指标对LLM服务往往不够敏感------模型推理是GPU密集型,CPU可能不高但GPU已满载。针对vLLM等推理框架,更精准的做法是基于队列长度 或等待请求数做扩缩容。
通过Prometheus采集vLLM暴露的num_requests_waiting指标,再由Prometheus Adapter转换成HPA可用的自定义指标:
yaml
# 基于KEDA + Prometheus的自定义扩缩容配置
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: llm-keda
spec:
scaleTargetRef:
name: ai-agent
minReplicaCount: 1
maxReplicaCount: 10
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus:9090
metricName: llm_queue_length
threshold: "1000" # 队列超过1000个请求即扩容
根据vLLM生产堆栈的实践,结合ReadWriteMany(RWX)存储类可以让新Pod启动时无需重新下载模型权重,大幅缩短扩容时间,实现秒级弹性。
4.3 Knative Serverless:缩容到0
如果业务有明显的波峰波谷(如企业下班后几乎无请求),Knative Serving可以实现更激进的弹性:空闲时缩容到0 Pod,请求到来时冷启动拉起,电费和GPU成本降低90%以上。
yaml
# Knative Service示例
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: ai-agent
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/minScale: "0"
autoscaling.knative.dev/maxScale: "10"
autoscaling.knative.dev/metric: "concurrency"
autoscaling.knative.dev/target: "50"
spec:
containers:
- image: my-registry/ai-agent:latest
resources:
limits:
nvidia.com/gpu: 1
核心配置 :minScale: 0允许缩容到零;target: 50表示每个Pod维持50个并发请求。
五、进阶:Operator模式管理多AI服务
当AI服务规模扩大到数十甚至上百个Agent实例时,手动管理Deployment和HPA变得不可持续。此时引入自定义资源(CRD)+ Operator模式,将Agent的生命周期管理抽象为声明式配置。
yaml
apiVersion: ai.io/v1alpha1
kind: Agent
metadata:
name: hr-assistant
spec:
image: my-registry/ai-agent:latest
knowledgeBase:
s3: "s3://company-kb/hr/"
resources:
limits:
nvidia.com/gpu: 1
autoscaling:
maxReplicas: 5
targetQueueLength: 500
Operator自动监听Agent资源的增删改,创建对应的Deployment、Service、HPA和Ingress。这种模式让AI Agent的部署从"写一堆YAML"变成了"写一个意图声明",是大型企业级部署的最佳实践。
总结
从Docker到Kubernetes,AI应用的部署能力逐级跃升:
| 阶段 | 核心技术 | 解决的问题 |
|---|---|---|
| Docker容器化 | Dockerfile + 镜像仓库 | 环境一致性、依赖固化 |
| K8s基础部署 | Deployment + Service + 探针 | 高可用、负载均衡、故障自愈 |
| GPU调度 | Device Plugin + limits配置 | GPU资源管理和隔离 |
| 弹性伸缩 | HPA / KEDA / Knative | 按需扩缩容、成本优化 |
| 企业级管理 | Operator + CRD | 规模化运维、声明式管理 |
记住:先让应用在Docker里跑通,再一步步往K8s迁移。每一个阶段都有明确的收益,不必一上来就追求最复杂的方案。对于绝大多数AI应用,基础K8s部署 + GPU调度 + HPA弹性伸缩这组合已经能覆盖90%的生产需求。