当前位置:   article > 正文

k8s的Service详解_k8s service

k8s service

一、Service 基本了解

Service 存在的意义?

  • 引入 Service 主要是解决 Pod 的动态变化,通过创建 Service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并且将请求负载分发到后端的各个容器应用上。

  • 若提供服务的容器应用是分布式,所以存在多个 pod 副本,而 Pod 副本数量可能在运行过程中动态改变,比如水平扩缩容,或者服务器发生故障 Pod 的 IP 地址也有可能发生变化。当 pod 的地址端口发生改变后,客户端再想连接访问应用就得人工干预,很麻烦,这时就可以通过 service 来解决问题。

概念:

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

svc 特点:

  1. 服务发现,防止阴滚动升级等因素导致 Pod IP 发生改变而失联,找到提供同一个服务的 Pod。

  2. 负载均衡,定义一组 Pod 的访问策略。

    img

svc 与 pod 关系:

  • pod 在创建时,与资源没有明确关联,通过 service 标签和 pod 标签相匹配来以此关联。

  • 可以通过 endpoints 来查看关联的 pod。

    img

二、Service 定义与创建

2.1 相关命令

命令说明
kubectl create service clusterip web --tcp=80:80命令创建 svc
kubectl apply -f service.yaml定义 yaml 文件创建 svc
kubectl expose deployment webapp命令创建 svc,需要提前创建 deploy
kubectl get service查看 svc

2.2 yaml 文件参数大全

参数释义是否必选
version版本号,例如 v1必选
kind资源对象类型,例如 pod、deployment、service必选
metadata元数据必选
metadata.name对象名称必选
metadata.namespace对象所属的命名空间,默认值为 default必选
metadata.labels自定义标签列表
metadata.annotation自定义注解列表
spec详细定义描述必选
spec.selectorLabel Selector 配置,将选择具有指定 Label 标签的 Pod 作为管擦绡啷谎理范围必选
spec.typesvc 类型,指定 svc 访问方式,默认为 ClusterIP。 1、ClusterP:虚拟服务 IP 地址,用于 K8s 集群内部的 Pod 访问,在 Node 上 kube-proxy 通过设置的 iptables 规则进行转发。 2、NodePort:对外部客户端提供访问应用使用。 3、LoadBalancer:使用外接负载均衡器完成到服务的负载分发,用于公有云环境。必选
spec.clusterlP虚拟服务的 IP 地址。 当 type=ClusterIP 时,若不指定,则系统进行自动分配,也可以手工指定; 当 type=LoadBalancer 时,需要指定。
spec.sessionAffinity是否支持 Session,可选值为 ClientP,默认值为 None。 ClientIP 表示将同一个客户端 (根据客户端的 IP 地址决定) 的访问请求都转发到同一个后端 Pod。
spec.ports定义端口设置列表。
spec.ports.name端口名称
spec.ports.protocol端口协议,支持 TCP、HTTP、UDP、SCTP 等等,默认值为 TCP
Spec.ports.portsvc 端口
spec.ports.targetPort容器端口
spec.ports.nodePort当 spec.type=NodePort 时,指定映射到宿主机的端口号
Status当 spec.ype=lodBalaner 时,设置外部负均衡器的地址,用于公有云环境
status.loadBalancer外部负载均衡器
status.loadBalancer.ingress外部负载均衡器
status.loadBalancer.ingress.ip外部负载均衡器 IP
status.loadBalancer.ingress.hostname外部负载均衡器的主机名
spec.selector指定关联 Pod 的标签必选

2.3 创建 svc

\1. 创建一个 service,名称为 seride-demo,指定类型为 clusterip,第一个 80 是 svc 端口,第二个 80 是容器端口。

[root@k8s-master bck]# kubectl  create service  clusterip service-demo  --tcp=80:80

\2. 查看 svc

img

2.3.1 两种创建方式类比

\1. 先通过 kubectl expose 方式创建,先创建一个 deployment,此时的 pod 名称为 demo1,标签为 app=demo1。

img

\2. 创建一个 svc,名为 demo1,看是否能和 demo1 的 pod 关联上。

[root@k8s-master bck]# kubectl  create svc clusterip demo1 --tcp=80:80

\3. 此时查看 demo1 的 svc 和 demo1 的 pod 关联上了,是因为创建的 svc 标签是和 deployment 创建的 pod 标签一样。

img

2.3.2 验证集群内 A 应用访问 B 应用

我们创建一个 svc 后,会随机分配和 cluster-ip,配合 svc 端口,可以在任何一个节点上访问其他应用。

img

