总结:

  1. Service类型决定了客户访问Service的方法
  2. Kube-proxy工作模式是service实现代理时的底层实现方式
  • service作用

使用kubernetes集群运行工作负载时,由于Pod经常处于用后即焚状态,Pod经常被重新生成,因此Pod对应的IP地址也会经常变化,导致无法直接访问Pod提供的服务,

Kubernetes中使用了Service来解决这一问题,即在Pod前面使用Service对Pod进行代理,无论Pod怎样变化 ,只要有Label,就可以让Service能够联系上Pod,把PodIP地址添加到Service对应的端点列表(Endpoints)实现对Pod IP跟踪,进而实现通过Service访问Pod目的。

  • 通过service为pod客户端提供访问pod方法,即客户端访问pod入口
  • 通过标签动态感知pod IP地址变化等
  • 防止pod失联
  • 定义访问pod访问策略
  • 通过label-selector相关联
  • 通过Service实现Pod的负载均衡(TCP/UDP 4层)
  • 底层实现由kube-proxy通过userspace、iptables、ipvs三种代理模式完成

举例:

apiVersion: apps/v1

kind: Deployment

metadata:

  name: nginx1

spec:

  replicas: 3

  selector:

    matchLabels:

      app: nginx

  template:

    metadata:

      labels:

        app: nginx

    spec:

      containers:

        - name: nginx

          image: nginx:1.20

          ports:

            - containerPort: 80

---

apiVersion: v1

kind: Service

metadata:

  name: test-svc

spec:

  type: NodePort

  selector:

    app: nginx

  ports:

    - protocol: TCP

      port: 1000

      targetPort: 80

      nodePort: 32034

  1. 中的 kube-proxy 是一个网络代理,负责为集群中的服务提供网络转发。

  • userspace、iptables 和 ipvs。下面用通俗的例子来解释这三种模式。

  1. Userspace 模式

  • kube-proxy)负责把你的订单(网络请求)交给厨师(后端 Pod)。服务员需要亲自跑到厨房,把订单交给厨师,然后再把做好的菜端给你。这个过程比较慢,因为服务员需要来回跑动。

  • userspace 模式下,kube-proxy 在用户空间处理网络请求,数据包需要从内核空间传到用户空间,再由 kube-proxy 转发到后端 Pod。这种模式效率较低,因为数据包需要在用户空间和内核空间之间来回传递。

  1. iptables 模式

  • iptables)。你点餐后,订单通过传送带直接送到厨师那里,厨师做好菜后也通过传送带直接送到你桌上。服务员只需要确保传送带正常工作。

  • iptables 模式下,kube-proxy 通过配置 iptables 规则来实现网络转发。数据包直接在内核空间处理,不需要经过用户空间,效率更高。kube-proxy 只需要负责更新 iptables 规则,不需要亲自处理每个数据包。

  1. ipvs 模式[华王1] 

  • ipvs)。这个系统可以根据厨师的工作负载,自动把订单分配给最空闲的厨师,确保每道菜都能快速做好并送到你桌上。

  • ipvs 模式下,kube-proxy 使用 Linux 内核的 IP Virtual Server(IPVS)功能来实现负载均衡。IPVS 提供了更高效的负载均衡算法,能够根据后端 Pod 的负载情况动态调整流量分配。这种模式性能最好适合大规模集群

  • Userspace 模式:服务员亲自跑腿,效率低。
  • iptables 模式:使用传送带自动送餐,效率较高。
  • ipvs 模式:引入智能调度系统,效率最高,适合大规模集群。

  • iptables 和 ipvs 是更常用的模式,尤其是 ipvs,因为它提供了更好的性能和可扩展性。

注:使用iptables与ipvs时机

1.10版本之前使用iptables(1.1版本之前使用UserSpace进行转发)

1.11版本之后同时支持iptables与ipvs,默认使用ipvs,如果ipvs模块没有加载时,会自动降级至iptables

 

修改kube-proxy的工作模式

# 查看configmap

[root@master01 ~]# kubectl -n kube-system describe cm kube-proxy  | grep mode

 修改configmap

[root@master01 ~]#kubectl -n kube-system edit cm kube-proxy            

 mode: "ipvs"

重启damonset控制器

[root@master01 ~]# kubectl -n kube-system rollout restart daemonset kube-proxy

再次查看configmap

[root@master01 ~]# kubectl -n kube-system describe cm kube-proxy  | grep mode

  • service类型

Service类型决定了访问Service的方法

3.1 service类型

  • ClusterIP
    • 默认,分配一个集群内部可以访问的虚拟IP
  • NodePort
    • 在每个Node上分配一个端口作为外部访问入口
    • nodePort端口范围为:30000-32767
  • LoadBalancer
    • 工作在特定的Cloud Provider上,例如Google Cloud,AWS,OpenStack
  • ExternalName
    • 表示把集群外部的服务引入到集群内部中来,即实现了集群内部pod和集群外部的服务进行通信

