Kubernetes Service(虚拟ip和服务代理 userspace iptables ipvs 会话粘性)

Kubernetes Service

概述

访问k8s集群中的pod, 客户端需要知道pod地址,需要感知pod的状态。那如何获取各个pod的地址?若某一node上的pod故障,客户端如何感知?

什么是Service

Kubernetes service 定义了这样一种抽象:一个 Pod 的逻辑分组,一种可以访问它们的策略 —— 通常称为微服务。这一组 pod 能够被 Service 访问到,通常是通过 Label selector
在这里插入图片描述
Service能够提供负载均衡的能力,但是在使用上有以下限制:

  • 只提供4层负载均衡能力,而没有7层功能,但有时我们可能需要更多的匹配规则来转发请求,这点上4层负载均衡是不支持的

Kubernetes Service 从逻辑上代表了一组 Pod,具体是哪些 Pod 则是由 label 来挑选,Service 有自己 IP,而且这个 IP 是不变的。

  • 客户端只需要访问 Service 的 IP,Kubernetes 则负责建立和维护 Service 与 Pod 的映射关系。
  • 无论后端 Pod 如何变化,对客户端不会有任何影响,因为 Service 没有变

为什么要有Service

当Pod宕机后重新生成时,其IP等状态信息可能会变动,Service会根据Pod的Label对这些状态信息进行监控和变更,保证上游服务不受Pod的变动而影响。

​ Kubernetes Pods 是有生命周期的。他们可以被创建,而且销毁不会再启动。 如果您使用Deployment来运行您的应用程序,则它可以动态创建和销毁 Pod。

​ 一个Kubernetes的Service是一种抽象,它定义了一组Pods的逻辑集合和一个用于访问它们的策略 - 有的时候被称之为微服务。一个Service的目标Pod集合通常是由Label Selector 来决定的。

​ 如下图所示,当Nginx Pod作为客户端访问Tomcat Pod中的应用时,IP的变动或应用规模的缩减会导致客户端访问错误。而Pod规模的扩容又会使得客户端无法有效的使用新增的Pod对象,从而影响达成规模扩展之目的。为此,Kubernetes特地设计了Service资源来解决此类问题。

在这里插入图片描述

Service实现原理

Service资源基于标签选择器将一组Pod定义成一个逻辑组合,并通过自己的IP地址和端口调度代理请求至组内的Pod对象之上,如下图所示,它向客户端隐藏了真实的、处理用户请求的Pod资源,使得客户端的请求看上去就像是由Service直接处理并响应一样。
在这里插入图片描述
Service对象的IP地址也称为Cluster IP,它位于Kubernetes集群配置指定专用IP地址的范围之内,是一种虚拟IP地址,它在Service对象创建后既保持不变,并且能够被同一集群中的Pod资源所访问。Service端口用于接收客户端请求并将其转发至其后端的Pod中的相应端口之上,因此,这种代理机构也称为“端口代理”(port proxy)或四层代理,工作于TCP/IP协议栈的传输层。

​ Service资源会通过API Server持续监视着(watch)标签选择器匹配到的后端Pod对象,并实时跟踪各对象的变动,例如,IP地址变动、对象增加或减少等。Service并不直接链接至Pod对象,它们之间还有一个中间层——Endpoints资源对象,它是一个由IP地址和端口组成的列表,这些IP地址和端口则来自由Service的标签选择器匹配到的Pod资源。当创建service对象时,其关联的Endpoints对象会自动创建。

Service 的类型

Service 在 K8s 中有以下四种类型
在这里插入图片描述

  • Clusterlp:默认类型,自动分配一个仅 Cluster 内部可以访问的虚拟 IP
  • NodePort:在 ClusterIP 基础上为 Service 在每台机器上绑定一个端口,这样就可以通过:NodePort来访问该服务
  • LoadBalancer:在 NodePort 的基础上,借助 cloud provider创建一个外部负载均衡器,并将请求转发到:NodePort
  • ExternalName:把集群外部的服务引入到集群内部来,在集群内部直接使用。没有任何类型代理被创建,这只有kubernetes1.7或更高版本的 kube-dns 才支持
