第4章:vLLM服务暴露:Service类型介绍、ClusterIP、NodePort、LoadBalancer的区别
好,咱们接着聊。上一章我们把 vLLM 服务部署到了 K8s 集群里,但 Pod 这东西说白了是“飘忽不定”的——它可能被调度到任意节点,IP 也会随重启而改变。那问题来了:客户端怎么稳定地访问它?
答案就是 Service。Service 是 K8s 里用来暴露 Pod 的抽象层。它给一组 Pod 提供一个固定的“入口”,不管 Pod 怎么变,客户端只管访问这个入口就行。
我个人习惯把 Service 比作“前台接待”。你打电话到公司,前台帮你转接到具体工位。工位换了,你只要记住前台号码就行。Service 就是那个前台。
K8s 提供了三种主要的 Service 类型:ClusterIP、NodePort、LoadBalancer。它们各有各的适用场景。下面我一个个讲,顺便聊聊我踩过的坑。
4.1 ClusterIP:集群内部访问
ClusterIP 是默认类型。它给 Service 分配一个集群内部的虚拟 IP,只有集群内的 Pod 能访问。外部网络是连不进来的。
你想想看,如果你的 vLLM 服务只给集群内的其他微服务调用,比如一个前端应用、一个数据处理管道,那 ClusterIP 就够用了。简单、安全、没额外开销。
核心特点:
- 分配一个虚拟 IP(ClusterIP),仅集群内可达
- 通过 kube-proxy 实现负载均衡和转发
- 默认类型,无需额外配置
举个例子,我部署一个 vLLM 推理服务,集群内有个 Python 脚本要调它的 API。我会这么写 Service:
apiVersion: v1
kind: Service
metadata:
name: vllm-service-clusterip
spec:
selector:
app: vllm
ports:
- protocol: TCP
port: 8000
targetPort: 8000
type: ClusterIP
然后集群内的 Pod 直接用 vllm-service-clusterip:8000 就能访问。注意,这里用的是 Service 名称,K8s 的 DNS 会自动解析成 ClusterIP。
小提示:ClusterIP 的 IP 是虚拟的,你没法在宿主机上 ping 通它。它只在 iptables/IPVS 规则里存在。我第一次用的时候还傻乎乎去 ping,结果超时了……
4.2 NodePort:从集群外部访问(简单粗暴)
NodePort 是在 ClusterIP 基础上,在每个节点的 IP 上开一个端口(范围 30000-32767)。外部流量通过 节点IP:NodePort 就能访问到 Service。
说白了,NodePort 就是把 Service 的端口“映射”到了宿主机上。你想想看,如果你在开发环境想快速验证一下 vLLM 服务能不能跑通,或者你手头没有 LoadBalancer,NodePort 是最快的办法。
我在项目中遇到过这种情况:客户现场没有 LoadBalancer,只有几台裸金属服务器。我就用 NodePort 暴露服务,然后让运维人员在防火墙里放行对应端口。虽然不优雅,但能干活。
注意:NodePort 的端口范围是固定的(30000-32767)。如果你需要暴露多个服务,注意端口不要冲突。我曾经因为两个 Service 用了同一个 NodePort,结果其中一个一直报错,排查了半天才发现是端口冲突。
配置示例:
apiVersion: v1
kind: Service
metadata:
name: vllm-service-nodeport
spec:
selector:
app: vllm
ports:
- protocol: TCP
port: 8000
targetPort: 8000
nodePort: 30080 # 可选,不指定则随机分配
type: NodePort
访问方式:http://任意节点IP:30080。注意,如果节点有多个 IP,kube-proxy 会监听所有 IP 上的这个端口。
NodePort 的优缺点:
- 优点:配置简单,不依赖外部组件,适合开发测试
- 缺点:端口范围受限,安全性差(直接暴露节点端口),无法做高级负载均衡
4.3 LoadBalancer:云原生时代的标配
LoadBalancer 是 NodePort 的“升级版”。它在 NodePort 的基础上,额外调用云厂商的负载均衡器(比如阿里云 SLB、AWS ELB),给 Service 分配一个公网 IP。外部流量先到负载均衡器,再转发到节点端口,最后到 Pod。
我个人觉得,如果你在云上跑 K8s,LoadBalancer 是首选。它把网络接入的复杂性交给了云厂商,你只需要声明 type: LoadBalancer,剩下的云平台帮你搞定。
我记得有一次帮客户迁移 vLLM 服务,从自建机房搬到阿里云。原来用 NodePort 暴露,运维要手动配 Nginx 做反向代理。换成 LoadBalancer 后,一行 YAML 就搞定了,省了不少事。
配置示例:
apiVersion: v1
kind: Service
metadata:
name: vllm-service-lb
spec:
selector:
app: vllm
ports:
- protocol: TCP
port: 80
targetPort: 8000
type: LoadBalancer
创建后,用 kubectl get svc 查看 EXTERNAL-IP 字段,那就是公网 IP。等它从 <pending> 变成具体 IP,就可以用了。
避坑指南:LoadBalancer 的 EXTERNAL-IP 如果一直 <pending>,八成是云厂商的插件没装好,或者账号权限不够。我曾经在测试环境折腾了一下午,最后发现是云平台的 RAM 角色没配对。
4.4 三种类型对比:一张表说清楚
为了方便你对比,我整理了一张表。嗯,面试也经常考这个。
| 特性 | ClusterIP | NodePort | LoadBalancer |
|---|---|---|---|
| 访问范围 | 集群内部 | 集群外部(节点IP+端口) | 集群外部(公网IP) |
| 端口范围 | 任意 | 30000-32767 | 任意(由负载均衡器决定) |
| 依赖组件 | 无 | 无 | 云厂商负载均衡器 |
| 适用场景 | 微服务间调用 | 开发测试、小规模暴露 | 生产环境、公网服务 |
| 安全性 | 高(仅集群内) | 低(直接暴露节点) | 中(可配合安全组) |
| 成本 | 无额外成本 | 无额外成本 | 按负载均衡器计费 |
4.5 核心逻辑:一张图看懂
下面我用 SVG 画了一张图,帮你理清这三种 Service 的流量路径。你一看就明白。
从图上你能看到:
- ClusterIP:流量只在集群内部走,不经过外部网络
- NodePort:外部用户直接访问节点 IP + 端口,kube-proxy 转发到 Pod
- LoadBalancer:外部用户先到云负载均衡器,再分发到各节点的 NodePort
4.6 怎么选?我的建议
说了这么多,到底用哪个?我根据经验给个参考:
- 开发环境:用 ClusterIP 就够了。你可以在集群内跑个测试 Pod 来调 vLLM。如果非要外部访问,NodePort 也行,但记得用完关掉。
- 测试/预发布环境:NodePort 或者 LoadBalancer 都行。看你们有没有云资源。我习惯在测试环境用 NodePort,省得每次创建 LoadBalancer 还要等云平台分配 IP。
- 生产环境:必须 LoadBalancer。别省那点钱。NodePort 直接暴露节点端口,安全审计都过不了。而且 LoadBalancer 自带健康检查和流量分发,比 NodePort 靠谱得多。
再次提醒:如果你用 NodePort 暴露 vLLM 服务,记得在安全组里限制来源 IP,别让全网都能扫到你的 30080 端口。我曾经见过一个客户,NodePort 暴露了 Redis,结果被挖矿程序盯上了……
好了,这一章就到这里。三种 Service 类型你心里有数了吧?下一章我们聊聊 Ingress,那才是真正生产环境暴露服务的“正规军”。
公众号:蓝海资料掘金营,微信deep3321