Kubernetes从入门到精通-服务发现Service

发布于:2025-07-01 ⋅ 阅读:(17) ⋅ 点赞:(0)

一、为什么需要 Service?

  • Pod 的动态性: Pod 是 Kubernetes 调度的基本单位。它们可能因为故障、滚动更新、扩缩容等原因随时被创建或销毁。

  • Pod IP 的不稳定性: 每个 Pod 都有自己的 IP 地址,但当 Pod 重建时,IP 地址会改变。

  • 访问需求: 集群内部的其他应用(前端访问后端)、集群外部用户(访问 Web 应用)需要一种稳定可靠的方式来访问一组提供相同功能的 Pod。

二、Service 是什么?

1.定义

       Service 是 Kubernetes 中的一个 API 对象,它定义了一组 Pod 的逻辑集合以及访问这组 Pod 的策略(通常通过标签选择器 selector)。service主要解决Pod的动态变化,提供统一的访问入口。

2.核心功能

  • 稳定访问端点: 为动态变化的 Pod 集合提供一个虚拟的、稳定的 IP 地址 (ClusterIP) 或 DNS 名称。

  • 负载均衡: 基于iptables或者ipvs,将到达 Service 的请求自动分发到其后端健康的 Pod 上。

  • 服务发现:基于标签管理器关联后端的Pod列表 让其他应用能够轻松地找到并连接到这组 Pod。

3.endpoints对象

       由 Kubernetes 自动创建和管理(通常无需手动操作),与同名的 Service 关联,存储了当前匹配 Service 标签选择器的所有健康 Pod 的 IP:Port 列表,Service 的负载均衡器就是基于这个列表进行流量转发的

三、service类型以及是用场景

1.ClusterIP

1.1 用途

       默认类型,为 Service 分配一个集群内部的虚拟 IP (VIP),仅限集群内部的其他 Pod 或 Service 访问,用于后端服务间的内部通信(如前端访问后端 API、数据库访问)。

1.2 示例代码
[root@master-1 service]# cat 01-svc-ClusterIP.yaml 
apiVersion: v1
kind: Service
metadata:
  name: myweb-service
spec:
   # 声明Service的类型,主要有:ClusterIP, NodePort, LoadBalancer.
   #    ClusterIP:
   #       k8s集群内部使用的类型,仅供K8S集群内部访问,外部无法访问。默认值。
   #    NodePort:
   #       在ClusterIP基础之上,监听了所有的worker节点的端口号,可供K8s集群外部访问。
   #    LoadBalancer:
   #       适合在公有云上对k8s集群外部暴露应用。
  type: ClusterIP
  # 声明标签选择器,即该svc资源关联哪些Pod,并将其加入到ep列表
  selector:
    apps: web
  # 配置端口映射
  ports:
    # 指定Service服务本身的端口号
  - port: 8888
    # 后端Pod提供服务的端口号
    targetPort: 80
[root@master-1 service]# cat nginx.yaml 
apiVersion: apps/v1
kind: Deployment            
metadata:
  name: nginx
spec:
  replicas: 3
  #基于标签关联pod,会关联apps=test或者apps=prod的pod
  selector:
    matchExpressions:
    - key: apps
      values: 
      - "test"
      - "web"
      operator: In
  template:
    metadata:
      #为pod设置了两个标签
      labels:
        apps: web
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        imagePullPolicy: IfNotPresent

#部署
[root@master-1 service]# kubectl apply -f .
#查看pod,service,endpoints
[root@master-1 service]# kubectl get pods,svc,endpoints -o wide
1.3 验证结果

       如图所示,该Service自动生成了集群内部专用的虚拟IP地址(ClusterIP)和端口。

       使用该ClusterIP地址(10.0.0.69:8888)成功访问到了集群内部署的Web业务服务。

2. NodePort

2.1 用途

       k8s集群外部访问,NodePort机制在ClusterIP基础上,将服务以<节点IP>:<静态端口>的形式暴露到集群外部,该端口可自动分配(30000-32767)或手动指定。端口范围可以在api-server中查看。

查看端口范围:

2.2 示例代码
[root@master-1 service]# cat 02-svc-NodePort.yaml 
apiVersion: v1
kind: Service
metadata:
  name: myweb-nodeport
