2. K8s核心概念回顾:快速回顾Pod、Deployment、Service、Ingress、ConfigMap、Secret等核心资源
好,咱们直接进入正题。这一章我打算带大家快速过一遍Kubernetes里最常用的几个核心资源。你可能会觉得「这些我早就知道了」,但别急——我挑几个我踩过坑的点,结合vLLM部署的实际场景来讲,保证有收获。
一句话总结本章价值:搞懂这些资源,你就能在K8s里把vLLM服务跑起来,并且让外界能访问到它。
2.1 Pod:最小调度单元,也是vLLM进程的家
Pod是K8s里你能创建的最小单位。说白了,一个Pod就是一个或多个容器的组合。我习惯把Pod想象成一个「进程盒子」——里面跑着你的应用进程,共享网络和存储。
在vLLM的场景下,一个Pod里通常只跑一个容器,就是vLLM推理服务本身。但注意,如果你需要边推理边做日志采集,那就可以在同一个Pod里加一个sidecar容器,专门负责日志上传。
我的经验:我曾经在部署vLLM时,把模型加载和推理放在同一个Pod的两个容器里,结果发现模型加载容器先退出,Pod就重启了——其实应该用InitContainer来做模型预热。这个后面实战章节会细讲。
Pod的YAML长这样,很简单:
apiVersion: v1
kind: Pod
metadata:
name: vllm-pod
namespace: ai-namespace
spec:
containers:
- name: vllm
image: vllm/vllm-openai:latest
ports:
- containerPort: 8000
resources:
requests:
memory: "8Gi"
nvidia.com/gpu: 1
limits:
memory: "16Gi"
nvidia.com/gpu: 1
嗯,这里要注意:Pod是临时性的。如果节点挂了,Pod就没了。所以生产环境我们很少直接创建Pod,而是用Deployment来管理。
2.2 Deployment:让vLLM服务永不掉线
Deployment是K8s里最常用的工作负载控制器。它的核心能力就三个字:自愈。你告诉它「我要跑3个vLLM实例」,它就会一直维持3个。哪个Pod挂了,它立刻再起一个。
我个人觉得,Deployment是K8s最伟大的设计之一。你想想看,以前运维一个推理服务,节点宕机了得手动重启容器,现在Deployment自动搞定。
避坑指南:我曾经在更新vLLM镜像时,直接改了Deployment的镜像版本,结果新版本有bug,所有Pod都CrashLoopBackOff。幸好Deployment支持回滚——kubectl rollout undo deployment/vllm-deployment 一键回到上一个版本。所以,永远不要手动删Pod来更新版本,用Deployment的滚动更新策略。
Deployment的YAML示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: vllm-deployment
namespace: ai-namespace
spec:
replicas: 3
selector:
matchLabels:
app: vllm
template:
metadata:
labels:
app: vllm
spec:
containers:
- name: vllm
image: vllm/vllm-openai:latest
ports:
- containerPort: 8000
2.3 Service:给vLLM Pod一个稳定的入口
Pod的IP是动态的。今天这个Pod的IP是10.1.1.5,明天重启后就变成10.1.1.8了。那客户端怎么访问?Service就是来解决这个问题的。
Service为一组Pod提供一个固定的虚拟IP(ClusterIP)和DNS名称。客户端只要访问Service的名字,K8s会自动把请求转发到后端的某个Pod上。
在vLLM场景下,我们通常用ClusterIP类型的Service,让集群内部的其他服务(比如你的前端应用)通过Service名来调用vLLM的推理接口。
关键点:Service的selector必须和Pod的labels匹配。我见过很多新手在这里栽跟头——Service配好了,但就是转发不到Pod,一查发现label写错了。
Service YAML:
apiVersion: v1
kind: Service
metadata:
name: vllm-service
namespace: ai-namespace
spec:
selector:
app: vllm
ports:
- protocol: TCP
port: 80
targetPort: 8000
type: ClusterIP
2.4 Ingress:让外部世界访问你的vLLM
Service的ClusterIP只能在集群内部访问。如果想让外部用户调用vLLM的API,就需要Ingress。
Ingress是K8s的七层负载均衡器。它负责把外部的HTTP/HTTPS请求,根据域名和路径,路由到集群内部的Service上。
举个例子:你有一个域名 api.mymodel.com,想让它指向vLLM的推理接口。Ingress就可以配置:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: vllm-ingress
namespace: ai-namespace
spec:
rules:
- host: api.mymodel.com
http:
paths:
- path: /v1/completions
pathType: Prefix
backend:
service:
name: vllm-service
port:
number: 80
我的建议:生产环境一定要配TLS证书。我曾经在测试环境忘了配,结果API被爬虫扫到,白白浪费了GPU算力。Ingress支持自动签发Let's Encrypt证书,配合cert-manager用起来很爽。
2.5 ConfigMap & Secret:配置与敏感信息管理
这两个资源经常一起出现,我就放一块讲了。
ConfigMap 用来存非敏感配置,比如vLLM的模型路径、日志级别、最大并发数等。你可以把它挂载到Pod里作为环境变量或配置文件。
Secret 用来存敏感信息,比如API密钥、数据库密码、Hugging Face的token等。它的内容会被base64编码(注意,不是加密,只是编码),但K8s会保证它在传输和存储时是加密的。
我曾经踩过的坑:有一次我把Hugging Face的token直接写在了Deployment的YAML里,然后不小心把YAML提交到了公开的Git仓库。结果第二天发现有人用我的token下载了付费模型……从那以后,我所有敏感信息都走Secret,而且用Sealed Secrets或External Secrets来做加密存储。
ConfigMap示例:
apiVersion: v1
kind: ConfigMap
metadata:
name: vllm-config
namespace: ai-namespace
data:
model_name: "meta-llama/Llama-2-7b-chat-hf"
max_model_len: "4096"
gpu_memory_utilization: "0.9"
Secret示例:
apiVersion: v1
kind: Secret
metadata:
name: hf-secret
namespace: ai-namespace
type: Opaque
data:
hf_token: aGZfxxxxxxxxxxxxxxxxxxxxx # base64编码后的token
2.6 本章知识体系总览
下面这张图,是我用SVG画的本章核心资源关系图。你看一眼就能明白它们是怎么协作的:
从这张图可以清晰看到:外部用户请求 → Ingress(域名路由) → Service(负载均衡) → Deployment(管理Pod) → Pod(运行vLLM)。同时ConfigMap和Secret把配置和密钥注入到Pod里。
2.7 快速总结
好了,这一章我们快速回顾了6个核心资源。我再用一句话帮你记住它们:
- Pod:跑vLLM进程的盒子
- Deployment:保证Pod数量正确、版本可回滚
- Service:给Pod一个稳定的内部访问入口
- Ingress:让外部用户通过域名访问vLLM
- ConfigMap:存模型路径、日志级别等配置
- Secret:存API密钥、Hugging Face token等敏感信息
我的个人习惯:每次部署新服务前,我都会先画一张类似上面的资源关系图。画完图,整个架构就清晰了,写YAML的时候基本不会漏东西。你也可以试试。
下一章,我们会把这些资源组合起来,真正搭建一个带命名空间隔离的vLLM推理服务。到时候你会看到这些概念是怎么落地的。