Skip to content

Service类型详解

Kubernetes Service 的 spec.type 字段决定了 Service 的访问方式和网络暴露范围。共有四种有效的 Service 类型:ClusterIP、NodePort、LoadBalancer 和 ExternalName。此外,通过设置 clusterIP: None 可以得到一种特殊的 Headless Service,它不属于上述四种类型,但经常在实际使用中作为补充。

ClusterIP

ClusterIP 是默认的 Service 类型。它为 Service 分配一个仅在集群内部可访问的虚拟 IP 地址。集群内的 Pod 或其他组件可以通过该 ClusterIP 访问 Service 后端的一组 Pod。

  • 工作原理:kube-proxy 在节点上配置 iptables 或 ipvs 规则,将发往 ClusterIP 的流量负载均衡到后端的 Pod IP。
  • 使用场景:微服务之间的内部调用,如 API 网关调用后端业务服务、数据库访问代理等。
  • 访问方式:<ClusterIP>:<port><service-name>.<namespace>.svc.cluster.local(集群 DNS 解析)。

示例:

yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp-svc
spec:
  type: ClusterIP
  selector:
    app: myapp
  ports:
    - port: 8080
      targetPort: 80

注意:ClusterIP 无法从集群外部直接访问。如果需要调试或临时访问,可以使用 kubectl port-forwardkubectl proxy

NodePort

NodePort 建立在 ClusterIP 的基础之上,额外在每个集群节点上开放一个静态端口(默认范围 30000-32767)。外部客户端可以通过 <任意节点IP>:<NodePort> 访问 Service。

  • 工作原理:kube-proxy 在每个节点上监听 NodePort 端口,并将接收到的流量转发给对应的 ClusterIP,再最终到达后端 Pod。节点间也会互相转发,即使请求到达的节点上没有目标 Pod,也会被转发到正确的节点。
  • 使用场景:适合本地开发环境、小型生产环境,或作为 LoadBalancer 的基础。当无法直接使用云负载均衡器时,使用 NodePort 配合外部硬件 LB 也是常见方案。
  • 访问方式:<NodeIP>:<NodePort>。NodeIP 可以是任意节点的内网或外网 IP,取决于网络配置。

示例:

yaml
apiVersion: v1
kind: Service
metadata:
  name: web-nodeport
spec:
  type: NodePort
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 8080
      nodePort: 30080 # 可选,不指定则自动分配

注意事项:

  • NodePort 端口范围可通过 kube-apiserver 的 --service-node-port-range 参数修改。
  • 如果节点防火墙未开放 NodePort 端口,外部访问将失败。
  • 默认情况下,源 IP 可能会被 SNAT,导致后端 Pod 看到的客户端 IP 是节点 IP。可通过设置 externalTrafficPolicy: Local 保留真实源 IP,但会失去节点间的流量转发能力。

LoadBalancer

LoadBalancer 类型是 NodePort 的扩展,主要在云环境(AWS、GCP、Azure、阿里云等)中使用。它会自动向云厂商申请一个外部负载均衡器,并将流量转发到节点的 NodePort 上。

  • 工作原理:Kubernetes 控制器(如 cloud-controller-manager)与云 API 交互,创建负载均衡器实例。负载均衡器的目标端口指向所有节点的 NodePort。外部流量到达负载均衡器后,再分发到各节点的 NodePort,最终由 kube-proxy 转发到 Pod。
  • 使用场景:生产环境中的公有云集群。开发者只需声明 Service 类型为 LoadBalancer,即可获得一个公共 IP 或 DNS 名,无需手动配置外部 LB。
  • 访问方式:云厂商分配的负载均衡器 IP 或主机名。

示例:

yaml
apiVersion: v1
kind: Service
metadata:
  name: public-app
spec:
  type: LoadBalancer
  selector:
    app: public-app
  ports:
    - port: 443
      targetPort: 8443
  loadBalancerIP: "203.0.113.10" # 可选,部分云支持静态 IP

进阶配置:

  • loadBalancerIP:仅部分云支持,用于指定已有静态公网 IP。
  • loadBalancerClass(Kubernetes v1.24+):指定使用某个自定义 LB 提供商。
  • 内部负载均衡器:可通过注解(如 service.beta.kubernetes.io/aws-load-balancer-internal: "true")声明为私有 IP 负载均衡器。

