kubernetes(k8s)-Service
Service 是 K8s 中一个至关重要、不可或缺的核心概念。
Service 是 Kubernetes 中用于定义一组 Pod 的访问策略的抽象层。它充当了这组 Pod 的稳定入口点,为它们提供可靠的网络标识和负载均衡。
核心问题:为什么需要 Service?
Pod 是短暂的:Pod 可能会因为节点故障、滚动更新、扩缩容等原因被销毁和重建。每次重建都会获得一个新的 IP 地址(动态 IP)。
Pod 是动态的:你通过 Deployment 等控制器运行了 3 个 Pod,前端应用如何知道这 3 个 Pod 的 IP 地址?即使知道了,当 Pod 数量发生变化时,前端如何感知?
负载均衡需求:流量需要被均匀地分发到后端多个健康的 Pod 实例上。
Service 就是为了解决这些问题而生的,它的主要作用如下:
一、主要作用
1、服务发现
- Service 通过 Label Selector 动态地识别属于它的 Pod。
- 它为这组 Pod 提供一个唯一的、稳定的 虚拟 IP(VIP) 和 DNS 名称。其他应用只需要访问这个固定的 VIP 或 DNS 名,而无需关心后端具体有哪些 Pod 以及它们的 IP 是什么。
2、负载均衡
- 当有请求到达 Service 的虚拟 IP 时,Service 会自动将流量均匀地分发到后端所有健康的 Pod 上。
3、解耦
- 实现了前端应用(客户端)与后端 Pod(服务端)的解耦。前端不需要知道后端的任何变化,它只认准 Service 这个稳定的入口。
二、Service 的类型
Kubernetes 提供了四种主要的 Service 类型,用于不同的暴露场景:
1、ClusterIP(默认)
- 作用:为 Service 分配一个集群内部的虚拟 IP。这个 IP 只能在集群内部访问。
- 场景:用于微服务间的内部通信。例如,前端 Pod 需要访问后端 API Service。
2、NodePort
- 作用:在 ClusterIP 的基础上,在每个 Node 的 IP 上暴露一个静态端口(
NodePort,范围 30000-32767)。这样,集群外部的客户端可以通过<NodeIP>:<NodePort>来访问 Service。 - 场景:用于开发、测试环境,或者需要直接从集群外部访问的简单应用。
3、LoadBalancer
- 作用:在 NodePort 的基础上,利用云服务商(如 AWS、GCP、Azure)提供的外部负载均衡器。云商会自动分配一个外部 IP,并将流量转发到 Service。
- 场景:在公有云上运行生产环境服务,需要对外提供服务的标准方式。
4、ExternalName
- 作用:将 Service 映射到一个外部域名(例如
my.database.example.com)。它通过返回一个CNAME记录来实现。 - 场景:让你在集群内部能够像访问内部服务一样访问集群外部的服务。
三、核心机制详解
1、Label Selector(标签选择器)
这是 Service 与 Pod 关联的纽带。Service 通过 selector 字段中定义的标签来查找目标 Pod。
selector:app: my-apptier: backend这个选择器会找到所有拥有 app=my-app 和 tier=backend 标签的 Pod。
2、Endpoints(端点)
当你创建一个 Service 时,Kubernetes 会自动创建一个与 Service 同名的 Endpoints 对象。这个对象是一个动态的列表,里面记录了所有匹配 Service Selector 的健康 Pod 的 IP 地址和端口。
你可以通过以下命令查看:
kubectl get endpoints <service-name>Service 的流量正是被转发到 Endpoints 列表中列出的 Pod IP。
3、kube-proxy 与流量转发
每个 Node 上都运行着一个 kube-proxy 组件,它负责实现 Service 的虚拟 IP 机制。当创建 Service 时,kube-proxy 会通过 API Server 监听到变化,并在本机配置相应的转发规则(如 iptables/IPVS 规则),将目标为 Service VIP 的流量透明地转发到后端真实的 Pod IP。
四、案例演示
让我们通过几个具体的 YAML 示例来理解不同类型的 Service。
场景准备:先部署后端 Pod
我们首先创建一个 Deployment,它管理着 3 个 Nginx Pod。
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: my-nginx
spec:selector:matchLabels:app: nginxreplicas: 3template:metadata:labels:app: nginx # 这个标签会被 Service 的 selector 使用spec:containers:- name: nginximage: nginx:alpineports:- containerPort: 80应用它:kubectl apply -f deployment.yaml
案例 1:ClusterIP Service(内部访问)
service-clusterip.yaml
apiVersion: v1
kind: Service
metadata:name: my-nginx-service-clusterip
spec:type: ClusterIP # 此项可省略,因为它是默认值selector:app: nginx # 选择器:匹配所有带有 `app: nginx` 标签的 Podports:- protocol: TCPport: 80 # Service 自己监听的端口targetPort: 80 # 后端 Pod 的端口应用它:kubectl apply -f service-clusterip.yaml
验证与访问:
1、查看 Service:
kubectl get svc my-nginx-service-clusterip
# 输出类似:
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# my-nginx-service-clusterip ClusterIP 10.96.123.456 <none> 80/TCP 30s这里 10.96.123.456 就是稳定的集群内虚拟 IP。
2、查看 Endpoints:
kubectl get endpoints my-nginx-service-clusterip
# 输出会显示 3 个 Pod 的 IP 地址。
3、在集群内部访问:
我们可以在集群内临时启动一个 Pod 来测试访问:
kubectl run test-pod --image=busybox --rm -it --restart=Never -- sh
# 在 Kubernetes 中启动一个临时 Pod(使用 busybox 镜像),进入交互式 Shell 进行调试,退出后自动删除 Pod。在 test-pod 的 shell 中,执行:
wget -q -O - http://10.96.123.456:80
# 或者使用 DNS 名称!在同一个命名空间内,可以直接用 Service 名:
wget -q -O - http://my-nginx-service-clusterip:80
# 如果不在同一个命名空间,需要使用全限定域名:
# wget -q -O - http://my-nginx-service-clusterip.<namespace>.svc.cluster.local:80你应该能看到 Nginx 的欢迎页面。多次执行,请求会被负载均衡到不同的 Pod 上。
案例 2:NodePort Service(外部通过节点IP访问)
service-nodeport.yaml
apiVersion: v1
kind: Service
metadata:name: my-nginx-service-nodeport
spec:type: NodePortselector:app: nginxports:- protocol: TCPport: 80targetPort: 80# nodePort: 30007 # 可以手动指定端口,如果不指定,K8s 会在 30000-32767 间自动分配应用它:
kubectl apply -f service-nodeport.yaml验证与访问:
1、查看 Service:
kubectl get svc my-nginx-service-nodeport
# 输出类似:
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# my-nginx-service-nodeport NodePort 10.96.234.123 <none> 80:30568/TCP 20s这里 30568 就是自动分配的 NodePort。
2、从集群外部访问:
打开你的浏览器,访问 <任何一个Node的IP地址>:30568。
例如,如果你的 Minikube IP 是 192.168.49.2,那么就访问 http://192.168.49.2:30568。
同样,你应该能看到 Nginx 页面,并且流量被负载均衡。
案例 3:LoadBalancer Service(云环境外部访问)
service-loadbalancer.yaml
apiVersion: v1
kind: Service
metadata:name: my-nginx-service-loadbalancer
spec:type: LoadBalancerselector:app: nginxports:- protocol: TCPport: 80targetPort: 80在支持云负载均衡器的环境中(如 GKE、EKS、AKS),应用这个 YAML 后:
1、查看 Service:
kubectl get svc my-nginx-service-loadbalancer
# 输出类似(以 AWS 为例):
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# my-nginx-service-loadbalancer LoadBalancer 10.96.123.456 a1b2c3d4e5f6g7h8.us-west-2.elb.amazonaws.com 80:32345/TCP 2mEXTERNAL-IP 字段会变成一个由云厂商提供的外部域名或 IP。
2、从集群外部访问:
直接在浏览器中访问 http://a1b2c3d4e5f6g7h8.us-west-2.elb.amazonaws.com 即可。
总结
| 特性 | ClusterIP | NodePort | LoadBalancer |
|---|---|---|---|
| 访问范围 | 集群内部 | 集群外部(通过 NodeIP) | 互联网(通过云LB) |
| IP类型 | 集群内虚拟 IP | 集群内虚拟 IP + 节点 IP | 集群内虚拟 IP + 节点 IP + 云外部 IP |
| 适用场景 | 微服务内部通信 | 开发、测试、简单外部访问 | 云上生产环境 |
| 依赖 | kube-proxy | kube-proxy, 节点网络 | kube-proxy, 节点网络, 云提供商 |
Service 是 Kubernetes 服务发现的基石。它通过一个稳定的抽象层,屏蔽了后端 Pod 的动态性和复杂性,为构建可靠、可扩展的分布式应用提供了关键支撑。在实际生产中,通常将 Ingress(7层路由) 与 Service(4层负载均衡) 结合使用,由 Ingress 接收外部 HTTP/HTTPS 流量,再根据规则转发给后端的不同 Service。
