首页 > 其他分享 >k8s的Service详解

k8s的Service详解

时间:2024-04-30 11:36:14浏览次数:13  
标签:kube Service 端口 svc 详解 proxy 80 k8s pod

一、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.selector Label Selector 配置,将选择具有指定 Label 标签的 Pod 作为管擦绡啷谎理范围 必选
spec.type svc 类型,指定 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.port svc 端口  
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

 

 

 

 

标签:kube,Service,端口,svc,详解,proxy,80,k8s,pod
From: https://www.cnblogs.com/exd1189/p/18167690

相关文章

  • 云原生技术kubernetes(K8S)简介
    详细介绍目录01kubernetes是什么?02kubernetes和Compost+Swarm之间的区别03一点总结今天我们看看kubernetes技术的介绍,最近在极客时间上看张磊老师的深入kubernetes技术,讲的非常好,有兴趣的同学可以去收听一下,对于理解kubernetes技术非常有帮助,这里我会按照自己的进度,分享一下......
  • K8s 开先河、技能全栈、业务“无感”,深度解读云原生的这一年
    此次峰会的同行人包括后来的Kubernetes创始人JoeBeta和CraigMcLuckie,两人联手另一位同事BrendanBurns创立了Heptio,这家公司据传在两年内以数亿美金的价格被VMWare收购。会议当时,CraigMcLuckie还是新成立的谷歌云部门产品经理,而JoeBeda则刚写好内部Kubernetes设计文档,在峰会期......
  • 云原生k8s史上最详细 云原生 serverless
    Serverless是云计算发展的产物,其实不管是云计算还是云原生,亦或者是Serverless架构,他具体是什么,都是很难说得清的,但是这并不影响我们对Serverless架构的理解。一、心智层面去服务器化:专业的事情交给更专业的人,开发者可以更关注于自身业务逻辑字面解释Server和less的:就是将更少的......
  • 云原生周刊:K8s 中的服务和网络 | 2024.4.29
    开源项目推荐k8s-image-swapperk8s-image-swapper是Kubernetes的一个变更Webhook,它将镜像下载到自己的镜像仓库,并将镜像指向该新位置。它是dockerpull-throughproxy的一个替代方案。KubeIPv2KubeIPv2是DoiTKubeIPv1-main开源项目的全面改进版本,最初由AvivLau......
  • Linux Bridge和Tap关系详解
    本文分享自天翼云开发者社区《Linux Bridge和Tap关系详解》,作者:x****nLinux Bridge介绍Bridge(桥)是Linux上用来做TCP/IP二层协议交换的设备,与现实世界中的交换机功能相似。Bridge设备实例可以和Linux上其他网络设备实例连接,既attach一个从设备,类似于在现实世界中的交换机和一......
  • k8s限速队列使用场景分析
    场景1:add->add->get->getpackagemainimport( "fmt" "k8s.io/client-go/util/workqueue")funcmain(){ queue:=workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()) queue.Add(100) queue.Add(100) v,_......
  • XYCTF pwn部分题解 (部分题目详解)
    hello_world(签到)思路:✅这道题就是利用printf函数泄露libc的基地址,然后再次进行栈溢出通过system,/bin/sh来获取shellwp:invisible_flag思路:✅题目提示orw,那我们先看看是否开了沙盒那么是开了沙盒的,试试orw读取flag虽然保护全开但是程序会执行我们写的shellcdoe那么就可......
  • 符文Runes协议技术详解
    最近符文Runes协议是比特币生态最火的项目,于是我利用晚上的时间,把Runes协议使用Go语言实现了一遍,项目地址:https://github.com/bxelab/runestone,另外也基于这个Runestone库编写对应的一个命令行客户端在这里,基于对Runes协议的深入理解,发现网上很多项目对符文的用法是不对的,于是我......
  • Mysql启动报错:Job for mysqld.service failed because the control process exited wi
      该方法会删除mysql数据,慎用centos7上使用yum安装mysql后,启动报错[root@localhost~]#systemctlstartmysqldJobformysqld.servicefailedbecausethecontrolprocessexitedwitherrorcode.See"systemctlstatusmysqld.service"and"journalctl-xe"for......
  • 10分钟搭建k8s
    换桥接模式,换sealos桥接模式部署出问题了,用这个:ipconfig以太网适配器以太网:连接特定的DNS后缀.......:本地链接IPv6地址........:fe80::29f9:1da9:30:3d48%8IPv4地址............:10.1.161.207子网掩码............:......