Kubernetes服务组件(service)详解指南

Kubernetes 服务组件(Service)详解指南

在 Kubernetes (K8s) 集群中,Pod 是短暂的、可替换的。它们可能会因为各种原因(例如节点故障、资源限制、应用更新)而被创建、销毁或重新调度。这意味着直接依赖 Pod 的 IP 地址是不可靠的。Kubernetes Service 组件应运而生,它提供了一个稳定的、抽象的访问入口,将客户端请求路由到一个或多个 Pod 的集合。

1. 为什么要使用 Service?

Service 的核心作用是:

  • 服务发现和负载均衡: Service 为一组具有相同功能的 Pod 提供一个单一的、稳定的访问点(虚拟 IP 地址和 DNS 名称)。客户端无需关心后端具体有哪些 Pod,以及这些 Pod 的 IP 地址如何变化。Service 会自动将流量负载均衡到健康的 Pod 上。
  • 解耦: Service 将前端应用(客户端)与后端应用(Pod)解耦。后端 Pod 的变化(例如扩缩容、滚动更新)不会影响前端应用,只要 Service 的定义保持不变。
  • 内部和外部访问: Service 可以配置为仅在集群内部访问,也可以暴露到集群外部,供外部客户端访问。

2. Service 的类型

Kubernetes 提供了几种不同类型的 Service,以满足不同的访问需求:

2.1 ClusterIP

  • 默认类型。
  • Service 获得一个集群内部的虚拟 IP 地址(Cluster IP),只能在集群内部访问。
  • 适用于集群内部服务之间的通信。

示例 (YAML):

yaml
apiVersion: v1
kind: Service
metadata:
name: my-internal-service
spec:
selector:
app: my-app # 匹配带有标签 app=my-app 的 Pod
ports:
- protocol: TCP
port: 80 # Service 端口
targetPort: 8080 # Pod 端口
type: ClusterIP # 可以省略,因为这是默认类型

2.2 NodePort

  • ClusterIP 的基础上,在每个节点上开放一个静态端口(NodePort)。
  • 外部客户端可以通过 <节点IP>:<NodePort> 访问 Service。
  • 通常用于临时测试或需要直接从集群外部访问的场景,不建议生产环境长期使用。

示例 (YAML):

yaml
apiVersion: v1
kind: Service
metadata:
name: my-nodeport-service
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
nodePort: 30007 # 指定 NodePort,范围通常是 30000-32767
type: NodePort

2.3 LoadBalancer

  • NodePort 的基础上,使用云提供商的负载均衡器(例如 AWS ELB、Google Cloud Load Balancer、Azure Load Balancer)将流量分发到各个节点。
  • 云提供商会自动配置负载均衡器,并将流量转发到 Service 的 NodePort
  • 适用于需要高可用、可扩展的外部访问场景。

示例 (YAML):

yaml
apiVersion: v1
kind: Service
metadata:
name: my-loadbalancer-service
spec:
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
type: LoadBalancer

2.4 ExternalName

  • 将 Service 映射到集群外部的服务,通过 DNS CNAME 记录实现。
  • Service 没有 Cluster IP,也没有端口映射。
  • 适用于访问集群外部的数据库、API 等服务。

示例 (YAML):

yaml
apiVersion: v1
kind: Service
metadata:
name: my-external-service
spec:
type: ExternalName
externalName: my.database.example.com # 外部服务的 DNS 名称

2.5 Headless Service

  • 通过指定clusterIP: None来创建的特殊Service。
  • Headless Service 不会分配 Cluster IP, kube-proxy也不会处理它们。
  • DNS会为 Headless Service 对应的每个Pod创建一个 A记录。
  • 适用于需要直接访问特定 Pod 的场景,例如 StatefulSet。

示例(YAML)
yaml
apiVersion: v1
kind: Service
metadata:
name: my-headless-service
spec:
clusterIP: None
selector:
app: my-app
ports:
- protocol: TCP
port: 80
targetPort: 8080

3. Service 的工作原理

  1. Endpoint Controller: Endpoint Controller 持续监控 Pod 的变化(创建、删除、更新)。
  2. Endpoints 对象: 当 Service 创建时,会自动创建一个同名的 Endpoints 对象。Endpoints 对象包含了与 Service 的 selector 匹配的 Pod 的 IP 地址和端口列表。
  3. kube-proxy: kube-proxy 是运行在每个节点上的网络代理。它负责实现 Service 的负载均衡和服务发现。kube-proxy 有几种不同的模式:
    • userspace 模式 (已弃用): kube-proxy 监听 Service 和 Endpoints 的变化,并在 userspace 中创建代理规则。性能较差。
    • iptables 模式 (默认): kube-proxy 使用 iptables 规则来实现负载均衡。性能比 userspace 模式好,但当 Service 数量很多时,iptables 规则可能会变得非常庞大,影响性能。
    • IPVS 模式: kube-proxy 使用 IPVS (IP Virtual Server) 来实现负载均衡。IPVS 专门为负载均衡设计,性能比 iptables 更好,特别是在 Service 数量很多的情况下。
  4. DNS: Kubernetes 集群通常会配置一个 DNS 服务(例如 CoreDNS)。当 Service 创建时,DNS 服务会为 Service 创建一个 DNS 记录,将 Service 的名称解析为 Service 的 Cluster IP(对于 ClusterIP 类型的 Service)或负载均衡器的 IP 地址(对于 LoadBalancer 类型的 Service)。

4. Service 的关键概念

  • Selector: Service 通过 selector 标签选择器来匹配一组 Pod。只有带有匹配标签的 Pod 才会成为 Service 的后端。
  • Ports: Service 定义了 port(Service 端口)和 targetPort(Pod 端口)的映射关系。客户端通过 Service 的 port 访问服务,流量会被转发到 Pod 的 targetPort
  • Session Affinity (会话亲和性): Service 可以配置会话亲和性,将来自同一个客户端的请求始终路由到同一个 Pod。这对于需要维护会话状态的应用(例如购物车)非常有用。可以通过 service.spec.sessionAffinity 字段配置,可选值为 None (默认) 或 ClientIP

5. 总结

Kubernetes Service 是集群内部和外部访问应用的关键组件。它提供了服务发现、负载均衡、解耦等重要功能。理解不同类型的 Service 以及它们的工作原理,对于构建可靠、可扩展的 Kubernetes 应用至关重要。选择正确的 Service 类型取决于您的具体需求和应用场景。 通过合理利用 Service,您可以轻松管理应用的访问,并确保应用的高可用性和可扩展性。

THE END