虚拟IP和服务代理

​ Kubernetes Pods 是有生命周期的。他们可以被创建,而且销毁不会再启动。 如果您使用Deployment来运行您的应用程序,则它可以动态创建和销毁 Pod。

​ 一个Kubernetes的Service是一种抽象,它定义了一组Pods的逻辑集合和一个用于访问它们的策略 - 有的时候被称之为微服务。一个Service的目标Pod集合通常是由Label Selector 来决定的。

kube-proxy将请求代理至相应端点的方式有三种:userspace(用户空间)、iptables和ipvs

​ 一个Service对象就是工作节点上的一些iptables或ipvs规则,用于将到达Service对象IP地址的流量调度转发至相应的Endpoints对象指定的IP地址和端口之上。

​ kube-proxy组件通过API Server持续监控着各Service及其关联的Pod对象,并将其创建或变动实时反映到当前工作节点上的iptables规则或ipvs规则上。

​ ipvs是借助于Netfilter实现的网络请求报文调度框架,支持rr、wrr、lc、wlc、sh、sed和nq等十余种调度算法,用户空间的命令行工具是ipvsadm,用于管理工作与ipvs之上的调度规则。

​ Service IP事实上是用于生成iptables或ipvs规则时使用的IP地址,仅用于实现Kubernetes集群网络的内部通信,并且能够将规则中定义的转发服务的请求作为目标地址予以相应,这也是将其称为虚拟IP的原因之一。

userspace代理模式

userspace是Linux操作系统的用户空间

​ 这种模式下,kube-proxy负责跟踪API Server上Service和Endpoints对象的变动(创建或移除),并据此调整Service资源的定义。对于每个Service对象,它会随机打开一个本地端口(运行于用户控件的kube-proxy进程负责监听),任何到达此端口的连接请求都将代理至当前Service资源后端的各Pod对象上,至于会挑选中哪个Pod对象则取决于当前Service资源的调度方式(通过Service的SessionAffinity来确定),默认的调度算法是轮循(round-robin)。

​ 其代理的过程是:请求到达service后,其被转发至内核空间,经由套接字送往用户空间的kube-proxy,而后再由它送回内核空间,并调度至后端Pod。其传输效率太低,在1.1版本前是默认的转发策略。
在这里插入图片描述

iptables代理模式

​ iptables代理模式中,kube-proxy负责跟踪API Server上Service和Endpoints对象的变动(创建或移除),并据此作出Service资源定义的变动。同时,对于每个Service对象,它都会创建iptables规则直接捕获到达Cluster IP(虚拟IP)和Port的流量,并将其重定向至当前Service的后端。对于每个Endpoints对象,Service资源会为其创建iptables规则并关联至挑选的后端Pod资源,默认的调度算法是随机调度(random)。实现基于客户端IP的会话亲和性(来自同一个用户的请求始终调度到后端固定的一个Pod),可将service.spec.sessionAffinity的值设置为“ClientIP”(默认值为“None”)。

​ 其代理过程是:请求到达service后,其请求被相关service上的iptables规则进行调度和目标地址转换(DNAT)后再转发至集群内的Pod对象之上
在这里插入图片描述
相对userspace模式来说,iptables模式无须将流量在用户空间和内核空间来回切换,因而更加高效和可靠。其缺点是iptables代理模型不会在被挑中的Pod资源无响应时自动进行重定向;而userspace模式则可以。

ipvs代理模式

​ kube-proxy跟踪API Server上Service的Endpoints对象的变动,据此来调用netlink接口创建ipvs规则,并确保与API Server中的变动保持同步,其请求流量的调度功能由ipvs实现,其余的功能由iptables实现。ipvs支持众多调度算法,如rr、lc、dh、sh、sed和nq等。

在这里插入图片描述

