9、Service资源管理
connygpt 2024-11-20 14:07 8 浏览
Service资源
Service及Proxy Mode
iptables
ipvs
Service类型
ClusterIP
NodePort
LoadBalancer
ExternalName
Service代理
手动修改代理方式为ipvs
示例一
Service资源
Pod资源在Pod控制器的控制下,可能随时会重启或重构,其实严格意义上来讲Pod是不能被重建的,所谓的重建就是指在原来的基础之上建立一个,但Pod不是这样的,因为在Pod控制器下,一旦这个Pod终止了,我们会发现它和原来的Pod是没有关系的,所以从某种意义上来讲,这是不叫重建的,所以Pod资源存在生命周期,且不可重建,必要时,我们仅能够创建一个替代者,而不是在原来的基础上重构出来的,从某种意义上来讲这叫新建和替代的关系,所以严格意义上来说不是重建,只是一个替代者而已;
Pod控制器是可以实现规模伸缩的,此前使用的scale命令或者直接去修改deployment控制器的副本数量,就能够调整Pod副本数量的,一旦Pod数量增加或减少了,也会导致Pod在访问时的可用及不可用状态的变动,因此Pod相对于这种动态性在很大程度上会给客户端去访问Pod带来困扰,如果使用Pod的IP直接访问Pod,就可能会出现一会儿有,一会儿没有,所以在必要时我们需要增加一个中间层,这个中间层是固定的,只要你不删除和人为修改,这个中间层我们就称为Service,Service本身通过标签选择器,关联拥有相匹配的Pod对象,Service其实也不是直接关联Pod的,甚至说Service压根就不是关联Pod的,而是关联到端点Endpoint,Endpoint引用了Pod,Endpoint就是IP+端口,比如指定了一个某一个Pod的IP+端口,这就是一个Pod的Endpoint,因此Service引用的Endpoint,而Endpoint引用了Pod,因此这个时候客户端向Service请求时,Service能够将其代理并调度至后端不同的Endpoint从而把流量转发给这个Endpoint后端引用的IP地址和端口;
Endpoint后端也不一定是Pod,有的时候,我们的MySQL数据库服务器可能并没有运行在Pod中,而是直接运行在我们的Kubernetes集群之外的主机中,那么这个时候,我们也可以对于这个MySQL做一个端点,让Pod里面服务能直接通过Endpoint访问集群外部的MySQL服务器,这就是为什么集群中加一个中间层的原因,因为被引用的不一定是Pod,也有可能是集群之外其他地方的服务,这就是为什么Service后端是Endpoint的这个中间层,而不是直接的Pod的原因;
Service也是一个标准的kubernetes资源,对它的增删改查的管理操作,依然需要借助于ApiServer进行,但是其实每一个Service,对一个kubernetes实际上来讲,它应该是被转换为每一个节点上的Iptables或ipvs规则,每一个节点都有,因此,以某一个节点为例,这个节点上的Pod它是一个Client客户端,它试图访问某一个Service时,这个Service的IP地址一定在存在于这个Client节点所在的内核的netfilter框架的iptables或者ipvs规则上的,所以一旦这个Pod中的进程,对外发出的网络请求,如果目标的某一个Service,那这个目标地址一定会被当前节点上的iptables或者ipvs匹配到,而这个规则,可能是一个DNAT规则,也可能是一个简单的转发,或者代理规则,它未必是一个DNAT,一般而言不会使用DNAT逻辑,因为Pod到Pod是直接可达的,只有必要的时候才会给它做DNAT;
所以这个时候,我们的内核中的规则,会根据规则中的逻辑,假如它访问的服务的后端有多个Pod,那么这个时候,我们的Service会基于挑选算法或叫调度算法,从这个众多被访问的服务端Pod中挑选出一个Pod出来,并把挑选出来的Endpoint对应的地址,返回给客户端,或者说把流量直接转过去,因此就能使得Client与目标后端Pod直接进行通信了,Service后端有可能是当前集群中的一个Pod,也可能是当前集群之外的具体的服务器提供的服务,不管怎么样,Service会把流量代理带指定的节点上去的,如果就是当前节点上的其他Pod,只不过Service做的仅仅是一个转发而已,如果后端有多个Pod,DNAT虽然有调度功能,但是DNAT支持的调度算法是有限的,我们想实现更强大调度算法应该使用ipvs,因此这儿的规则也可以不是iptables规则,也可以是ipvs规则。
我们的Service随时有可能会被创建、修改、删除,那也就意味着我们每一个节点上的iptables或ipvs规则随时有可能会发生变化,那这个变动如何及时的反映到谋个节点上呢,那么整个集群中的每一个节点上都会运行一个守护进程,如果使用kubeadm去部署,它就是运行为一个Pod,就是我们的kube-proxy,它会在每一个节点上运行为一个Pod,它是一个DaemonSet控制器所控制的Pod,因此每个节点只能有一个,在kubernetes上如果是使用kubeadm部署集群的话,它甚至于会容忍主节点的污点,所以会在主节点上也运行一个;
kube-proxy其实就是ApiServer的客户端,运行在每一个节点上的一个守护进程,并告诉ApiServer监听所有Service资源的变动,一旦ApiServer上某一个Service资源发生变动,ApiServer会立即通知到每一个监视到这个Service的所有kube-proxy,而后kube-proxy转换为iptables或ipvs规则,所以支持Service实现的重要组件就是每一个节点上的kube-proxy进程,这个进程监听所有Service资源的变动,实时将其变动转换为节点上的规则;
Service及Proxy Mode
简单来讲,一个Service对象就是工作节点上的iptables或ipvs规则,用户将到底Service对象IP地址的流量转发至想用的Endpoint对象指向的IP地址和端口之上;
工作于每个工作节点的kube-proxy组件,通过API Server持续监控着各Service及其关联的Pod对象,并将其创建或变动实时反映至当前工作节点上的响应的iptables或ipvs规则,kube-proxy把请求代理至少相应端点的方式有三种:userspace(用户空间)、iptables、ipvs
iptables
对于每个Service对象,kube-proxy会创建iptables规则直接捕获到达ClusterIP和Port的流量,并将其重定向至当前的Service对象的后端Pod资源,对于每一个Endpoint对象,Service资源会为其创建iptables规则并关联至挑选的后端Pod资源对象,相对于用户控件模型来说,iptables无需讲流量在用户控件和内核空间来回切换,因此也就更为高效,kube-proxy只负责维护iptables规则链,当客户端访问到我们的Service的时候,当请求报文到达内核的iptables规则链上,一经匹配,立马转发给后端的Pod;
ipvs
Kubernetes自1.9-alpha起引入ipvs代理模型,且自1.11版本成为默认设置,kube-proxy跟踪API server上Service和Endpoints对象的变动,根据此来调用netlink接口创建ipvs规则,并确保与API server中的变动保持同步;
它与iptables规则的不同之处仅在于其请求流量的调度功能由ipvs实现,余下的其他功能仍由iptables完成,ipvs支持众多调度算法,例如rr、lc、dh、sh、sed和nq等;
Service类型
Service其实是有多种类型的,在定义Service资源时,还有个字段叫type,它就是指定Service类型的,支持ClusterIP、ExternalName、NodePort、LoadBalancer,默认为ClusterIP;
ClusterIP
ClusterIP就是指,给一个Service分配一个当前集群上的位于Service可用网段内的动态地址,如果它是ClusterIP类型,就表示这个服务只可以被集群内机器所访问,脱离集群无法访问,那因此,如果这个Service期望暴露给集群外部的主机访问,那使用ClusterIP的不合适的;
[root@node1 ~]# cat service.yaml
apiVersion: v1
kind: Service
metadata:
name: ccesvc
spec:
ports:
- port: 80 # Service端口
protocol: TCP
targetPort: 80 # 后端Pod端口
selector: # 利用标签选择器来关联后端Pod
app: cce
# 我们的Service也不是直接到后端的Pod对象的,而是通过我们的Endpoint,Endpoints表示一个Service对应的所有Pod副本的访问地址,而Endpoints Controller就是负责生成和维护所有Endpoints对象的控制器.它负责监听Service和对应的Pod副本的变化,如果检测到Service被删除,则删除和该Service同名的Endpoints对象。如果检测到新的Service被创建或者修改则根据该Service信息获得相关的Pod列表,然后创建或者更新Service对应的Endpoints对象;
# 创建一个Service会立马创建一个endpoint,kube-proxy会监控当前主机的Pod的变化,同时也会监控endpoint相关数据,一旦有后端的Pod的label符合endpoint的label就会将其加入endpoint作为后端服务端之一,如果一旦该Pod发生变化会立即剔除;
# Service关联的是Endpoint,而Endpoint通过IP地址+端口关联Pod;
# 查看当前的Pod
[root@node1 ~]# kubectl get pods --show-labels
NAME READY STATUS RESTARTS AGE LABELS
cce-fcd4c8cff-bqvrt 1/1 Running 0 26m app=cce,pod-template-hash=fcd4c8cff
# 查看当前的endpoint
[root@node1 ~]# kubectl get endpoints
NAME ENDPOINTS AGE
ccesvc <none> 4m40s # 此时ccesvc后端没有Pod
kubernetes 172.16.1.2:6443 11d
# 修改Pod的label让endpoint能关联到
[root@node1 ~]# kubectl label pods cce-fcd4c8cff-bqvrt --overwrite app=ce
pod/cce-fcd4c8cff-bqvrt labeled
# 重新查看,Pod已经关联至Endpoint
[root@node1 ~]# kubectl get endpoints
NAME ENDPOINTS AGE
ccesvc 10.244.2.4:80 4m46s
kubernetes 172.16.1.2:6443 11d
NodePort
所谓NodePort是指,对于一个Service来说,它该有的ClusterIP还是有的,但除此之外,我们会在每一个节点上生成一个iptables或ipvs规则,它允许集群外部客户端去访问节点的IP地址和端口,这个节点端口是通过iptables规则进行操作的,比如说节点的80端口映射到clusterIP的80端口,然后由ClusterIP转发到Endpoint继而转发给Pod,所以外部主机通过访问节点的IP和端口就能直接访问到Pod里面的服务了,由于Service的iptables或者ipvs规则是配置的每一个节点上的,所以每一个节点的同一个端口都为NodePort提供服务;
[root@node1 ~]# cat service.yaml
apiVersion: v1
kind: Service
metadata:
name: ccesvc
spec:
type: NodePort
ports:
- port: 80 # Service端口,NodePort不对丢球ClusterIP原有的特性
protocol: TCP
nodePort: 30080 # 只有type为NodePort的时候才能使用nodePort字段,这个字段一般不写,随机
targetPort: 80 # 后端Pod端口
selector:
app: cce
查看创建的Service
[root@node1 ~]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ccesvc NodePort 10.106.142.19 <none> 80:30080/TCP 2m38s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 11d
使用clusterip的方式访问,nodeport不会丢弃clusterip的特性
[root@node1 ~]# curl 10.106.142.19/hostname.html
cce-fcd4c8cff-95sch
使用nodeport的方式访问
[root@node1 ~]# curl 127.0.0.1:30080/hostname.html
cce-fcd4c8cff-95sch
LoadBalancer
LoadBalancer是kubernetes为NodePort类型引入自动管理的外部负载均衡器,它会向底层cloud provider的API发送请求,由其按需创建,用户也可以手动提供负载均衡器,但它不再属于LoadBalancer类型;
ExternalName
ExternalName即为外部名称,它将集群外部Service引入集群内供各Pod客户端使用,我们在创建一个Service时,不指定标签选择器,不选Pod,而是直接指明类型为ExternalName,并externalName定义一个域名,这个域名能够被我们的DNS服务器解析为外部的IP地址,而这个外部的IP地址就是外部提供服务的对应的端点,那这个时候,客户端对此服务的访问就都被转给外部的服务了。这种方式是使用名称的方式来引用的;
Service标签选择器关联Pod的主要作用在于,它能够自动的为关联到的所有Pod创建一个Endpoint资源,那对于ExternalName类型来说,没有标签选择器了,它就不会自动创建Pod,那因此我们可以手动创建一个endpoint,把它的IP地址和端口指向集群之外的主机的IP地址和端口,然后再把这个endpoint作为ExternalName这个Service的引用放,因此所有发送给这个Service的请求都会被转发到手动创建的这个endpoint上面来,从而就调度到了集群外部的主机了;
Service代理
Service能够正常的把客户请求的流量,代理并调度到后端的资源,但是Service与Pod之间并不存在必然的关系,因为Service和Pod之间间隔着一个空间层Endpoint,而Endpoint在我们使用Service时,它会自动帮我们的生成Endpoint,当然我们也可以手动去管理Endpoint,尤其是在后端资源不是Pod的情况下,Endpoint如果手动创建的话,我们可用尝试让Endpoint的名称和Service一样,使得Service能够关联至相关的Endpoint资源,从而在定义Endpoint时引入非标准的客户端Pod,因此我们就可以把集群外部的服务以手工维护Endpoint的形式,映射进集群内部来,也把它组织为Service;
同时Service也能够实现会话保持功能,常见的会话保持有三种方式,通常是会话粘性、会话集群、会话服务器,其中Service本身也能支持会话粘性的方式,它可以实现把来自同一客户端IP地址的请求,始终绑定到同一个后端Pod上,需要在我们定义Service的时候加上一个专用属性sessionAffinity,有两个选项,Node为使用调度算法进行调度,不做会话粘性,ClientIP表示使用ClientIP来做会话粘性,和nginx的iphash,lvs的sh算法;
每一个Service都是有ClusterIP的,ClusterIP也作为Service的访问入口,但是有些场景当中,我们也可以不为Service添加ClusterIP,这种Service叫做无头Service,那么存在ClusterIP的Service时,会在kubernetes的DNS当中将Service Name解析为ClusterIP,一旦没有ClusterIP,会直接将Service Name解析为后端的Pod的IP,而Pod的IP可能不止一个,因此会使用DNS的方式生成多个A记录,实现DNS轮询,这种就叫做无头Service;
Service即便能够代理,并调度客户端请求,但是它只是一个四层代理,无论是iptables还是ipvs,都是由kube-proxy来实现,所以要想实现ipvs的规则类型,需要手动修改kube-proxy的配置,因为kube-proxy决定了你的节点是映射至iptables还是ipvs规则的,在Kubernetes之上我们配置容器应用,靠的是一种资源,这种资源叫做ConfigMap,我们称为配置映射,我们可以在容器外部改一个配置映射中的配置映射的定义,这个定义能够被自动注入到,相关的Pod中的应用之上,被容器所加载和使用,而当前Kubernetes集群所使用的kube-proxy配置是位于kube-system这个名称空间中(kubectl get configmap -n kube-system),当中的kube-proxy其实就是kube-proxy容器中的应用程序所加载的配置信息,而且这是一种集中配置,我们一旦修改了这个配置文件,对所有的kube-proxy容器都是生效的,因此有一种集中配置或者说配置中心的说法;
手动修改代理方式为ipvs
启用ipvs模块
[root@node1 ~]# cat /etc/sysconfig/modules/ipvs.modules
#!/bin/bash
ipvs_mods_dir="/usr/lib/modules/$(uname -r)/kernel/net/netfilter/ipvs"
for mod in $(ls $ipvs_mods_dir | grep -o "^[^.]*"); do
/sbin/modinfo -F filename $mod &> /dev/null
if [ $? -eq 0 ]; then
/sbin/modprobe $mod
fi
done
修改configmap里面的代理方式mode: "ipvs",还可以在ipvs.scheduler字段定义调度算法,默认是rr;
[root@node1 ~]# kubectl edit configmap -n kube-system kube-proxy
安装ipvsadm控制器管理工具
[root@node1 ~]# yum install -y ipvsadm
因为创建集群时使用的iptables创建的kube-proxy,现手动删除原Pod,会自动重建
[root@node1 ~]# kubectl delete pods -n kube-system -l controller-revision-hash=68594d95c
此时我们的ipvsadm就可以看到数据了
[root@node1 ~]# ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags
-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.96.0.1:443 rr
-> 172.16.1.2:6443 Masq 1 0 0
TCP 10.96.0.10:53 rr
-> 10.244.1.3:53 Masq 1 0 0
-> 10.244.2.3:53 Masq 1 0 0
TCP 10.96.0.10:9153 rr
-> 10.244.1.3:9153 Masq 1 0 0
-> 10.244.2.3:9153 Masq 1 0 0
UDP 10.96.0.10:53 rr
-> 10.244.1.3:53 Masq 1 0 0
-> 10.244.2.3:53 Masq 1 0 0
示例一
利用deployment控制器创建三个web服务pod,然后自定义Service,利用externalIPs向外部暴露kubernetes集群内部的Pod服务,这种Service属于ClusterIP;
[root@node1 ~]# cat pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
author: caichangen
name: ccepod
namespace: ccenamespace
spec:
replicas: 3
selector:
matchLabels:
podtype: deploy
template:
metadata:
name: ccepod
namespace: ccenamespace
labels:
podtype: deploy
spec:
restartPolicy: Always
containers:
- image: ikubernetes/myapp:v1
name: ccecontainers
[root@node1 ~]# cat service.yaml
apiVersion: v1
kind: Service
metadata:
name: cceservice
namespace: ccenamespace
spec:
externalIPs: # externalIPs向外部暴露集群内部的服务的通讯地址,暴露给外部的IP
- 172.16.1.2
- 172.16.1.3
ports:
- protocol: TCP # 传输协议
port: 80 # 暴露给外部的端口
targetPort: 80 # 集群内部Pod的端口
selector:
podtype: deploy # 标签选择器,用于选择Pod
[root@node1 ~]# curl -o /dev/null -s -w %{http_code} http://172.16.1.2
200
相关推荐
- 自学Python,写一个挨打的游戏代码来初识While循环
-
自学Python的第11天。旋转~跳跃~,我~闭着眼!学完循环,沐浴着while的光芒,闲来无事和同事一起扯皮,我说:“编程语言好神奇,一个小小的循环,竟然在生活中也可以找到原理和例子”,同事也...
- 常用的 Python 工具与资源,你知道几个?
-
最近几年你会发现,越来越多的人开始学习Python,工欲善其事必先利其器,今天纬软小编就跟大家分享一些常用的Python工具与资源,记得收藏哦!不然下次就找不到我了。1、PycharmPychar...
- 一张思维导图概括Python的基本语法, 一周的学习成果都在里面了
-
一周总结不知不觉已经自学Python一周的时间了,这一周,从认识Python到安装Python,再到基本语法和基本数据类型,对于小白的我来说无比艰辛的,充满坎坷。最主要的是每天学习时间有限。只...
- 三日速成python?打工人,小心钱包,别当韭菜
-
随着人工智能的热度越来越高,许多非计算机专业的同学们也都纷纷投入到学习编程的道路上来。而Python,作为一种相对比较容易上手的语言,也越来越受欢迎。网络上各类网课层出不穷,各式广告令人眼花缭乱。某些...
- Python自动化软件测试怎么学?路线和方法都在这里了
-
Python自动化测试是指使用Python编程语言和相关工具,对软件系统进行自动化测试的过程。学习Python自动化测试需要掌握以下技术:Python编程语言:学习Python自动化测试需要先掌握Py...
- Python从放弃到入门:公众号历史文章爬取为例谈快速学习技能
-
这篇文章不谈江流所专研的营销与运营,而聊一聊技能学习之路,聊一聊Python这门最简单的编程语言该如何学习,我完成的第一个Python项目,将任意公众号的所有历史文章导出成PDF电子书。或许我这个Py...
- 【黑客必会】python学习计划
-
阅读Python文档从Python官方网站上下载并阅读Python最新版本的文档(中文版),这是学习Python的最好方式。对于每个新概念和想法,请尝试运行一些代码片段,并检查生成的输出。这将帮助您更...
- 公布了!2025CDA考试安排
-
CDA数据分析师报考流程数据分析师是指在不同行业中专门从事行业数据搜集、整理、分析依据数据作出行业研究评估的专业人员CDA证书分为1-3级,中英文双证就业面广,含金量高!!?报考条件:满18...
- 一文搞懂全排列、组合、子集问题(经典回溯递归)
-
原创公众号:【bigsai】头条号:程序员bigsai前言Hello,大家好,我是bigsai,longtimenosee!在刷题和面试过程中,我们经常遇到一些排列组合类的问题,而全排列、组合...
- 「西法带你学算法」一次搞定前缀和
-
我花了几天时间,从力扣中精选了五道相同思想的题目,来帮助大家解套,如果觉得文章对你有用,记得点赞分享,让我看到你的认可,有动力继续做下去。467.环绕字符串中唯一的子字符串[1](中等)795.区...
- 平均数的5种方法,你用过几种方法?
-
平均数,看似很简单的东西,其实里面包含着很多学问。今天,分享5种经常会用到的平均数方法。1.算术平均法用到最多的莫过于算术平均法,考试平均分、平均工资等等,都是用到这个。=AVERAGE(B2:B11...
- 【干货收藏】如何最简单、通俗地理解决策树分类算法?
-
决策树(Decisiontree)是基于已知各种情况(特征取值)的基础上,通过构建树型决策结构来进行分析的一种方式,是常用的有监督的分类算法。决策树算法是机器学习中的一种经典算法,它通过一系列的规则...
- 面试必备:回溯算法详解
-
我们刷leetcode的时候,经常会遇到回溯算法类型题目。回溯算法是五大基本算法之一,一般大厂也喜欢问。今天跟大家一起来学习回溯算法的套路,文章如果有不正确的地方,欢迎大家指出哈,感谢感谢~什么是回溯...
- 「机器学习」决策树——ID3、C4.5、CART(非常详细)
-
决策树是一个非常常见并且优秀的机器学习算法,它易于理解、可解释性强,其可作为分类算法,也可用于回归模型。本文将分三篇介绍决策树,第一篇介绍基本树(包括ID3、C4.5、CART),第二篇介绍Ran...
- 大话AI算法: 决策树
-
所谓的决策树算法,通俗的说就是建立一个树形的结构,通过这个结构去一层一层的筛选判断问题是否好坏的算法。比如判断一个西瓜是否好瓜,有20条西瓜的样本提供给你,让你根据这20条(通过机器学习)建立起...
- 一周热门
- 最近发表
- 标签列表
-
- kubectlsetimage (56)
- mysqlinsertoverwrite (53)
- addcolumn (54)
- helmpackage (54)
- varchar最长多少 (61)
- 类型断言 (53)
- protoc安装 (56)
- jdk20安装教程 (60)
- rpm2cpio (52)
- 控制台打印 (63)
- 401unauthorized (51)
- vuexstore (68)
- druiddatasource (60)
- 企业微信开发文档 (51)
- rendertexture (51)
- speedphp (52)
- gitcommit-am (68)
- bashecho (64)
- str_to_date函数 (58)
- yum下载包及依赖到本地 (72)
- jstree中文api文档 (59)
- mvnw文件 (58)
- rancher安装 (63)
- nginx开机自启 (53)
- .netcore教程 (53)