讲解

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。