首页 / Kubernetes (k8s) 入门教程 / ClusterIP/NodePort/LoadBalancer

Kubernetes (k8s) 入门教程

ClusterIP/NodePort/LoadBalancer

本教程共 65 篇 · 第 26 篇 · 更新于 2026-08-14 · 约 13 分钟阅读

KubernetesServiceClusterIPNodePortLoadBalancer服务暴露

本节目标:分清 Service 的三种基础类型,知道什么场景用 ClusterIP、什么场景用 NodePort、什么场景上 LoadBalancer。

上一章说了,Service 用虚拟 IP 把一组 Pod 兜住。但这个虚拟 IP 能不能从集群外面访问,取决于 Service 的 type。Kubernetes 把能力做成层层递进的三档,越往后暴露面越广。

26-1 ClusterIP:只在集群内部用

ClusterIP 是默认类型。你不写 type 字段,创建出来的就是它。它从集群预留的 IP 段里分一个地址,只有集群内部能访问。

绝大多数内部服务就该用这个。比如订单服务要调库存服务,两者都在集群里,根本不需要让外界直接连。

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376

这里没写 type,等价于 type: ClusterIP。集群会分配一个类似 10.96.x.x 的地址。

Note

想让 ClusterIP 服务被集群外访问,得另配 Ingress 或 Gateway API。ClusterIP 本身只认集群内流量。

有时候你想自己定这个 IP,比如复用一个老 DNS 记录。那就显式写 spec.clusterIP,但它必须在 API 服务器配置的 service-cluster-ip-range 范围内,否则会被直接拒绝(返回 422)。

26-2 无头服务:我不要 IP

spec.clusterIP 设成 "None",就得到无头服务(Headless Service)。它不分配虚拟 IP,kube-proxy 也不管它。DNS 会直接把后端各个 Pod 的 IP 返回给调用方。

什么场景用?当你想自己掌控连哪个 Pod 时。比如有状态集(StatefulSet),每个 Pod 有自己的网络身份,客户端希望直连特定 Pod,而不是走负载均衡。

Tip

普通 Service 的 DNS 解析到集群 IP;无头 Service 的 DNS 解析到一组 Pod IP。想绕过负载均衡、自己挑 Pod,就上无头服务。

26-3 NodePort:在每个节点开个门

NodePort 在 ClusterIP 之上多做一步:它在每个节点的 IP 上开一个固定端口(默认范围 30000-32767)。

外部访问时,连任意一个节点的 IP 加这个端口,流量就会被转给后端 Pod。下面指定了 30007:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: NodePort
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - port: 80
      targetPort: 80
      nodePort: 30007

分配到的真实端口会写在 .spec.ports[*].nodePort 里。你访问 <节点IP>:30007 就能进到服务。

Warning

NodePort 的范围默认是 30000-32767。手动指定 nodePort 时,得自己防着端口冲突。另外自 v1.28 起(v1.29 稳定),范围被划成两段:30000-30085 是静态段(手动指定用),30086-32767 是动态段(自动分配用),这样能减少撞车。

NodePort 适合什么?你想自己搭负载均衡、或者集群外的某个固定网段要能直连节点时。但它对外暴露的是一堆节点的 IP,管理起来麻烦,生产上更多是给 LoadBalancer 当底座。

26-4 LoadBalancer:交给云平台

LoadBalancer 在 NodePort 的基础上,再让云平台帮你创建一个外部负载均衡器。典型场景就是跑在云上的托管集群。

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - protocol: TCP
      port: 80
      targetPort: 9376
  type: LoadBalancer

创建后,负载均衡器的地址会异步填充到 .status.loadBalancer.ingress 字段。等一两分钟,用 kubectl get service my-service 就能看到 EXTERNAL-IP 不再显示 <pending>

Note

Kubernetes 自己不带负载均衡组件。是 cloud-controller-manager 去调云平台的 API 把负载均衡器建起来的。所以在裸金属(bare-metal)集群上,LoadBalancer 不会自动生效,得装 MetalLB 这类实现。

LoadBalancer 默认会顺带分配 NodePort。自 v1.22 起(v1.24 GA),你可以把 spec.allocateLoadBalancerNodePorts 设成 false 来关掉它——前提是你的负载均衡器实现能直接把流量路由到 Pod。

26-5 指定负载均衡器的实现类别

如果集群里装了不止一种负载均衡器实现,可以用 spec.loadBalancerClass 挑一个:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: LoadBalancer
  loadBalancerClass: example.com/internal-vip
  selector:
    app.kubernetes.io/name: MyApp
  ports:
    - port: 80
      targetPort: 9376

设了 loadBalancerClass 后,云平台自带的默认实现会无视这个 Service,交给匹配该类的控制器处理。这个字段一旦设了就不能改。

26-6 内部负载均衡器怎么开

有时候你不想服务暴露到公网,只想在同 VPC 内被访问。各大云平台用注解来声明”内部负载均衡器”,写法各不同:

# 阿里云
metadata:
  annotations:
    service.beta.kubernetes.io/alibaba-cloud-loadbalancer-address-type: "intranet"
---
# 腾讯云
metadata:
  annotations:
    service.kubernetes.io/qcloud-loadbalancer-internal-subnetid: subnet-xxxxx
---
# AWS
metadata:
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-scheme: "internal"
Tip

这些注解是各家云平台自己定义的,不是 Kubernetes 标准字段。换云厂商时写法得跟着变,别当成通用配置。

26-7 三种类型怎么选

简单粗暴的选法:

  • 服务只在集群内部被调用 → ClusterIP,也是默认。
  • 要临时从集群外连一下、或在自己机房搭入口 → NodePort
  • 跑在云上,想正经对外暴露 HTTP/HTTPS 之外的服务 → LoadBalancer
Warning

Ingress 不是 Service 类型,它是七层 HTTP 路由。如果你的服务要走域名、路径路由、TLS 终止,优先用 Ingress(或 Gateway),而不是堆一堆 LoadBalancer。每个 LoadBalancer 背后都可能是真金白银的云资源。

下章讲集群内部的服务发现:Pod 怎么靠 DNS 名字找到彼此,CoreDNS 在其中扮演什么角色。