1.Service定义

        官方文档:https://kubernetes.io/zh-cn/docs/concepts/services-networking/service/

        Service是用于一组提供服务的pod抽象一个稳定的网络访问地址,是Kubernetes实现微服务的核心概念,可以为一组具有相同功能的pod提供一个统一的入口地址,并将请求负载分发到后端的各个容器上面。

#service的完整yaml文件如下
apiVersion: v1      // Required
kind: Service      	// Required
metadata:           // Required
  name: string      // Required
  namespace: string // Required
  labels:
    - name: string
  annotations:
    - name: string
spec:               // Required
  selector: []     // Required
  type: string     // Required
  clusterIP: string
  sessionAffinity: string
  ports:
    - name: string
      protocol: string
      port: int
      targetPort: int
      nodePort: int
  status:
    loadBalancer:
      ingress:
        ip: string
        hostname: string
属性名称取值类型是否必选取值说明
versionstringRequiredv1
kindstringRequiredService
metadataobjectRequired元数据
metadata.namestringRequiredservice名称
metadata.namespacestringRequired命名空间,不指定默认用default的命名空间
metadata.labels[]list自定义标签属性列表
metadata.annotations[]list自定义注解属性列表
specobjectRequired详细描述
spec.selector[]listRequiredLabel Selector配置,将选择具有指定Label标签的Pod作为管理范围
spec.typestringRequired

Service的类型,指定Service的访问方式,默认值为 ClusterIP.(1)ClusterIP : 虚拟服务 IP 地址,该地址用于 Kubernetes集群内部的 Pod 访问 , 在 Node 上 kubc-proxy 通过设置的iptables 规则进行转发 .

(2) NodePort: 使用宿主机的端口,使能够访问各 Node 的外部客户端通过 Node 的了地址和端口号就能访问服务.

(3) LoadBalancer, 使用外接负载均衡器完成到服务的负载分发,需要在spec.starus.loadbalancer 字段指定外部负载均衡器的 IP 地址,同时定义 nodePort 和 clusterlP, 用于 公有云环境

spec.clusterIPstring虚拟服务的IP地址,当type=ClusterIP 时,如果不指定,则系统进行自动分配,也可以手工指定:当type=LoadBalancer时,需要指定
spec.sessionAffinitystring是否支持 Session, 可选值为 ClientIp,默认值为 None。ClientIP, 表示将同一哥客户端(根据客户端的 IP 地址决定)的访问请求都转发到同一个后端 Pod
spec.ports[]listService端口列表
spec.ports[].namestring端口名称
spec.ports[].protocolstring端口协议,支持TCP和UDP,默认值为TCP
spec.ports[].portint服务监听的端口号
spec.ports[].targetPortint需要转发到后端Pod的端口号
spec.ports[].nodePortint当spectype=NodePort时,指定映射到宿主机的端口号
Statusobject当spec.typc=LoadBalancer时,设置外部负载均衡器的地址,用千公有云环境
status.loadBalancerobject外部负载均衡器
status.loadBalancer.ingressobject外部负载均衡器
status.loadBalancer.ingress.ipstring外部负载均衡器的IP地址
status.loadBalancer.ingress.hostnamestring外部负载均衡器的主机名

2.Service的概念和原理

    Service主要提供网络服务,通过Service的定义,能够为客户端应用提供稳定的访问地址(域名或者IP地址)和负载均衡功能,以及屏蔽后端Endpoint的变化,是Kubernetes实现微服务的核心资源。

2.1 概念

  我们以一个提供web服务的Pod集合,由两个tomcat容器副本组成为例子来说明,每个容器提供的服务端口号都为8080

#1.创建webapp-deployment.yaml文件
[root@k8s-master k8s-yaml]# cat webapp-deployment.yaml 
apiVersion: apps/v1
kind: Deployment
metadata: 
  name: webapp
spec:
  replicas: 2
  selector: 
    matchLabels:
      app: webapp
  template:
    metadata:
      labels:
        app: webapp
    spec:
      containers:
      - name: webapp
        image: tomcat
        ports: 
        - containerPort: 8080
#2.运行webapp-deployment.yaml文件
[root@k8s-master k8s-yaml]# kubectl apply -f webapp-deployment.yaml 
deployment.apps/webapp created
#3.查看pod
[root@k8s-master k8s-yaml]# kubectl get po 
NAME                              READY   STATUS    RESTARTS   AGE
nginx-deployment-f7599d4c-95nr8   1/1     Running   0          4h17m
nginx-deployment-f7599d4c-z8vf9   1/1     Running   0          4h17m
webapp-886db8b9-kc2dc             1/1     Running   0          2m24s
webapp-886db8b9-lm4rp             1/1     Running   0          2m24s
#4.查看pod访问地址
[root@k8s-master k8s-yaml]# kubectl get po -l app=webapp -o wide
NAME                    READY   STATUS    RESTARTS   AGE     IP              NODE         NOMINATED NODE   READINESS GATES
webapp-886db8b9-kc2dc   1/1     Running   0          3m19s   172.18.85.205   k8s-node01   <none>           <none>
webapp-886db8b9-lm4rp   1/1     Running   0          3m19s   172.18.85.206   k8s-node01   <none>           <none>