云外环境:对于裸金属集群,可以使用 MetalLB 作为 LoadBalancer 的实现,提供相同的体验。

ExternalName

ExternalName 是 Service 中最特殊的一种类型。它没有 ClusterIP,也不代理任何 Pod,而是将 Service 映射到一个外部的 DNS 名称(CNAME 记录)。

  • 工作原理:kube-dns / CoreDNS 会为 ExternalName Service 创建一条 CNAME 记录,指向 externalName 字段指定的域名。当集群内的 Pod 通过 Service 名称访问时,DNS 解析直接返回该外部域名。
  • 使用场景:让集群内应用使用统一的 Service 名称(如 databaseapi.external)访问外部服务,后续可以将该外部服务迁移到集群内部,只需修改 Service 类型,无需更改应用配置。
  • 访问方式:<service-name>.<namespace>.svc.cluster.local 解析为 externalName 指定的域名。

示例:

yaml
apiVersion: v1
kind: Service
metadata:
  name: external-db
spec:
  type: ExternalName
  externalName: mydatabase.example.com

集群内 Pod 可以通过 external-db.default.svc.cluster.local 访问 mydatabase.example.com

限制:

  • ExternalName 仅支持 DNS 名称,不支持 IP 地址(若使用 IP 地址,会作为 A 记录解析,但规范要求必须是合法域名)。
  • 不支持端口定义,实际访问时需使用目标服务的默认端口或由应用层指定。

Headless Service(特殊形式)

Headless Service 不是一种独立的 type 值,而是通过设置 spec.clusterIP: "None" 获得。它的主要特点是 不分配 ClusterIP,kube-proxy 也不对其进行负载均衡。

  • 工作原理:
    • 无 selector 的 Headless Service:Endpoints 不会自动创建,需手动管理,DNS 返回 CNAME 或 A 记录指向手动指定的地址。
    • 有 selector 的 Headless Service:Kubernetes 会自动创建 Endpoints 对象,但 DNS 返回的是 Pod IP 列表(A 记录),而非单个 Service IP。
  • 使用场景:
    • 配合 StatefulSet 为每个 Pod 提供稳定的 DNS 标识(如 pod-name.service-name.namespace.svc.cluster.local)。
    • 当客户端需要自行实现负载均衡或服务发现,如 Kafka、Cassandra 等有状态分布式系统。
    • 需要直接访问所有后端 Pod 的情况,例如监控 agent 需要抓取每个 Pod 的 metrics。

示例:

yaml
apiVersion: v1
kind: Service
metadata:
  name: nginx-headless
spec:
  clusterIP: None
  selector:
    app: nginx
  ports:
    - port: 80
      targetPort: 80

DNS 查询该 Service 会返回多个 A 记录:

bash
dig nginx-headless.default.svc.cluster.local
;; ANSWER SECTION:
nginx-headless.default.svc.cluster.local. 30 IN A 10.244.1.5
nginx-headless.default.svc.cluster.local. 30 IN A 10.244.2.8
nginx-headless.default.svc.cluster.local. 30 IN A 10.244.3.1

类型选择指南

类型对外暴露内部访问典型场景是否需云支持
ClusterIP内部服务通信
NodePort是(节点IP+端口)开发/测试环境、自建集群的外部入口
LoadBalancer是(LB IP/DNS)生产环境公有云是(或 MetalLB)
ExternalName否(仅DNS别名)是(指向外部DNS)访问外部服务且需要统一名称
Headless(clusterIP: None)视拓扑而定是(Pod IP直接访问)有状态应用、自定义服务发现

总结

Service 类型的选择直接决定了应用的访问策略和暴露范围。默认的 ClusterIP 足以覆盖绝大多数内部调用需求;NodePort 提供了一种简单的外部访问方式;LoadBalancer 将节点端口的暴露管理交由云提供商,简化运维;ExternalName 则帮助应用平滑对接外部资源。理解这几种类型的特性和适用场景,是构建稳定、可维护的 Kubernetes 服务网络的基础。