K8s基础8——svc基础使用、应用暴露、iptables代理、ipvs代理

一、Service基本了解

Service存在的意义?

  • 引入Service主要是解决Pod的动态变化,通过创建Service,可以为一组具有相同功能的容器应用提供一个统一的入口地址,并且将请求负载分发到后端的各个容器应用上。
  • 若提供服务的容器应用是分布式,所以存在多个pod副本,而Pod副本数量可能在运行过程中动态改变,比如水平扩缩容,或者服务器发生故障Pod的IP地址也有可能发生变化。当pod的地址端口发生改变后,客户端再想连接访问应用就得人工干预,很麻烦,这时就可以通过service来解决问题。

概念:

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

svc特点:

  1. 服务发现,防止阴滚动升级等因素导致Pod IP发生改变而失联,找到提供同一个服务的Pod。
  2. 负载均衡,定义一组Pod的访问策略。
    在这里插入图片描述

svc与pod关系:

  • pod在创建时,与资源没有明确关联,通过service标签和pod标签相匹配来以此关联。
  • 可以通过endpoints来查看关联的pod。
    在这里插入图片描述

二、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
在这里插入图片描述

2.3.1 两种创建方式类比

1.先通过kubectl expose方式创建,先创建一个deployment,此时的pod名称为demo1,标签为app=demo1。
在这里插入图片描述
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标签一样。
在这里插入图片描述

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

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

在这里插入图片描述

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

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

在这里插入图片描述
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将其与外部服务关联。
在这里插入图片描述
4.此时进入测试容器验证,可以访问到外部服务。

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

在这里插入图片描述

2.3.4 分配多个端口

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

1.先创建1个pod内有两个容器,一个是Nginx,一个是tomcat。现在需要通过访问80端口到达nginx,访问svc的8080端口到达tomcat。
在这里插入图片描述
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

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

在这里插入图片描述
在这里插入图片描述

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

在这里插入图片描述

2.4 常用三种类型

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

2.4.1 ClusterIP(集群内部访问)

  • 作用:默认分配一个稳定的虚拟IP,即VIP,仅可被集群内部的客户端应用访问。
  • 原理图:
    在这里插入图片描述

2.4.2 NodePort(浏览器访问)

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

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

原理图
在这里插入图片描述
注意事项:

  • NodePort会在每台Node上监听端口接收用户流量,在实际情况下,对用户暴露的只会有一个IP和端口,那这么多台Node该使用哪台让用户访问呢?
  • 这时就需要前面加一个公网负载均衡器为项目提供统一访问入口了。比如在公网机器上部署nginx做负载均衡,配置配置文件upstream ——> 网站A端口30001,upstream2——> 应用服务B端口30002。
    在这里插入图片描述
  • 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。
在这里插入图片描述
3.浏览器访问验证。
在这里插入图片描述
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  ##指定类型。

在这里插入图片描述

2.4.3 LoadBalancer

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

  • 原理图
    在这里插入图片描述

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…

概念图:在这里插入图片描述
数据包传输流程:

  • 客户端 ->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(多副本)(相当于项目本身)

提问:

  • 而这里我们就要看看,我们浏览器访问svc(http://192.168.130.146:30003)是怎么转发到容器内的?
    在这里插入图片描述

3.1 iptables模式

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

在这里插入图片描述
在这里插入图片描述
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规则链过滤查看负载均衡结果。(第二步:负载均衡)
在这里插入图片描述

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.查看其中一个规则链,最后转发到对应容器里。(第三步:转发到容器里)
在这里插入图片描述

3.2 ipvs模式

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

在这里插入图片描述
2.在线编辑kube-proxy文件,修改参数为ipvs模式。

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

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

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

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

yum -y install ipvsadm
  • 查看node1节点没有显示,是因为还是采用的iptables模式。

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

百慕卿君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值