因为本机资源有限,所以只有一个master节点和两个node节点,其中有一个node节点是关闭的,未打开

我们在node节点上分别curl 172.18.85.205:8080 和curl 172.18.85.206:8080 均有响应,我们在来创建service

#1.创建service
[root@k8s-master k8s-yaml]# kubectl expose deployment webapp 
service/webapp exposed
#2.查看service
[root@k8s-master k8s-yaml]# kubectl get svc
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP    8d
webapp       ClusterIP   10.106.80.230   <none>        8080/TCP   6s

此时我们在用curl 10.106.80.230:8080也有响应,此时是我们对10.106.80.230自动负载到后端两个pod之一:172.18.85.295或者206了

我们除了用kubectl expose来创建service以外,还能以yaml的方式来创建(实际生产中基本都用 这个,方便管理),如下

#1.创建webapp-service.yaml文件
[root@k8s-master k8s-yaml]# cat webapp-service.yaml 
apiVersion: v1
kind: Service
metadata:
  name: webapp
spec:
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080
  selector:
    app: webapp
#2.创建service
[root@k8s-master k8s-yaml]# kubectl create -f webapp-service.yaml 
service/webapp created
#3.查看svc
[root@k8s-master k8s-yaml]# kubectl get svc 
NAME         TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1      <none>        443/TCP    8d
webapp       ClusterIP   10.103.127.8   <none>        8080/TCP   41s

一个service对应的后端由Pod的IP和容器端口号组成,即一个完整的“IP:Port”访问地址,这个在kubernetes系统中叫做Endpoint,我们可以用kubectl describe svc webapp或者kubectl get endpoints来查看

[root@k8s-master k8s-yaml]# kubectl describe svc webapp
Name:              webapp
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=webapp
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.103.127.8
IPs:               10.103.127.8
Port:              <unset>  8080/TCP
TargetPort:        8080/TCP
Endpoints:         172.18.85.205:8080,172.18.85.206:8080
Session Affinity:  None
Events:            <none>

[root@k8s-master k8s-yaml]# kubectl get endpoints
NAME         ENDPOINTS                               AGE
kubernetes   11.0.1.12:6443                          8d
webapp       172.18.85.205:8080,172.18.85.206:8080   5m43s

2.2 Service的负载均衡机制

从clusterIP到后端Pod IP的负载均衡机制是由每个Node上的kube-proxy负责实现

  2.2.1 kube-proxy的代理模式

    1.userspace模式

       用户空间模式,由kube-proxy完成代理的实现,效率最低,不再推荐使用

    2.iptables模式

       kube-proxy通过设置Linux Kernel的iptables规则,实现从Service到后端的Endpoint列表的负载分发规则,效率很高。但是如果某个后端的Endpoint在转发时不可用,此次客户端请求会以失败告终,相对于userspace模式更不可靠。此时应该通过将Pod设置readinessprobe(服务可用性健康检查)来保证只有达到ready状态的Endpoint才会设置为Service的后端Endpoint

    3.ipvs模式

       通过设置Linux Kernel的netlink接口设置IPVS规则,转发效率和支持的吞吐率都是最高的。ipvs模式要求Linux Kernel启用IPVS模块,如果操作系统未启动IPVS内核模块,kube-proxy则会自动切换至iptables模式,同时,ipvs模式支持更多的负载均衡策略:rr(round-robin 轮询),lc(least connection 最小连接数),dh(destination hashing 目的地址哈希),sh(source hashing 源地址哈希),sed(shortest expected delay最短期望延时),nq(never queue 永不排队)

    4.kernelspace模式

      Windows Server上的代理模式

2.2.2 会话保持机制

    Service支待通过设置sessionAffinity 实现基于客户端IP的会话保持机制,即首次将某个客户端来源IP发起的请求转发到后端的某个Pod上,之后从相同的客户端 P发起的请求都将被转发到相同的后端Pod上,配置参数为 service.spec.sessionAffinity,例如

apiVersion: v1
kind: Service
metadata:
  name: webapp
spec:
  sessionAffinity: ClientIP
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080
  selector:
    app: webapp

同时,用户可以设置会话保持的最长时间,在此时间之后重置客户端来源IP的保持规则,配置参数为service.spec.sessionAffinityConfig.clientIP.timeoutseconds。例如下面的服务将会话保持时间设置为10800s(3h):

apiVersion: v1
kind: Service
metadata:
  name: webapp
spec:
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080
  selector:
    app: webapp

通过Service的负载均衡机制,Kubernetes实现了一种分布式应用的统一入口,免去了客户端应用获知后端服务实例列表和变化的复杂度