spec:
  # 指定svc的类型为NodePort,也就是在默认的ClusterIP基础之上多监听所有worker节点的端口而已。
  type: NodePort
  # 基于标签选择器关联Pod
  selector:
    apps: web
  # 配置端口映射
  ports:
    # 指定Service服务本身的端口号
  - port: 8888
    # 后端Pod提供服务的端口号
    targetPort: 80
    # 如果是NodePort类型,可以指定NodePort监听的端口号,若不指定,则随机生成。
    nodePort: 30080
    #端口范围以上提供了查询方法,可以修改,修改api-server启动时的参数.
    #nodePort: 8080

#部署
[root@master-1 service]# kubectl apply -f 02-svc-NodePort.yaml
service/myweb-nodeport created
#查看
[root@master-1 service]# kubectl get pods,svc,endpoints -o wide

2.3 验证结果

       如图所示,该Service除了创建集群内部的ClusterIP和端口外,还开放了指定的NodePort端口30080用于外部访问。

       通过任意节点IP加NodePort端口(如192.168.91.21:30080)均可成功访问部署的Web业务服务。

     通过外部浏览器访问(http://192.168.91.22:30080/),也可以成功访问到web业务。

3.LoadBalance

3.1 用途

       在 NodePort 基础上,利用云提供商的基础设施(如 AWS ELB, GCP Load Balancer, Azure LB)自动创建一个外部负载均衡器。该负载均衡器会将外部流量导向 NodePort Service (进而到 Pod)。通常用于公有云上向公网暴露服务。

3.2 示例代码
#01 创建loadbalancer的service
[root@master-1 service]# cat 03-services-LoadBalance.yaml 
kind: Service
apiVersion: v1
metadata:
  name: svc-loadbalancer
spec:
  # 指定service类型为LoadBalancer,注意,一般用于云环境
  type: LoadBalancer
  selector:
     app: web
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
    nodePort: 30080

#02 配置云环境的应用负载均衡器
#添加监听器规则,比如访问负载均衡器的80端口,反向代理到30080端口。
#简而言之,就是访问云环境的应用服务器的哪个端口,把他反向代理到K8S集群的node端口为30080即可。

#03 用户访问应用负载均衡器的端口
#用户直接访问云环境应用服务器的80端口即可,请求会自动转发到云环境nodePort的30080端口。

4.ExternalName

4.1 用途

       将 Service 映射到一个外部 DNS 名称 (如 my.database.example.com)。不创建任何代理或负载均衡。通过访问该 Service 的 DNS 名称,解析到外部服务的 DNS 名称。

4.2 示例代码
[root@master-1 service]# cat 04-svc-ExternalName.yaml 
apiVersion: v1
kind: Service
metadata:
  name: svc-externalname
spec:
  # svc类型
  type: ExternalName
  # 指定外部域名
  externalName: www.baidu.com

[root@master-1 service]# kubectl apply -f 04-svc-ExternalName.yaml
[root@master-1 service]# kubectl get svc svc-externalname
NAME               TYPE           CLUSTER-IP   EXTERNAL-IP     PORT(S)   AGE
svc-externalname   ExternalName   <none>       www.baidu.com   <none>    98s

#启动容器后访问名为"svc-externalname"的svc,请求会被cname到"www.baidu.com"的A记录

5.类型对比

类型 访问范围 适用场景 依赖条件
ClusterIP 仅集群内部 微服务间通信
NodePort 集群外部 开发测试/临时暴露 节点防火墙开放端口
LoadBalancer 公网访问 生产环境云集群 云厂商支持
ExternalName 集群内部 集成外部服务(如RDS) DNS 插件

四、 Service底层原理

1. Service 工作流程

  • Endpoint 控制器:监控 Pod 状态,更新 Service 关联的 Endpoints 列表。

  • kube-proxy:监听 Service/Endpoint 变化,生成代理规则。

  • 流量转发

    • iptables 模式:默认,通过 NAT 规则转发(适合小规模集群)。

    • IPVS 模式:基于哈希表,支持 RR/LC/WRR 等算法,万级服务性能更优。

2.kube-proxy的工作模式

2.1 定义

   kube-proxy 是运行在每个 Node 上的网络代理组件,是实现集群内部的服务发现和负载均衡的关键。它监听 API Server 的 Service 和 Endpoint 变化,并配置本机的网络规则将流量路由到正确的后端 Pod。kube-proxy 支持多种工作模式,每种模式都有其特点和适用场景。

2.2 工作模式
01 iptables 模式 (默认)

工作流程:

  • kube-proxy 使用 iptables 规则配置 Linux 内核的 netfilter 包过滤框架。
  • 当请求到达 Service 的 ClusterIP:Port 时,iptables 规则会进行 DNAT (目标地址转换),将目标 IP:Port 修改为随机选择的一个后端 Pod 的 IP:Port。

优点: 效率高,工作在操作系统内核层。

缺点:

  • 规则数量庞大(尤其是 Service 和 Pod 很多时),可能影响性能。
  • 负载均衡算法单一(默认是随机)。
  • 不支持更高级的负载均衡策略(如会话保持、最少连接)。
  • 如果第一个选中的 Pod 无响应,不会自动重试其他 Pod(除非应用层重试)。

02 ipvs 模式 (推荐)

       kube-proxy 使用 Linux 内核的 IP Virtual Server 模块,IPVS 是 L4 负载均衡器,专门设计用于高性能负载均衡。

优点:

  • 性能最高: 比 iptables 模式具有更低的延迟和更高的吞吐量,尤其在大规模集群中优势明显。
  • 支持多种负载均衡算法: rr (轮询), lc (最少连接), dh (目标地址哈希), sh (源地址哈希), sed (最短预期延迟), nq (永不排队)。
  • 支持会话保持: 通过 sh (源地址哈希) 算法实现。

  • 更高效的数据结构: 规则数量与 Service/Endpoint 数量呈线性关系,而非像 iptables 那样可能是指数关系。

缺点:

  • 需要 Linux 内核支持 IPVS 模块 (现代内核通常已支持)。
03 工作模式切换
#修改kube-proxy配置文件
[root@node-1 ~]# cat >/etc/kubernetes/cfg/kube-proxy.yaml<<EOF
apiVersion: kubeproxy.config.k8s.io/v1alpha1
bindAddress: 192.168.91.21
clientConnection:
  kubeconfig: /etc/kubernetes/cfg/kube-proxy.kubeconfig
clusterCIDR: 10.0.0.0/24
healthzBindAddress: 192.168.91.21:10256
kind: KubeProxyConfiguration
metricsBindAddress: 192.168.91.21:10249
mode: "ipvs"
EOF

#切换工作模式mode: "ipvs" 或者 mode: "iptables"
#修改完后重启kube-proxy
[root@node-1 bin]# systemctl restart kube-proxy 

      重启后重新部署web应用,如下图,发现service基于rr轮询的方式分发流量到pod

五、常见问题排查

1.无法通过 Service 访问 Pod

  • 检查 Service selector 是否与 Pod labels 匹配 。

kubectl describe svc <service-name>
kubectl get pods --show-labels
  • 检查 Endpoints 对象是否包含预期的 Pod IP,空的 Endpoints 意味着 selector 不匹配或 Pod 未就绪 (readinessProbe 失败)。
kubectl get endpoints <service-name>
  • 检查 Pod 是否正常运行且监听目标端口
kubectl logs <pod-name>
kubectl exec -it <pod-name> -- netstat -tuln 
kubectl exec -it <pod-name> -- ss -tuln
  • 检查 Pod 的 readinessProbe 是否配置正确且通过。
  • 检查 kube-proxy 是否在所有节点正常运行。
systemctl status kube-proxy 
kubectl get pods -n kube-system -l component=kube-proxy
  • 检查节点防火墙规则 (如果使用 iptables/ipvs 模式)。

2.NodePort 无法从外部访问

  • 检查 NodePort Service 是否已创建 
#看 PORT(S) 列是否有 80:3xxxx/TCP
kubectl get svc -A
  • 确认使用的 Node IP 和 NodePort 正确。

  • 检查节点的防火墙/安全组是否允许外部访问该 NodePort。

  • 检查 kube-proxy 是否在节点上正常运行

六、总结

优先使用 DNS 进行服务发现:避免环境变量的顺序依赖问题。

内部服务使用 ClusterIP:除非有特殊需求,否则这是最安全、最标准的内部通信方式

外部访问:

  • 开发/测试:NodePort
  • 公有云生产环境:LoadBalancer (通常配合 Ingress Controller 处理 L7 流量)。
  • 需要暴露多个 HTTP 服务:使用 Ingress + ClusterIP Service。

使用 ipvs 代理模式: 尤其是在大型集群或需要高性能、多种负载均衡算法、会话保持时。

合理使用 Headless Service 主要用于 StatefulSets 或需要直接访问所有 Pod IP 的场景。

配置 readinessProbe 确保 Service 只将流量路由到真正准备好接收请求的 Pod。

利用 Network Policies: 在 Service 之上实施网络层面的安全控制。

监控: 监控 Service 的 Endpoints 变化、DNS 解析延迟、kube-proxy 状态等。