Service示例

准备工作

创建deployment

vi nginx-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1 # 只有一个副本
  selector:
    matchLabels:
        app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.20
        ports:
        - containerPort: 80

启动deployment

kubectl apply -f nginx-deployment.yml

kubectl get pods -o wide

在这里插入图片描述
访问测试

curl 10.244.2.54

在这里插入图片描述

ClusterlP类型

类型为ClusterIP的service,这个service有一个Cluster-IP,其实就一个VIP,具体实现原理依靠kubeproxy组件,通过iptables或是ipvs实现。

注意:这种类型的service 只能在集群内访问
在这里插入图片描述
编辑资源清单

vi cluster-iP-service.yml
apiVersion: v1
kind: Service
metadata:
  name: nginx-service
  namespace: default
  labels:
    app: nginx-service
spec:
  type: ClusterIP
  ports:
  - port: 8000 		# Service 暴漏端口
    targetPort: 80  # 代理的对象的端口
  selector:
    app: nginx # 绑定标签是nginx的对象

应用Service

kubectl apply -f cluster-iP-service.yml

kubectl get service -o wide

在这里插入图片描述
访问测试

curl 10.1.206.66:8000

在这里插入图片描述
删除Pod
删除pod让Pod的节点漂移再次访问Service节点

kubectl delete pod nginx-deployment-6897679c4b-2hqmk

在这里插入图片描述
访问测试
我们发现虽然pod的IP以及节点变化了但是Service访问IP没有任何变化

curl 10.1.206.66:8000

在这里插入图片描述
工作原理
​ clusterIP 主要在每个 node 节点使用 iptables,将发向 clusterlP 对应端口的数据,转发到 kube-proxy 中。然后 kube-proxy 自己内部实现有负载均衡的方法,并可以查询到这个 service 下对应 pod 的地址和端口,进而把数据转发给对应的 pod 的地址和端口
在这里插入图片描述
为了实现图上的功能,主要需要以下几个组件的协同工作:

  • apiserver 用户通过 kubectl 命令向 apiserver 发送创建 service 的命令,apiserver接收到请求后将数据存储到 etcd 中
  • kube-proxy kubernetes 的每个节点中都有一个叫做 kube-porxy 的进程,这个进程负责感知service,pod 的变化,并将变化的信息写入本地的 iptables 规则中
  • iptables 使用 NAT 等技术将 virtuallP 的流量转至 endpoint 中
NodePort

当我们需要集群外业务访问,那么ClusterIP就满足不了了,NodePort当然是其中的一种实现方案
在这里插入图片描述

编辑资源清单
vi node-port-service.yml
apiVersion: v1
kind: Service
metadata:
  name: nginx-node-port-service
  namespace: default
  labels:
    app: nginx-service
spec:
  type: NodePort
  ports:
  - port: 8000 		# Service 暴漏端口
    targetPort: 80  # 代理的对象的端口
  selector:
    app: nginx # 绑定标签是nginx的对象

应用Service

kubectl apply -f node-port-service.yml

kubectl get service -o wide

在这里插入图片描述
访问测试

curl 10.1.137.200:8000

在这里插入图片描述
删除Pod
删除pod让Pod的节点漂移再次访问Service节点

kubectl delete pod nginx-deployment-6897679c4b-2hqmk

在这里插入图片描述
访问测试
我们发现虽然pod的IP以及节点变化了但是Service访问IP没有任何变化

curl 10.1.137.200:8000

在这里插入图片描述
外网访问
NodePort的最主要功能是进行外网访问,我们是不能通过访问8000端口访问的,他是内网端口,外网访问需要访问映射出来的端口8000:31337/TCP这里映射出来的nodeport是31337,还可以通过指定nodePort来指定端口,要求端口必须大于30000

curl 192.168.64.160:31337

在这里插入图片描述
通过浏览器访问
在这里插入图片描述
工作原理
​ nodePort 的原理在于在node上开了一个端口,将向该端口的流量导入到 kube-proxy,然后由 kube-proxy 进一步到给对应的pod

