Kubernetes Service深度解析:为什么Pod需要稳定接入点

引言:从Pod的脆弱性说起

  • 在Kubernetes中,Pod是部署的最小单位,但它们本质上是短暂且动态的。一个Pod可能因为节点故障、滚动更新或自动扩缩容而在任何时候被销毁和重建,每次重建都会获得新的IP地址。试想一下,如果前端应用直接通过IP连接后端Pod,当后端Pod重启后,前端将完全无法访问服务------这显然是不可接受的。
  • 这就是Kubernetes Service要解决的核心问题:为动态变化的Pod集合提供稳定的网络抽象层

Service的本质:稳定网络抽象

什么是service

Service是Kubernetes中的一种API对象,它定义了一组Pod的逻辑集合和访问这组Pod的策略。简单来说,Service就是:

  • 一个稳定的虚拟IP(ClusterIP)
  • 一个永久的DNS名称
  • 一套智能的负载均衡器

Service的核心价值

bash 复制代码
 # 没有Service:直接访问Pod(易断连)
 前端Pod → 后端Pod IP (10.244.1.2)
 后端Pod重启 → IP变为10.244.1.3  → 连接中断
 ​
 # 有Service:通过稳定端点访问
 前端Pod → Service (clusterIP: 10.200.3.26)
 Service → 后端Pod (负载均衡)  →持续可用

Service的底层工作原理

kube-proxy的两种模式

  • iptables模式(默认)

    • 客户端请求 → iptables规则 → 随机选择的Pod
    • 优点:性能好,规则简单
    • 缺点:连接失败不会重试其他Pod
  • IPVS模式(推荐生产使用)

    • 优点:支持更多负载均衡算法(rr, wrr, lc, wlc等)
    • 优点:更好的性能和可扩展性
  • 启用IPVS模式
bash 复制代码
 #更改kube-proxy配置
 kubectl get configmap kube-proxy -n kube-system -o yaml | \
 sed -e "s/strictARP: false/strictARP: true/"  | \
 sed -e 's#mode: ""#mode: "ipvs"#' | \
 kubectl apply -f - -n kube-system
 ​
 #删除pod使其拉起后生效配置或 kubectl rollout restart
 [root@master51 ~]# kubectl get pods -o wide -n kube-system  -l k8s-app=kube-proxy
 NAME               READY   STATUS    RESTARTS       AGE    IP           NODE        NOMINATED NODE   READINESS GATES
 kube-proxy-66dzn   1/1     Running   2 (3d6h ago)   7d3h   10.0.0.51   master51   <none>           <none>
 kube-proxy-9tjh8   1/1     Running   2 (3d6h ago)   7d3h   10.0.0.52   worker52   <none>           <none>
 kube-proxy-zg282   1/1     Running   0              22h    10.0.0.53   worker53   <none>           <none>
 [root@master51 ~]# 
 [root@master51 ~]# kubectl delete pods -n kube-system  -l k8s-app=kube-proxy
 pod "kube-proxy-66dzn" deleted
 pod "kube-proxy-9tjh8" deleted
 pod "kube-proxy-zg282" deleted
 [root@master51 ~]# 
 [root@master51 ~]# kubectl get pods -o wide -n kube-system  -l k8s-app=kube-proxy
 NAME               READY   STATUS    RESTARTS   AGE   IP           NODE        NOMINATED NODE   READINESS GATES
 kube-proxy-9q28v   1/1     Running   0          3s    10.0.0.52   worker52   <none>           <none>
 kube-proxy-fcp25   1/1     Running   0          3s    10.0.0.51   master51   <none>           <none>
 kube-proxy-n8njm   1/1     Running   0          3s    10.0.0.53   worker53   <none>           <none>
 [root@master51 ~]# 

Endpoint与EndpointSlice

Service通过Endpoints对象跟踪Pod变化

yaml 复制代码
 # 自动生成的Endpoints(若创建带selector的service,系统自动创建Endpoints并持续更新,包含所有匹配 Pod 的 IP:Port;若不带selector,则需要手动创建同名 Endpoints 来定义后端端点。)
 apiVersion: v1
 kind: Endpoints
 metadata:
   name: user-service
 subsets:
 - addresses:
   - ip: 10.100.140.89
   - ip: 10.100.140.90
   - ip: 10.100.203.176
   ports:
   - port: 80

EndpointSlice(K8s 1.21+) :性能更优,支持更多端点