\1. 创建一个 pod,配合上面创建的 svc demo1 来模拟前端访问后端。这里的 bs 为前端,demo1 为后端。进入 bs 容器,通过 clusterip:svc 端口来访问 demo1 前端网页。

img

2.3.3 将集群外服务定义为 K8s 的 svc

  • 将一个 Kubernetes 集群外部的已知服务定义为 Kubernetes 内的一个 Service,供集群内的其他应用访问。

应用场景:

  • 已部署的一个集群外服务,例如数据库服务、缓存服务等。

  • 其他 Kubernetes 集群的某个服务。

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

\1. 准备一个集群外的服务,我这里在 192.168.130.147 上部署一个 nginx 服务。

[root@k8s-node2 ~]# docker run -d --name nginx1 -p 80:80 nginx

img

\2. 此时我想将这个 nginx 服务定义成 K8s 集群内部的 svc,供集群内的其他应用访问。

[root@k8s-master ~]# cat svc.yaml 
---
apiVersion: v1
kind: Service
metadata:
  name: qingjun1
spec:
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
​
---
apiVersion: v1
kind: Endpoints
metadata:
  name: qingjun1   ##与svc名称一致。
subsets:
  - addresses:
      - ip: 192.168.130.147    ##外部服务地址
    ports:
      - port: 80     ##外部服务访问端口
​
[root@k8s-master ~]# kubectl  apply -f svc.yaml 

\3. 查看,此时就会会创建一个 svc 并分配 clusterip,同时 endpoint 将其与外部服务关联。

img

\4. 此时进入测试容器验证,可以访问到外部服务。

[root@k8s-master ~]# kubectl  run bs --image=busybox -- sleep 24h

img

2.3.4 分配多个端口

多端口 Service 定义:对于某些服务,需要公开多个端口,Service 也需要配置多个端口定义,通过端口名称区分。

\1. 先创建 1 个 pod 内有两个容器,一个是 Nginx,一个是 tomcat。现在需要通过访问 80 端口到达 nginx,访问 svc 的 8080 端口到达 tomcat。

img

\2. 创建 svc,编辑 yaml 文件,添加多个端口。

[root@k8s-master bck]# cat svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: web-multi
spec:
  ports:
  # nginx
  - name: 80-80
    port: 80       ##代理nginx80端口。
    protocol: TCP
    targetPort: 80
  # tomcat
  - name: 88-8080
    port: 88        ##代理tomcat8080端口。
    protocol: TCP
    targetPort: 8080
  selector:
    app: web-multi
  type: ClusterIP

img

\3. 通过另外一个 pod 验证,进入 bs 容器,访问 web-multi 里的容器端口。访问 88 端口,则返回 tomcat;访问 80 端口,则返回 nginx。

img

img

ep 相当于 svc 的小弟,就相当于 rs 是 deployment 的小弟,帮忙连接多个 pod。

img

2.4 常用三种类型

类型描述
ClusterIP集群内部使用(Pod)
NodePort对外暴露应用(浏览器)
LoadBalancer对外暴露应用,将 Service 映射到一个已存在的负载均衡器的 IP 地址上,适用公有云
ExternalName将 Service 映射为一个外部域名地址,通过 externalName 字段进行设置。

2.4.1 ClusterIP(集群内部访问)

  • 作用:默认分配一个稳定的虚拟 IP,即 VIP,仅可被集群内部的客户端应用访问。

  • 原理图:

    img

2.4.2 NodePort(浏览器访问)

作用:在每个节点上启用一个端口来暴露服务,可以在集群外部访问。也会分配一个稳定内部集群 IP 地址。 基本常识

  • 访问地址:<任意 NodeIP>:

  • 端口范围:30000-32767

  • 默认情况下,Node 的 kube-proxy 会在全部网卡(0.0.0.0)上绑定 NodePort 端口号。也可以通过配置启动参数 “–nodeport-addresses” 指定需要绑定的网卡 IP 地址,多个地址之间使用逗号分隔。

原理图

img

注意事项:

  • NodePort 会在每台 Node 上监听端口接收用户流量,在实际情况下,对用户暴露的只会有一个 IP 和端口,那这么多台 Node 该使用哪台让用户访问呢?

  • 这时就需要前面加一个公网负载均衡器为项目提供统一访问入口了。比如在公网机器上部署 nginx 做负载均衡,配置配置文件 upstream ——> 网站 A 端口 30001,upstream2——> 应用服务 B 端口 30002。

    img

yaml 文件配置模板

spec:
  type: NodePort  ##修改此处
  ports:
  - port: 80 
    protocol: TCP 
    targetPort: 80 
    nodePort: 30009    ##添加此行,指定端口,也可以不指定,使用随机端口。
  selector: 
    app: web