2.2.3 Service的多端口设置

    一个容器应用可以提供多个端口的服务,在Service的定义中也可以相应地设置多个端口号,例如

apiVersion: v1
kind: Service
metadata:
  name: webapp
spec:
  ports:
  - protocol: TCP
    port: 8080
    targetPort: 8080
    name: web
  - procotol: TCP
    port: 8005
    targetPort: 8005
    name: management
  selector:
    app: webapp

2.2.4 将外部服务定义成Service

Selector对后端Endpoint列表进行了一次抽象,如果后端的Endpoint是由Pod副本集提供的,则Service还可以抽象定义任意其他服务,将一个Kubernetes集群外部的已知服务定义为Kubernetes内的一个Service,供集群内的其他应用访问,常见的应用场景包括:

    1.普通的Service通过Label已部署的一个集群外服务,例如数据库服务、缓存服务等;

    2.其他 ubernetes集群的某个服务;

    3.迁移过程中对某个服务进行Kubernetes内的服务名访问机制的验证。

[root@k8s-master k8s-yaml]# cat my-service.yaml 
apiVersion: v1
  kind: Service
  metadata:
    name: my-service
  spec:
    ports:
    - protocol: TCP
      port: 80
      targetPort: 80
[root@k8s-master k8s-yaml]# cat my-endpoints.yml 
apiVersion: v1
  kind: Endpoints
  metadata:
    name: my-service
    subsets:
    - addresses:
      - IP: 1.2.3.4
      ports:
      - port: 80

2.2.5 将Service暴露到集群外部

    Kubernetes提供了多种机制将Service暴露出去,供集群外部的客户端访问。这可以通过Service资源对象的类型字段"type" 进行设置 

    目前Service的类型如下:

1.ClusterIP:Kubernetes会默认自动设置Service的虚拟IP地址,仅可被集群内部客户端应用访问。当然,用户也可以手动指定一个ClusterIP地址,不过需要确保该IP在Kubernetes集群设置的 ClusterIP 地址范围内(通过 kube-apiserver 服务的启动参数--service-cluster-ip-range 设置),并且没有被其他 Service 使用。

2.NodePort:将Service的端口号映射到每个Node的一个端口号上,这样集群中的任意Node都可以作为 Service 的访问入口地址,即 NodeIP:NodePort。

3.LoadBalancer:将Service映射到一个已存在的负载均衡器的IP地址上,通常在公有云环境中使用。

4.ExternalName:将Service映射为 一个外部域名地址 ,通过externalName字段进行

设置。

举例说明:

NodePort 类型:
#1.创建webapp-service.yaml
[root@k8s-master k8s-yaml]# cat webapp-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: webapp
spec:
  type: NodePort
  ports:
  - port: 8080
    targetPort: 8080
    nodePort: 30081
  selector:
    app: webapp
#2.创建svc
[root@k8s-master k8s-yaml]# kubectl create -f webapp-service.yaml 
service/webapp created
#3.查看svc
[root@k8s-master k8s-yaml]# kubectl get svc -o wide
NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE   SELECTOR
kubernetes   ClusterIP   10.96.0.1       <none>        443/TCP          8d    <none>
webapp       NodePort    10.102.137.65   <none>        8080:30081/TCP   16s   app=webapp

然后用curl 11.0.1.13:30081和curl 11.0.1.14:30081得到响应,其中IP为两个nodeIP

LoadBalancer类型 :

  通常在公有云环境中设置Service的类型为 “LoadBalancer", 可以将 Service 映射到公有云提供的某个负载均衡器的IP地址上,客户端通过负载均衡器的IP和Service的端口号就可以访问到具体的服务,无须再通过kube-proxy提供的负载均衡机制进行流量转发。公有云提供的LoadBalancer可以直接将流量转发到后端Pod上,而负载分发机制依赖于公有云服务商的具体实现。
 

#1.创建webapp-service.yaml
[root@k8s-master k8s-yaml]# cat webapp-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: webapp
spec:
  type: LoadBalancer
  ports:
  - port: 80
    targetPort: 9376
    protocol: TCP
  selector:
    app: webapp
#2.创建svc
[root@k8s-master k8s-yaml]# kubectl create -f webapp-service.yaml 
service/webapp created
#3.查看svc
[root@k8s-master k8s-yaml]# kubectl get svc -o wide
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE   SELECTOR
kubernetes   ClusterIP      10.96.0.1       <none>        443/TCP        8d    <none>
webapp       LoadBalancer   10.110.189.28   <pending>     80:31010/TCP   5s    app=webapp
ExternalName 类型:

ExternalName类型的服务用于将集群外的服务定义为Kubernetes的集群的Service,并且通过 externalName字段指定外部服务的地址,可以使用域名或IP格式。集群内的客户端应用通过访问这个Service就能访问外部服务了。这种类型的Service没有后端Pod,所以无须设置Label Selector

这个例子后续会在ingress中列出
 

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