yaml 复制代码
 apiVersion: discovery.k8s.io/v1
 kind: EndpointSlice
 metadata:
   name: user-service
 addressType: IPv4
 ports:
 - name: http
   port: 80
 endpoints:
 - addresses:
   - "10.100.140.89"
   conditions:
     ready: true

DNS解析机制

Service DNS的命名约定:

  • 同一命名空间:<service-name>

  • 跨命名空间:<service-name>.<namespace>.svc.<cluster-domain>

    cluster-domain 默认是cluster.local,在使用kubeadm初始化集群是可以设置:kubeadm init --service-dns-domain=yourdomain.com

bash 复制代码
 # 解析流程
 应用请求 user-service
 → CoreDNS查询
 → 返回ClusterIP (10.200.3.26)
 → 通过kube-proxy路由到具体Pod

Service的四种类型及其应用场景

ClusterIP(默认类型)

  • 最适合内部服务通信
  • 集群IP,一般用于K8S集群内部的服务代理。用于K8S集群内部各个服务之间相互访问。
yaml 复制代码
 apiVersion: v1
 kind: Service
 metadata:
   name: svc-clusterip
 spec:
   # 配置端口映射
   ports:
     # 表示的是service的对外端口
   - port: 90
     # 表示Pod的内部端口
     targetPort: 80
   # 关联Pod的标签
   selector:
     app: web
   # 指定svc的类型,仅集群内部可访问
   type: ClusterIP
   
   
 #测试验证
 [root@master51 ~]# kubectl get svc 
 NAME             TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
 kubernetes       ClusterIP   10.200.0.1     <none>        443/TCP   6d23h
 svc-clusterip      ClusterIP   10.200.3.26    <none>        90/TCP    4s
 ​
 #访问方式
 <cluster-ip>:<port>
 curl 10.200.3.26:90

NodePort

  • 开发测试与简单暴露
  • 在ClusterIP的基础之上,在每一个worker节点添加了NAT规则。从而达到K8S外部客户端能够访问到K8S集群内部的Pod功能。
  • 用于暴露服务到k8s集群集群外部,访问任意一个worker节点都可以访问到k8s集群内部的服务。
yaml 复制代码
 apiVersion: v1
 kind: Service
 metadata:
   name: svc-nodeport
 spec:
   ports:
   - port: 90
     targetPort: 80
     # 指定NodePort的端口范围,默认有效值为: 30000-32767
     nodePort: 30080
   selector:
     app: web
   type: NodePort
   
 #测试验证
 [root@master51 ~]# kubectl get svc 
 NAME                   TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
 kubernetes             ClusterIP   10.200.0.1       <none>        443/TCP        7d
 svc-nodeport   NodePort    10.200.236.205   <none>        90:30080/TCP   4s
 ​
 #访问方式
 集群内部:<cluster-ip>:<port>
 curl 10.200.236.205:90
 集群外部:<node-ip>:<port>
 curl 10.0.0.51:30080
 curl 10.0.0.52:30080
 curl 10.0.0.53:30080

修改Service的nodePort端口号范围

bash 复制代码
 #修改静态Pod的资源清单 
 [root@master51 ~]# vim /etc/kubernetes/manifests/kube-apiserver.yaml 
 ...
  12 spec:
  13   containers:
  14   - command:
  15     - kube-apiserver
  16     - --service-node-port-range=3000-50000
  
 #移出再移回使其更快加载
 [root@master51 ~]# mv /etc/kubernetes/manifests/kube-apiserver.yaml /opt/
 [root@master51 ~]# mv /opt/kube-apiserver.yaml /etc/kubernetes/manifests/
 ​
 #验证查看组件是否正常
 [root@master51 ~]# kubectl get pods -n kube-system -o wide -l component=kube-apiserver
 NAME                       READY   STATUS    RESTARTS      AGE   IP           NODE        NOMINATED NODE   READINESS GATES
 kube-apiserver-master51   1/1     Running   1 (13s ago)   8s    10.0.0.51   master51   <none>           <none>
 [root@master51 ~]# 
 ​
 #最后创建service验证即可

Loadbanlacer

  • 云原生应用的标配
  • 一般情况下是用于云厂商环境,配合专门的SLB相关产品进行服务的代理。如果自行部署的k8s需要单独部署第三方插件(如:metallb)来实现此功能,详细可参考:juejin.cn/post/759508...
  • LoadBalancer与NodePort的本质区别在于流量的智能化路由。 NodePort虽然提供了外部访问入口,但它只是一个静态的端口映射。客户端必须指定某个具体节点的IP,如果该节点故障,需要人工干预切换流量。 而LoadBalancer则提供了一个完全抽象的"虚拟IP"(VIP)。会自动将流量分发到所有健康的节点,并在节点故障时立即从后端池(NodeIP+NodePort)中移除该节点,实现全自动的高可用。