\1. 配置 svc 的 yaml 文件,指定 NodePort 类型,使用随机端口。

##这里没有指定端口,后面是随机生成一个端口。
[root@k8s-master bck]# vim svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: web-demo1
spec:
  ports:
  # nginx
  - name: 80-80
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: demo1
  type: NodePort    ##指定类型。

\2. 导入 yaml 文件,查看 svc 随机端口为 32580。

img

\3. 浏览器访问验证。

img

\4. 使用指定端口。

[root@k8s-master bck]# cat svc.yaml 
apiVersion: v1
kind: Service
metadata:
  name: web-demo1
spec:
  ports:
  # nginx
  - name: 80-80
    port: 80
    protocol: TCP
    targetPort: 80
    nodePort: 30003   ##指定端口。
  selector:
    app: demo1
  type: NodePort  ##指定类型。

img

2.4.3 LoadBalancer

  • 作用:与 NodePort 类似,在每个节点上启用一个端口来暴露服务。除此之外,Kubernetes 会请求底层云平台(例如阿里云、腾讯云、AWS 等)上的负载均衡器,将每个 Node([NodeIP]:[NodePort])作为后端添加进去。

  • 原理图

    img

2.5 svc 支持的协议

协议是否支持
TCP默认网络协议,支持所有类型的 svc。
UDP可用于大多数类型的 svc,LoadBalancer 类型取决于云服务商对 UDP 的支持。
HTTP取决于云服务商是否支持 HTTP 和实现机制。
PROXY取决于云服务商是否支持 HTTP 和实现机制。
SCTP现已默认启用,如需关闭该特性,则需要设置 kube-apiserver 的启动参数–feature-gates=SCTPSupport=false 进行关闭。

定义 AppProtocol 字段,用于标识后端服务在某个端口号上提供的应用层协议类型,例如 HTTP、HTTPS、SSL、DNS 等。需要设置 kube-apiserver 的启动参数–feature-gates=ServiceAppProtocol=true 进行开启,然后在 Service 或 Endpoint 的定义中设置 AppProtocol 字段指定应用层协议的类型。

三、svc 负载均衡

实现原理:

  • 当一个 Service 对象在 K8s 集群中被定义出来时,集群内的客户端应用就可以通过服务 IP 访问到具体的 Pod 容器提供的服务了。从服务 IP 到后端 Pod 的负载均衡机制,则是由每个 Node 上的 kube-proxy 负责实现的。

实现负载均衡的 2 种方式:

  1. kube-proxy 的代理模式,通过启动参数–proxy-mode 设置。

  2. 会话保持机制。设置 sessionAffinity 实现基于客户端 IP 的会话保持机制,即首次将某个客户端来源 IP 发起的请求转发到后端的某个 Pod 上,之后从相同的客户端 IP 发起的请求都将被转发到相同的后端 Pod 上。

kube-proxy 的代理模式分类:

  1. userspace 模式:用户空间模式,由 kube-proxy 完成代理的实现,效率最低,不推荐。

  2. iptables 模式:kube-proxy 通过设置 Linux Kernel 的 iptables 规则,实现从 Service 到后端 Endpoint 列表的负载分发规则,效率较高。用此模式时需要给 pod 设置健康检查,这样可以避免某个后端 Endpoint 不可用导致客户端请求失败。

  3. ipvs 模式:1.11 版本推出,kube-proxy 通过设置 Linux Kernel 的 netlink 接口设置 IPVS 规则,转发效率和支持的吞吐率达到最高。ipvs 模式要求 Linux Kernel 启用 IPVS 模块,如果操作系统未启用 IPVS 内核模块,kube-proxy 则会自动切换至 iptables 模式。支持负载均衡策略如下:

    • rr:round-robin,轮询。

    • lc:least connection,最小连接数。

    • dh:destination hashing,目的地址哈希。

    • sh:source hashing,源地址哈希。

    • sed:shortest expected delay,最短期望延时。

    • nq:never queue,永不排队。

  4. kernelspace 模式:Windows Server 上的代理模式。

Iptables 模式和 IPVS 模式对比:

  • iptables:灵活、功能强大;规则遍历匹配和更新,呈线性时延

  • IPVS:工作在内核态,有更好的性能;调度算法丰富:rr,wrr,lc,wlc,ip hash…

概念图:

img

数据包传输流程:

  • 客户端 ->NodePort/ClusterIP(iptables/Ipvs 负载均衡规则) -> 分布在各节点 Pod

查看负载均衡规则:

  • iptables 模式:iptables-save |grep <SERVICE-NAME>

  • ipvs 模式:ipvsadm -L -n

