kubernetes核心概念 Service

总结:

  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 模式

  • 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的工作模式

# kubectl -n kube-system describe cm kube-proxy  | grep mode        # 查看configmap

 mode: ""

# kubectl -n kube-system edit cm kube-proxy            # 修改configmap

 mode: "ipvs"

# kubectl -n kube-system rollout restart daemonset kube-proxy       # 重启damonset控制器

  • 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(无头服务,无群集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 ~]# cat nginx1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-server1
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx1
  template:
     metadata:
       labels:
         app: nginx1
     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

NAME                             READY   STATUS    RESTARTS   AGE    IP             NODE       NOMINATED NODE   READINESS GATES

nginx-server1-5cfd5b5644-kxkh2   1/1     Running   0          2m4s   10.244.5.6     worker01   <none>           <none>

nginx-server1-5cfd5b5644-mjzgc   1/1     Running   0          2m4s   10.244.30.70   worker02   <none>        

[root@master01 ~]# curl 10.244.5.6     (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

NAME            TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE

nginx-server1   ClusterIP   10.100.81.30   <none>        80/TCP    23s

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

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

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


apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-server2
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx2
  template:
     metadata:
       labels:
         app: nginx2
     spec:
       containers:
       - name: nginx2
         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: nginx2

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

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

查看service


[root@master01 ~]# kubectl get service
 

NAME            TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE

kubernetes      ClusterIP   10.96.0.1       <none>        443/TCP   14m

nginx-server1   ClusterIP   10.100.81.30    <none>        80/TCP    10m

nginx-server2   ClusterIP   10.103.207.91   <none>        80/TCP    3m18s

查看endpoints


[root@master01 ~]# kubectl get endpoints
 

NAME            ENDPOINTS                       AGE

kubernetes      192.168.10.11:6443              12m

nginx-server1   10.244.30.70:80,10.244.5.6:80   9m2s

nginx-server2   10.244.30.72:80,10.244.5.8:80   92s

4.1.1.3 访问

[root@master01 ~]# curl http:// 10.100.81.30
 

可看到网页内容

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

[root@master01 ~]# kubectl exec -it nginx-server2-pod名称1 -- bash

root@nginx-server1-5cfd5b5644-kxkh2:/# cd /usr/share/nginx/html/

root@nginx-server1-5cfd5b5644-kxkh2:/usr/share/nginx/html# echo web1 > index.html

root@nginx-server1-5cfd5b5644-kxkh2:/usr/share/nginx/html# exit

[root@master01 ~]# kubectl exec -it nginx-server2-pod名称2 -- bash

root@nginx-server1-5cfd5b5644-mjzgc:/# cd /usr/share/nginx/html/

root@nginx-server1-5cfd5b5644-mjzgc:/usr/share/nginx/html# echo web2 > index.html

root@nginx-server1-5cfd5b5644-mjzgc:/usr/share/nginx/html# exit

4.1.1.5 测试

[root@master01 ~]# curl 10.100.81.30

web2

[root@master01 ~]# curl 10.100.81.30

web1

[root@master01 ~]# curl 10.100.81.30

web2

[root@master01 ~]# curl 10.100.81.30

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 ~]# cat nginx-server3.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-server3
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx3
  template:
     metadata:
       labels:
         app: nginx3
     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: nginx3      

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

NAME               TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE

headless-service   ClusterIP   None            <none>        80/TCP    10s

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

[root@master01 ~]# kubectl get endpoints

NAME               ENDPOINTS                        AGE

headless-service   10.244.30.77:80,10.244.5.13:80   69s

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服务)


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

NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE

kube-dns   ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   15h

查看到coreDNS的服务地址是10.96.0.10

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


[root@master01 ~]# dig -t A headless-service.default.svc.cluster.local. @10.96.0.10

...

;; OPT PSEUDOSECTION:

; EDNS: version: 0, flags:; udp: 4096

;; QUESTION SECTION:

;headless-service.default.svc.cluster.local. IN A

;; ANSWER SECTION:

headless-service.default.svc.cluster.local. 30 IN A 10.244.5.9

headless-service.default.svc.cluster.local. 30 IN A 10.244.30.73

4.1.2.5.3 验证pod的IP


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

NAME                READY   STATUS    RESTARTS   AGE     IP             NODE       NOMINATED NODE   READINESS GATES

nginx-server3-8cb76d66-j9rxm   1/1     Running   0          3m55s   10.244.5.13    worker01   <none>         <none>

nginx-server3-8cb76d66-vx6d8   1/1     Running   0          3m55s   10.244.30.77   worker02   <none>         <none>

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.


显示网页内容

创建资源清单文件

[root@master01 ~]# cat 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

NAME            READY   UP-TO-DATE   AVAILABLE   AGE

nginx-server4   2/2     2            2           10s

[root@master01 ~]# kubectl get svc

NAME             TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE

kubernetes       ClusterIP   10.96.0.1        <none>        443/TCP          94s

nginx-nodeport   NodePort    10.108.118.158   <none>        8060:30001/TCP   18s

[root@master01 ~]# kubectl get endpoints

NAME             ENDPOINTS                        AGE

kubernetes       192.168.10.11:6443               100s

nginx-nodeport   10.244.30.81:80,10.244.5.21:80   24s

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

更多推荐