yaml 复制代码
 apiVersion: v1
 kind: Service
 metadata:
   name: svc-loadbalancer
 spec:
   selector:
     app: web
   ports:
   - port: 90          #service端口(集群内:clusterIP:90)
     targetPort: 80    #pod端口
     #当type为LoadBalancer时,如果不指定nodePort,K8s会自动分配一个(默认范围30000-32767)
     nodePort: 30080    #节点端口(集群外:nodeIP:30080)
   type: LoadBalancer

ExternalName

  • 连接外部服务的桥梁
  • 主要应用在将K8S集群外部的某个服务映射到K8S集群内部的Service,为外部服务提供统一的Kubernetes服务发现接口,这样可以不需要记住外部服务的地址
yaml 复制代码
 apiVersion: v1
 kind: Service
 metadata:
   name: svc-externalname
 spec:
   externalName: www.baidu.com
   #externalName:myproductiondatabase.example.com
   ports:
   - port: 80
   type: ExternalName
   
   
 #测试验证
 #查看DNS服务器IP
 [root@master51 ~]# kubectl get svc,po -n kube-system -l k8s-app=kube-dns -o wide
 NAME               TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)                  AGE    SELECTOR
 service/kube-dns   ClusterIP   10.200.0.10   <none>        53/UDP,53/TCP,9153/TCP   7d5h   k8s-app=kube-dns
 ​
 NAME                          READY   STATUS    RESTARTS   AGE   IP               NODE        NOMINATED NODE   READINESS GATES
 pod/coredns-6d8c4cb4d-bzggh   1/1     Running   0          28h   10.100.160.135   master51   <none>           <none>
 pod/coredns-6d8c4cb4d-l6vfm   1/1     Running   0          28h   10.100.160.133   master51   <none>           <none>
 ​
 ​
 [root@master51 ~]# kubectl get svc
 NAME                       TYPE           CLUSTER-IP       EXTERNAL-IP     PORT(S)        AGE
 kubernetes                 ClusterIP      10.200.0.1       <none>          443/TCP        7d
 svc-externalname           ExternalName   <none>           www.baidu.com   80/TCP         3s
 ​
 #验证ExternalName
 [root@master51 ~]# dig @10.200.0.10 svc-externalname.default.svc.geniusc.com +short
 www.baidu.com.
 www.a.shifen.com.
 110.242.70.57
 110.242.69.21
 ​

CoreDNS组件补充

  • CoreDNS是K8S集群内置的DNS服务器,如果是kubeadm方式部署的话,无需手动部署该组件,但二进制部署的话需要手动部署该组件。
  • CoreDNS的作用就是将svc的名称解析为CLusterIP,也可以实现Pod的负载均衡,还可以为ExternalName提供地址解析功能。
相关推荐
Hui Baby2 小时前
K8S CCM简介
云原生·容器·kubernetes
molaifeng2 小时前
Token:AI 时代的数字货币——从原理到计费全解
人工智能·ai·大模型·llm·go·token
星环处相逢2 小时前
Kubernetes PV 与 PVC 深度解析:从基础存储到动态部署实战
云原生·容器·kubernetes
ICT董老师2 小时前
在Ubuntu 22.04上使用GitLab和Jenkins部署CI/CD的完整过程
ubuntu·ci/cd·kubernetes·gitlab·jenkins
ζั͡山 ั͡有扶苏 ั͡✾2 小时前
K8s 集群内存压力检测和智能 Pod 驱逐工具
云原生·容器·kubernetes
腾讯数据架构师2 小时前
k8s兼容昆仑芯p800
人工智能·云原生·容器·kubernetes·cube-studio·昆仑芯
风一样的男子&3 小时前
kylin桌面版v10安装docker和k8s
docker·kubernetes·kylin
努力搬砖的咸鱼3 小时前
为什么需要 Kubernetes
微服务·云原生·容器·kubernetes
oMcLin13 小时前
如何在 Ubuntu 22.10 上通过 Kubernetes 和 Helm 管理微服务应用,简化跨平台电商平台的自动化部署?
ubuntu·微服务·kubernetes