讲解
ClusterIP 只在集群内有效,要让集群外的流量进来,最直接的类型是 NodePort:在每个节点上开一个高位端口(默认范围 30000-32767),外部访问 任意节点IP:NodePort 就会被转发到后端 Pod。NodePort 是建立在 ClusterIP 之上的——创建 NodePort 类型的 Service 会同时分配一个 ClusterIP,集群内访问方式不变,只是多了一条外部入口。
NodePort 适合开发测试和小规模场景,生产上它有三个明显短板:一是端口范围受限且要记端口号,不友好;二是没有健康检查负载均衡,流量打到某节点后该节点上未必有健康 Pod(externalTrafficPolicy: Local 可以优化但又有新的取舍);三是节点本身就是单点。所以生产环境的对外入口一般是 LoadBalancer 类型(云厂商自动创建云 LB 并把流量导给 NodePort)或 Ingress(七层路由,下一章)。
验证 NodePort 有个环境细节:节点 IP 是集群内部网络的地址,从宿主机能不能直接访问取决于集群怎么搭的。本教程的 kind 集群在建集群时用 extraPortMappings 把宿主机的 30080 映射到了节点容器的 30080,所以宿主机上 curl localhost:30080 等价于访问节点的 30080。自建 kind 集群忘了配端口映射时,可以用 kubectl port-forward svc/服务名 8080:80 临时把 Service 转发到本机调试。
示例
把上一章的 web 应用用 NodePort 暴露出来(nodePort 固定为 30080,对应建集群时的端口映射):
# wait: deploy/ohmydocs-verify-web
apiVersion: apps/v1
kind: Deployment
metadata:
name: ohmydocs-verify-web
spec:
replicas: 2
selector:
matchLabels:
app: ohmydocs-verify-web
template:
metadata:
labels:
app: ohmydocs-verify-web
spec:
containers:
- name: nginx
image: nginx:1.27-alpine
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: ohmydocs-verify-web-np
spec:
type: NodePort
selector:
app: ohmydocs-verify-web
ports:
- port: 80
targetPort: 80
nodePort: 30080
TYPE 列变成了 NodePort,PORT(S) 列显示 80:30080——集群内走 80,节点上走 30080:
kubectl get svc ohmydocs-verify-web-np
从宿主机访问节点端口(kind 的端口映射把它转到集群内),拿到 nginx 首页即全链路打通:
curl -sf --retry 8 --retry-connrefused --retry-delay 2 http://localhost:30080/ | head -3
生产环境里更常见的 LoadBalancer 类型长这样(需要云厂商或 MetalLB 提供 LB 实现,本地集群会一直 pending,只做客户端校验):
# 仅示意:LoadBalancer 需要云厂商 LB 或 MetalLB,kind 集群没有该实现,仅做 dry-run 校验
apiVersion: v1
kind: Service
metadata:
name: ohmydocs-verify-web-lb
spec:
type: LoadBalancer
selector:
app: ohmydocs-verify-web
ports:
- port: 80
targetPort: 80
常见坑
- nodePort 冲突或越界:端口必须在 30000-32767(apiserver 的 --service-node-port-range 决定),且全局唯一,冲突时 apply 报错。
- kind/minikube 里 curl 节点 IP 不通:节点 IP 在容器/虚拟机内部网络里,宿主机访问要靠端口映射(kind 的 extraPortMappings)或 minikube service 命令。
- 生产直接暴露 NodePort:端口不友好、无健康检查、依赖具体节点;对外入口交给 LoadBalancer 或 Ingress。
- externalTrafficPolicy 的副作用:设 Local 保留源 IP 但节点上没有本服务 Pod 时丢包;默认 Cluster 更稳妥。
小结
NodePort = 每节点开一个高位端口,把外部流量导入 Service;本地验证靠端口映射或 port-forward;生产对外入口用 LoadBalancer 或 Ingress。下一章讲更强大的七层入口:Ingress。