kubernetes资源对象之service

一、service简介

pod是有生命周期的,创建、销毁、扩容、滚动升级都会导致pod的IP改变,这会导致一个问题一组pod( backend )为其它pod( frontend )提供服务,那么pod( frontend )如何发现pod( backend )。通过service可以实现,pod通过 Label Selector 绑定到service。

例如:pod( backend )运行三个副本,pod( frontend )不会关心自己调用的是哪一个pod( backend ),pod( frontend )会去访问定义的service。pod( backend )程序发生改变,pod( frontend )也不需要跟踪这一组pod的状态, service 定义的抽象能够解耦这种关联。

对 Kubernetes 集群中的应用,Kubernetes 提供了简单的 Endpoints API,只要 Service 中的一组 Pod 发生变更,应用程序就会被更新。 对非 Kubernetes 集群中的应用,Kubernetes 提供了基于 VIP 的网桥的方式访问 Service,再由 Service 重定向到 backend Pod。

二、代理模式

  • userspace 代理模式(K8S 1.1之前版本)
  • iptables 代理模式(K8S 1.10之前版本)
  • ipvs 代理模式(K8S 1.11 之后版本,激活ipvs需要修改配置)

1、userspace 代理模式

在 userspace 模式下,访问服务的请求到达节点后首先进入内核 iptables,然后回到用户空间,由 kube-proxy 转发到后端的 pod,这样流量从用户空间进出内核带来的性能损耗是不可接受的,所以也就有了 iptables 模式。

为什么 userspace 模式要建立 iptables 规则,因为 kube-proxy 监听的端口在用户空间,这个端口不是服务的访问端口也不是服务的 nodePort,因此需要一层 iptables 把访问服务的连接重定向给 kube-proxy 服务。

img

2、iptables 模式

iptables 模式是目前默认的代理方式,基于 netfilter 实现。当客户端请求 service 的 ClusterIP 时,根据 iptables 规则路由到各 pod 上,iptables 使用 DNAT 来完成转发,其采用了随机数实现负载均衡。

iptables 模式与 userspace 模式最大的区别在于,iptables 模块使用 DNAT 模块实现了 service 入口地址到 pod 实际地址的转换,免去了一次内核态到用户态的切换,另一个与 userspace 代理模式不同的是,如果 iptables 代理最初选择的那个 pod 没有响应,它不会自动重试其他 pod。

iptables 模式最主要的问题是在 service 数量大的时候会产生太多的 iptables 规则,使用非增量式更新会引入一定的时延,大规模情况下有明显的性能问题。

img

3、ipvs模式

当集群规模比较大时,iptables 规则刷新会非常慢,难以支持大规模集群,因其底层路由表的实现是链表,对路由规则的增删改查都要涉及遍历一次链表,ipvs 的问世正是解决此问题的,ipvs 是 LVS 的负载均衡模块,与 iptables 比较像的是,ipvs 的实现虽然也基于 netfilter 的钩子函数,但是它却使用哈希表作为底层的数据结构并且工作在内核态,也就是说 ipvs 在重定向流量和同步代理规则有着更好的性能,几乎允许无限的规模扩张。

ipvs 支持三种负载均衡模式:DR模式(Direct Routing)、NAT 模式(Network Address Translation)、Tunneling(也称 ipip 模式)。三种模式中只有 NAT 支持端口映射,所以 ipvs 使用 NAT 模式。linux 内核原生的 ipvs 只支持 DNAT,当在数据包过滤,SNAT 和支持 NodePort 类型的服务这几个场景中ipvs 还是会使用 iptables。

此外,ipvs 也支持更多的负载均衡算法,例如:

  • rr:round-robin/轮询
  • lc:least connection/最少连接
  • dh:destination hashing/目标哈希
  • sh:source hashing/源哈希
  • sed:shortest expected delay/预计延迟时间最短
  • nq:never queue/从不排队

userspace、iptables、ipvs 三种模式中默认的负载均衡策略都是通过 round-robin 算法来选择后端 pod 的,在 service 中可以通过设置 service.spec.sessionAffinity 的值实现基于客户端 ip 的会话亲和性,service.spec.sessionAffinity 的值默认为"None",可以设置为 “ClientIP”,此外也可以使用 service.spec.sessionAffinityConfig.clientIP.timeoutSeconds 设置会话保持时间。

img

三、service资源清单

