核心概念:Service 是什么?
在深入类型之前,首先要明白 Service 的核心作用:它为一组功能相同的 Pod(通常由同一个 Deployment 管理)提供一个稳定的、统一的访问入口(IP 地址、DNS 名称和端口),并负责将客户端的请求负载均衡到后端的多个 Pod 上。
由于 Pod 是“ ephemeral ”(短暂的),它的 IP 地址会随着重启、调度而改变。Service 解决了“如何可靠地访问一组动态 Pod”的问题。
Service 的四种类型
Service 的类型 (type) 决定了其网络暴露的范围和能力,即谁能访问这个 Service。
1. ClusterIP (默认类型)
解释:这是默认的 Service 类型。它为 Service 分配一个仅在集群内部可以访问的虚拟 IP 地址(即 ClusterIP)。这个 IP 地址在集群的生命周期内是稳定的。
用例:
集群内部服务通信:这是最常见的场景。例如,你的前端(frontend)Pod 需要访问后端(backend)Pod 的 API,你应该为后端服务创建一个 ClusterIP 类型的 Service。前端通过这个 Service 的 ClusterIP 或 DNS 名称(如
http://backend-service.default.svc.cluster.local)来访问后端,而不需要关心后端具体有多少个 Pod 以及它们的 IP 是什么。
YAML 示例:即使不指定
type,它也会被创建为 ClusterIP。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 # 省略即是默认值访问方式:集群内的其他 Pod 或节点可以通过
{service-name}.{namespace}.svc.cluster.local或直接使用 ClusterIP 来访问。
2. NodePort
解释:NodePort 在 ClusterIP 的基础上,在每个集群节点的 IP 上静态暴露一个端口(NodePort)。这样,任何可以通过节点 IP 访问集群的客户端,都可以通过
{NodeIP}:{NodePort}来访问该 Service。工作原理:
K8S 会分配一个 ClusterIP(内部可访问)。
K8S 控制平面会在所有节点上开放一个端口(默认范围是 30000-32767)。
访问任何节点的这个端口的流量,都会被自动转发到 ClusterIP,进而负载均衡到后端 Pod。
用例:
开发测试环境:简单快捷,让你不用配置 LoadBalancer 就能从外部访问服务。
直接暴露节点IP的应用:例如,在一些裸金属部署(Bare Metal)且没有负载均衡器的环境中。
YAML 示例:
apiVersion: v1 kind: Service metadata: name: my-nodeport-service spec: type: NodePort selector: app: my-app ports: - protocol: TCP port: 80 # Service 的端口(ClusterIP 的端口) targetPort: 8080 # Pod 的端口 nodePort: 31000 # (可选) 手动指定节点端口,必须在范围内。不指定则由系统自动分配。访问方式:从集群外部,通过
http://{任意节点IP}:31000访问。
3. LoadBalancer
解释:LoadBalancer 在 NodePort 的基础上,向云服务商(如 AWS, GCP, Azure, 阿里云等)申请一个外部的负载均衡器。这个负载均衡器会自动将流量路由到各个节点的
NodePort。工作原理:
K8S 会分配一个 ClusterIP(内部可访问)。
K8S 会在所有节点上分配一个 NodePort(外部可通过节点访问)。
K8S 会调用云平台的 API,自动创建并配置一个云负载均衡器(如 AWS 的 ELB/ALB、GCP 的 Network Load Balancer)。这个负载均衡器有一个公有的、稳定的 IP 地址。
用例:
生产环境:这是在生产环境中向公网暴露服务的最标准、最可靠的方式。客户端只需访问云负载均衡器的 IP/域名,剩下的由云平台和 K8S 自动处理。
YAML 示例:
apiVersion: v1 kind: Service metadata: name: my-loadbalancer-service spec: type: LoadBalancer selector: app: my-app ports: - protocol: TCP port: 80 targetPort: 8080访问方式:从集群外部,通过云提供商分配的外部负载均衡器 IP 地址(
EXTERNAL-IP)来访问,例如http://{LoadBalancer-IP}:80。
4. ExternalName
解释:这是一种特殊的 Service 类型,它没有选择器 (
selector),也不会创建任何负载均衡或代理机制。它只是简单地将一个集群内部的 Service 映射到一个外部的域名(DNS CNAME 记录)。用例:
访问集群外部的服务:例如,你的 Pod 需要访问一个托管在集群外(如公司老机房、AWS RDS 数据库)的服务
my-database.example.com。你可以创建一个 ExternalName Service,让集群内的应用通过一个稳定的集群内部 DNS 名称(如my-database-service)来访问它,而无需硬编码外部地址。
YAML 示例:
apiVersion: v1 kind: Service metadata: name: my-external-service spec: type: ExternalName externalName: my-database.example.com # 外部域名 # 注意:这里没有 selector 和 ports 定义? # 通常还是会定义 ports,以便其他服务能了解期望的端口 ports: - protocol: TCP port: 3306 # 假设外部服务监听 3306 端口访问方式:集群内的 Pod 通过访问
my-external-service.default.svc.cluster.local,DNS 查询会被重定向到my-database.example.com。
总结与对比
关系递进
你可以将这四种类型看作一个层层递进的关系:
ClusterIP 是基础,提供内部访问。
NodePort 基于 ClusterIP,增加了通过节点IP的访问方式。
LoadBalancer 基于 NodePort,增加了云负载均衡器,提供了最成熟的外部访问方案。
ExternalName 是一个特例,用于将集群内外的网络进行DNS层面的桥接。
在实际生产中,通常不会直接使用 NodePort 对外暴露生产服务,而是使用 LoadBalancer,或者更高级的 Ingress 资源(其背后通常也是一个 LoadBalancer 类型的 Service)来管理外部访问。