3.2 Service参数

  • port 访问service使用的端口
  • targetPort Pod中容器暴露端口
  • nodePort 通过Node实现外网用户访问k8s集群内service的端口 (30000-32767)

Service的创建在工作中有两种方式

一是命令行创建

二是通过资源清单文件YAML文件创建。

4.1 ClusterIP分类

ClusterIP根据是否生成ClusterIP又可分为普通Service和Headless Service

Service两类:

  • 普通Service:

为Kubernetes的Service分配一个集群内部可访问的固定虚拟IP(Cluster IP), 实现集群内的访问。

  • Headless Service[华王2] (无头服务,无群集ip):  用在内部的不公开的域名访问

该服务不会分配Cluster IP, 也不通过kube-proxy做反向代理和负载均衡。而是通过DNS提供稳定的网络ID来访问,DNS会将headless service的后端直接解析为pod IP列表。

4.1.1 普通ClusterIP Service创建

4.1.1.1 命令行创建Service

创建Deployment类型的应用

[root@master01 ~]# vim nginx1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-server1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
1
  template:
     metadata:
       labels:
         app: nginx
1
     spec:
       containers:
       - name: c1
         image: nginx:
1.20
         imagePullPolicy: IfNotPresent
         ports:
         - containerPort: 80

应用资源清单文件

[root@master01 ~]# kubectl apply -f nginx1.yaml

验证Deployment类型的创建情况

[root@master01 ~]# kubectl get deployment.apps

[root@master01 ~]# kubectl get pod -o wide

[root@master01 ~]# curl 10.244.5.7   (pod ip地址)

可查看到网页内容

创建ClusterIP类型service与Deployment类型应用关联

命令创建service


[root@master01 ~]# kubectl expose deployment.apps nginx-server1 --type=ClusterIP --target-port=80 --port=80

说明:
expose 创建service
deployment.apps 控制器类型
nginx-server1 应用名称,也是service名称
--type=ClusterIP 指定service类型
--target-port=80 指定Pod中容器端口
--port=80 指定service端口

[root@master01 ~]# kubectl get service nginx-server1

[root@master01 ~]# curl 10.103.253.214   (ClusterIP 群集IP)

4.1.1.2 通过资源清单文件创建Service

[root@master01 ~]# vim nginx-server2.yaml


apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-server
2
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
2
  template:
     metadata:
       labels:
         app: nginx
2
     spec:
       containers:
       - name: nginx
2
         image: nginx:1.20
         imagePullPolicy: IfNotPresent
         ports:
         - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-
server2
spec:
  type: ClusterIP
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80
  selector:
    app: nginx
2

[root@master01 ~]# kubectl delete all --all

[root@master01 ~]# kubectl  apply -f nginx-server2.yaml

查看service
[root@master01 ~]# kubectl get service

查看endpoints


[root@master01 ~]# kubectl get endpoints

4.1.1.3 访问

[root@master01 ~]# curl 10.98.242.254

可看到网页内容

4.1.1.4 两个pod里做成不同的主页方便测试负载均衡

[root@master01 ~]#  kubectl get pod -o wide

[root@master01 ~]# kubectl exec -it nginx-server2-5f644dc499-62xmk -- bash

root@nginx-server2-5f644dc499-62xmk:/# cd /usr/share/nginx/html/

root@nginx-server2-5f644dc499-62xmk:/usr/share/nginx/html# echo web1 > index.html

root@nginx-server2-5f644dc499-62xmk:/usr/share/nginx/html# exit

[root@master01 ~]# kubectl exec -it nginx-server2-5f644dc499-62xmk -- bash

root@nginx-server2-5f644dc499-62xmk:/# cd /usr/share/nginx/html/

root@nginx-server2-5f644dc499-62xmk:/usr/share/nginx/html# echo web2 > index.html

root@nginx-server2-5f644dc499-62xmk:/usr/share/nginx/html# exit

exit

4.1.1.5 测试

[root@master01 ~]# curl 10.98.242.254

web2

[root@master01 ~]# curl 10.98.242.254

web1

4.1.2 Headless Service

  • 普通的ClusterIP service是service name解析为cluster ip,然后cluster ip对应到后面的pod ip
  • Headless service是指service name 直接解析为后面的pod ip
4.1.2.1 编写用于创建Deployment控制器类型的资源清单文件

[root@master01 ~]# vim nginx-server3.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-server
3
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
3
  template:
     metadata:
       labels:
         app: nginx
3
     spec:
       containers:
       - name: nginx-smart
         image: nginx:
1.20
         imagePullPolicy: IfNotPresent
         ports:
         - containerPort: 80

[root@master01 ~]# kubectl apply -f nginx-server3.yaml

4.1.2.2 通过资源清单文件创建headless Service

[root@master ~]# vim headless-service.yml
apiVersion: v1
kind: Service
metadata:
  name: headless-service
  namespace: default
spec:

  type: ClusterIP     # ClusterIP类型,也是默认类型
  clusterIP: None     # None就代表是无头service
  ports:                    
  - port: 80                      
    protocol: TCP
    targetPort: 80       
  selector:                      
     app: nginx
3       

4.1.2.3 应用资源清单文件创建headless Service


[root@master ~]# kubectl apply -f headless-service.yml
 

4.1.2.4 查看已创建的headless Service

[root@master01 ~]# kubectl get svc

可以看到headless-service没有CLUSTER-IP,用None表示

[root@master01 ~]# kubectl get endpoints

4.1.2.5 DNS

DNS服务监视Kubernetes API,为每一个Service创建DNS记录用于域名解析

headless service需要DNS来解决访问问题

DNS记录格式为: 服务名.名称空间.svc.cluster.local.

4.1.2.5.1 查看kube-dns服务的IP     (k8s群集内DNS服务,k8s内置的)


[root@master01 ~]# kubectl get svc -n kube-system

查看到coreDNS的服务地址是10.96.0.10

4.1.2.5.2 在集群主机通过DNS服务地址查找无头服务的dns解析

[root@master01 ~]# yum -y install bind-utils
[root@master01 ~]# dig[华王3]  -t A[华王4]  headless-service.default.svc.cluster.local. @10.96.0.10

生产环境中需要合法的域名

4.1.2.5.3 验证pod的IP


[root@master01 ~]# kubectl get pod -o wide

4.1.2.5.4 在集群中创建一个pod验证

创建一个镜像为yauritux/busybox-curl的pod,pod名称为busybox,用来解析域名

[root@master01 ~]# kubectl run busybox --image=yauritux/busybox-curl -it

/home # curl headless-service.default.svc.cluster.local.


显示网页内容

  • NodePort类型(在外部使用集群节点IP访问)

创建资源清单文件

[root@master01 ~]# vim nodeport-service.yaml


apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-
server4
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx-
nodeport
  template:
    metadata:
      labels:
        app: nginx-
nodeport
    spec:
      containers:
      - name:
nginx-nodeport
        image: nginx:1.20
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-
nodeport
spec:
  type: NodePort
  selector:
    app: nginx-
nodeport
  ports:
  - protocol: TCP
    nodePort: 30001
    port: 8060
    targetPort: 80

应用资源清单文件

[root@master01 ~]# kubectl apply -f nodeport-service.yaml
 

验证service创建

[root@master01 ~]# kubectl get deployments.apps

[root@master01 ~]# kubectl get svc

[root@master01 ~]# kubectl get endpoints

访问kubernetes 任一节点ip的nodeport端口30001,均可成功访问

http://192.168.10.11:30001/

http://192.168.10.12:30001/

http://192.168.10.13:30001/


 [华王1]在 iptables 模式下,数据包的处理流程如下:

  1. 客户端发送请求:客户端向 Service 的虚拟 IP(ClusterIP)发送请求。
  2. 数据包进入内核空间:数据包到达节点后,直接进入内核空间,由 iptables 规则处理。
  3. NAT 表处理
    • 数据包首先经过 nat 表的 PREROUTING 链,进行目标地址转换(DNAT)。
    • iptables 规则将数据包的目标 IP 地址从 Service 的 ClusterIP 转换为后端 Pod 的 IP 地址。
  4. 转发到后端 Pod:数据包被转发到后端 Pod。
  5. 响应处理
    • Pod 处理完请求后,响应数据包经过 nat 表的 POSTROUTING 链,进行源地址转换(SNAT)。
    • 响应数据包直接返回给客户端。

 [华王2]无头服务的特点

  1. 没有 ClusterIP
    • 无头服务不分配 ClusterIP,因此没有单一的 IP 地址可供客户端访问。
  2. 直接解析到 Pod IP
    • 客户端通过 DNS 查询无头服务的名称时,会返回所有匹配 Pod 的 IP 地址列表。
  3. 适用于有状态应用
    • 无头服务为有状态应用(如数据库集群、消息队列集群)提供稳定的网络标识。
  4. 灵活性高
    • 无头服务允许用户直接与 Pod 通信,避免了负载均衡器的介入,适合需要自定义网络策略的场景。
  •  [华王3]dig:DNS 查询工具,用于向 DNS 服务器发送查询请求并返回结果。

 [华王4]-t A:指定查询的记录类型为 A 记录(Address Record),A 记录用于将域名解析为 IPv4 地址。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