apiVersion: v1
kind: Service
metadata:		#元数据
  name: string		#Service名称
  namespace: string		#命名空间,不指定时默认为default命名空间
  labels:		#自定义标签属性列表     
    - name: string
spec:		#详细描述    
  selector: []		#这里选择器一定要选择容器的标签,也就是pod的标签
  type: string		#service的类型,指定service的访问方式,默认ClusterIP
  clusterIP: string		#虚拟服务IP地址,当type=ClusterIP时,如不指定,则系统会自动进行分配,也可以手动指定。当type=loadBalancer,需要指定
  sessionAffinity: string		#是否支持session,可选值为ClietIP,默认值为空
  #ClientIP表示将同一个客户端(根据客户端IP地址决定)的访问请求都转发到同一个后端Pod
  ports:		#service需要暴露的端口列表    
  - name: string		#端口名称
    protocol: string		#端口协议,支持TCP或UDP,默认TCP
     port: int		#服务监听的端口号
     targetPort: int		#需要转发到后端的端口号(要于containerPort对应)
     nodePort: int		#当type=NodePort时,指定映射到物理机的端口号
  status:		#当type=LoadBalancer时,设置外部负载均衡的地址,用于公有云环境    
    loadBalancer:		#外部负载均衡器    
      ingress:		#外部负载均衡器 
      ip: string		#外部负载均衡器的IP地址
      hostname: string		#外部负载均衡器的机主机

service四种类型

1、ClusterIp(集群内部使用)

ClusterIP 类型的 service 是 kubernetes 集群默认的服务暴露方式,它只能用于集群内部通信,可以被各 pod 访问,其访问方式为:

pod ---> ClusterIP:ServicePort --> (iptables)DNAT --> PodIP:containePort

img

2、NodePort(对外暴露应用)

如果想要在集群外访问集群内部的服务,可以使用这种类型的 service,NodePort 类型的 service 会在集群内部署了 kube-proxy 的节点打开一个指定的端口,之后所有的流量直接发送到这个端口,然后会被转发到 service 后端真实的服务进行访问。Nodeport 构建在 ClusterIP 上,其访问链路如下所示:

client ---> NodeIP:NodePort ---> ClusterIP:ServicePort ---> (iptables)DNAT ---> PodIP:containePort

img

3、LoadBalancer(对外暴露应用,适用于公有云)

LoadBalancer 类型的 service 通常和云厂商的 LB 结合一起使用,用于将集群内部的服务暴露到外网,云厂商的 LoadBalancer 会给用户分配一个 IP,之后通过该 IP 的流量会转发到你的 service 上。

img

4、ExternalName

创建一个dns别名指到service name上,主要是防止service name发生变化,要配合dns插件使用。通过返回 CNAME 和它的值,可以将服务映射到 externalName 字段的内容。这只有 Kubernetes 1.7或更高版本的kube-dns才支持

5、Ingress

ingress 其实不是 service 的一个类型,但是它可以作用于多个 service,被称为 service 的 service,作为集群内部服务的入口,Ingress 作用在七层,可以根据不同的 url,将请求转发到不同的 service 上。

img

kubernetes四种端口

1、nodePort

nodePort是外部访问k8s集群中service的端口,通过nodeIP: nodePort可以从外部访问到某个service。

2、port

port是k8s集群内部访问service的端口,即通过clusterIP: port可以访问到某个service。

3、targetPort

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

4、containerPort

containerPort是pod内部容器的端口,targetPort映射到containerPort。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tzDEvNY0-1660473072037)(C:\Users\83493\AppData\Roaming\Typora\typora-user-images\1655883729222.png)]

四、创建service

1、创建clusterIP类型

apiVersion: v1
kind: Service
metadata:
  name: nginx1
spec:
  selector:
    app: nginx1
  sessionAffinity: None
  type: ClusterIP
  clusterIP: 10.105.146.177
  ports:
  - name: web
    port: 80
    protocol: TCP
    targetPort: 80

2、创建nodePort类型

apiVersion: v1
kind: Service
metadata:
  name: nginx2
spec:
  selector:
    app: nginx2
  sessionAffinity: None
  type: NodePort
  ports:
  - name: web2
    port: 80
    protocol: TCP
    targetPort: 80
    nodePort: 30080

:
selector:
app: nginx2
sessionAffinity: None
type: NodePort
ports:

  • name: web2
    port: 80
    protocol: TCP
    targetPort: 80
    nodePort: 30080

Logo

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

更多推荐