项目流程:

  • 项目 a:用户——> LB(基于域名分流 a.com) ——> service nodeport 30001 ——> 一组 pod(多副本)(相当于项目本身)

  • 项目 b:用户——> LB(基于域名分流 b.com)——> service nodeport 30002 ——> 一组 pod(多副本)(相当于项目本身)

  • 项目 c:用户——> LB(基于域名分流 c.com)——> service nodeport 30003 ——> 一组 pod(多副本)(相当于项目本身)

提问:

3.1 iptables 模式

\1. 根据 svc 名称,在工作节点上查看 iptables 规则。

img

img

\2. 将两条规则复制出来分析。(第一步:流量入口)

第一步:浏览器访问 30003 端口,转发到服务器上的网络协议栈,再转发到该服务器的 iptables 来处理,根据 iptables 规则一条条处理。

  • -A KUBE-NODEPORTS -p tcp -m comment --comment “default/web-demo1:80-80” -m tcp --dport 30003 -j KUBE-EXT-72T25B5TU2KEWYA6

第二步:处理完第一条规则,再处理第二条,这里就是访问 cluster IP,访问 pod。

  • -A KUBE-SERVICES -d 10.104.171.31/32 -p tcp -m comment --comment “default/web-demo1:80-80 cluster IP” -m tcp --dport 80 -j KUBE-SVC-72T25B5TU2KEWYA6

\3. 这里给 demo1pod 扩容增加 2 个副本,好看出效果。

[root@k8s-master bck]# kubectl  scale deployment demo1 --replicas=3

\4. 根据 iptables 规则链过滤查看负载均衡结果。(第二步:负载均衡)

img

1.第一个请求第一个规则的权重概率为33%。
-A KUBE-SVC-72T25B5TU2KEWYA6 -m comment --comment "default/web-demo1:80-80 -> 10.244.169.143:80" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-WNIKZVEWSTDE4VLZ
​
2.第二个请求第二个规则权重为50%,因为第一个规则已经请求了,就剩第二、第三个请求了。
-A KUBE-SVC-72T25B5TU2KEWYA6 -m comment --comment "default/web-demo1:80-80 -> 10.244.36.87:80" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-ZM2JCM2TG2VXDQG3
​
3.从第三个请求第三个规则权重为100%,因为此时就剩下最后一条规则,所以请求概率为100%。
-A KUBE-SVC-72T25B5TU2KEWYA6 -m comment --comment "default/web-demo1:80-80 -> 10.244.36.89:80" -j KUBE-SEP-CSYMMWI2AY6NBPWB

\5. 查看其中一个规则链,最后转发到对应容器里。(第三步:转发到容器里)

img

3.2 ipvs 模式

使用此种模式需要手动去修改,因为默认是 iptables 模式。不同的 k8s 集群搭建方式,其修改方式不同。kubeadm 方式修改 ipvs 模式:第一步:修改配置文kube-proxy件参数。 kubectl edit configmap kube-proxy -n kube-system ... mode: “ipvs“ ... 第二步:删除该组Pod,重建所有节点。 kubectl delete pod kube-proxy-btz4p -n kube-system注意事项:kube-proxy 配置文件以 configmap 方式挂载存储。如果让所有节点生效,需要重建所有节点 kube-proxy pod二进制方式修改 ipvs 模式:第一步:编辑修改配置文件。 vi kube-proxy-config.yml mode: ipvs ipvs: scheduler: "rr“ 第二步:重启kube-proxy。 systemctl restart kube-proxy

\1. 查看配置文件位置。

[root@k8s-master bck]# kubectl  get configmap -n kube-system

img

\2. 在线编辑 kube-proxy 文件,修改参数为 ipvs 模式。

[root@k8s-master bck]# kubectl edit configmaps kube-proxy -n kube-system

img

\3. 此时需要删除这组 pod 重建,相当于重启。我这里只删除了一个节点,是为了验证对比效果,正常情况下是要重启所有节点的。

[root@k8s-master bck]# kubectl  delete pod kube-proxy-vkfkh -n kube-system

img

\4. 在删除的 kube-proxy 容器所在节点上验证,我这里删除的是 node2 节点上的 kube-proxy,重启后 ipvs 模式生效;node1 节点没有删除,也就没有重启,依然还是 iptables 模式。使用 ipvs 模式验证需要安装 ipvsadm。

yum -y install ipvsadm

查看 node1 节点没有显示,是因为还是采用的 iptables 模式。

img

查看 node2 节点,此时为 ipvs 模式就显示出路由数据。当访问 node2 节点 IP:30003 时,最后路由到列出来的对应容器里。

img

访问 cluster ip 时,就转发到对应的容器里。

img

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/189814
推荐阅读
相关标签
  

闽ICP备14008679号