端口号区分

k8s 中 port nodePort targetPort有什么区别呢

应用位置不同

port:是service的的端口
targetport:是pod也就是容器的端口
nodeport:是容器所在宿主机的端口(实质上也是通过service暴露给了宿主机,而port却没有)

port

k8s集群内部服务之间访问service的入口。即clusterIP:port是service暴露在clusterIP上的端口

​ 主要作用是集群内其他pod访问本pod的时候,需要的一个port,如nginx的pod访问mysql的pod,那么mysql的pod的service可以如下定义,由此可以这样理解,port是service的port,nginx访问service的33306

apiVersion: v1
 kind: Service
 metadata:
  name: mysql-service
 spec:
  ports:
  - port: 33306
    targetPort: 3306
  selector:
   name: mysql-pod
targetport

容器的端口(最终的流量端口)。targetPort是pod上的端口,从port和nodePort上来的流量,经过kube-proxy流入到后端pod的targetPort上,最后进入容器。

​ 看上面的targetport,targetport说过是pod暴露出来的port端口,当nginx的一个请求到达service的33306端口时,service就会将此请求根据selector中的name,将请求转发到mysql-pod这个pod的3306端口上

nodeport

nodeport就很好理解了,它是集群外的客户访问,集群内的服务时,所访问的port,比如客户访问下面的集群中的nginx,就是这样的方式,ip:30001

​ 外部流量访问k8s集群中service入口的一种方式(另一种方式是LoadBalancer),即nodeIP:nodePort是提供给外部流量访问k8s集群中service的入口

​ 比如外部用户要访问k8s集群中的一个Web应用,那么我们可以配置对应service的type=NodePort,nodePort=30001。其他用户就可以通过浏览器http://node:30001访问到该web服务。而数据库等服务可能不需要被外界访问,只需被内部服务访问即可,那么我们就不必设置service的NodePort。

apiVersion: v1 
kind: Service 
metadata: 
    name: nginx-service 
spec: 
    type: NodePort # 有配置NodePort,外部流量可访问k8s中的服务 
    ports: 
    - port: 30080 # 服务访问端口 
      targetPort: 80 # 容器端口 
      nodePort: 30001 # NodePort 
    selector: name: nginx-pod
小结

​ nodeport是集群外流量访问集群内服务的端口类型,比如客户访问nginx,apache,port是集群内的pod互相通信用的端口类型,比如nginx访问mysql,而mysql是不需要让客户访问到的,最后targetport,顾名思义,目标端口,也就是最终端口,也就是pod的端口。

Service会话粘性

Service资源支持Session affinity(粘性会话或会话粘性)机制,能够将来自同一个客户端的请求始终转发至同一个后端的Pod对象。这意味着会影响调度算法的流量分发功能,进而降低其负载均衡的效果。所以,当客户端访问pod中的应用程序时,如果有基于客户端身份保存某些私有信息,并基于这些私有信息追踪用户的活动等一类的需求时,就可以启用session affinity机制。

​ Session affinity的效果仅在一段时间期限内生效,默认值为10800秒,超出此时长之后,客户端的再次访问会被调度算法重新调度。Service资源的Session affinity机制仅能基于客户端的IP地址识别客户端身份,把经由同一个NAT服务器进行源地址转换的所有客户端识别为同一个客户端,便导致调度效果不佳,所以,这种方法并不常用。

​ Service资源通过service.spec.sessionAffinity和service.spec.sessionAffinityConfig两个字段配置粘性会话。sessionAffinity字段用于定义要使用的粘性会话的类型,仅支持使用“None”和“ClientIp”两种属性值。

  • None:不使用sessionAffinity,默认值。
  • ClientIP:基于客户端IP地址识别客户端身份,把来自同一个源IP地址的请求始终调度至同一个Pod对象。
修改资源清单
# 定义pod
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-deployment
spec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: nginx
        image: ikubernetes/myapp:v1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 80
---
#定义service
apiVersion: v1
kind: Service
metadata:
  name: myapp-service    #service名称
spec:
  selector:    #用于匹配后端的Pod资源对象,需和上面定义pod的标签一致
    app: myapp
  ports:
  - port: 8000    #service端口号
    targetPort: 80    #后端Pod端口号
    protocol: TCP    #使用的协议
  sessionAffinity: ClientIP    #指定使用ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10    #配置session超时时间,这里为了看效果设置的比较短
生效配置
kubectl apply -f myapp-demo.yml

在这里插入图片描述

测试

使用curl命令测试

for i in 1 2 3 4 5; do curl 10.1.216.151:8000/hostname.html; done

我们发现请求数据都在同一个客户端
在这里插入图片描述
等待10S后在次访问

for i in 1 2 3 4 5; do curl 10.1.216.151:8000/hostname.html; done

我们发现现在已经在不同的客户端了
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Early Userspace是指在Linux内核启动过程中,内核会在完成一些必要的初始化后,将控制权交给一个称为“initramfs”或“initrd”的文件系统,该文件系统包含了用于启动系统的必要文件和工具。这个文件系统就是Early Userspace,它是在内核启动的早期阶提供了一个临时的根文件系统,用于挂载真正的根文件系统并完成系统初始化的过程。在一些特殊的情况下,Early Userspace也可以用于恢复系统、调试系统等操作。 ### 回答2: Early Userspace(早期用户空间)是指在操作系统启动过程中的一个阶,在这个阶中,用户空间的一部分已经被初始化和启动,但操作系统的其他部分和服务尚未完全加载和运行。 在早期用户空间中,操作系统内核会初始化一些基本的用户空间组件,例如shell环境、文件系统等,以便用户能够进行一些基本的操作和管理。这是为了确保在操作系统完全启动前,用户已经能够进行某些必要的任务。早期用户空间的目的是为了提供一种对于用户来说更友好和可控的启动过程。 通过早期用户空间,用户可以进行一些简单的操作,例如查看和编辑文件、管理网络连接等。这使得用户可以在操作系统启动的早期阶就能够进行一些必要的操作,而无需等待操作系统完全加载和运行。 早期用户空间的一个常见应用是在Linux系统启动过程中。在该过程中,操作系统内核会首先加载最小化的文件系统和内存管理功能,然后将控制权交给用户空间的一部分。在这个阶,用户可以使用预先配置好的工具和服务来进行一些操作和管理。 总的来说,早期用户空间在操作系统启动的早期阶提供了一种用户可交互的环境,以便用户能够进行一些基本的操作和管理任务。这样,用户可以更早地开始使用操作系统的功能,而无需等待整个系统完全启动和加载。 ### 回答3: early_userspace指的是在操作系统启动的早期阶,即内核加载和初始化完成后,但用户空间还没有完全准备好的阶。在这个阶,操作系统的一部分功能已经可用,可以执行一些用户空间的任务,例如初始化设备、加载驱动、启动服务等。 early_userspace的优点在于可以更早地完成一些操作系统的准备工作,提高了系统的启动速度和效率。例如,在这个阶可以提前准备好一些必要的设备驱动程序,避免用户空间启动后再加载,节省了时间和资源。同时,也可以在这个阶执行一些系统初始化配置,以便用户空间的启动更加顺利和高效。 在early_userspace阶,用户空间的功能是有限的,只能执行一些特定的任务,不能进行全面的用户应用程序执行。因此,这个阶的代码量通常比较小,主要是一些轻量级的工具和服务程序。随着系统的启动继续进行,用户空间会逐渐完全准备好,可以执行更多的应用程序和服务。 总之,early_userspace是操作系统启动过程中的一个阶,它在内核加载和用户空间完全准备好之间,提供一些提前完成的功能和任务。通过在这个阶进行一些准备工作,可以加快系统启动速度和提高效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值