菜鸟学Kubernetes(K8s)系列——(七)关于Kubernetes底层工作原理
Kubernetes系列文章 | 主要内容 |
菜鸟学Kubernetes(K8s)系列——(一)关于Pod和Namespace | 通过本文你将学习到: (1)什么是Pod,为什么需要它、如何创建Pod、Pod的健康检查机制(三种探针) (2)什么是标签、标签选择器 (3)什么是Namespace、他能做什么、如何创建它等等 |
菜鸟学Kubernetes(K8s)系列——(二)关于Deployment、StatefulSet、DaemonSet、Job、CronJob | 通过本文你将学习到: (1)什么是Deployment,如何创建它、它的扩缩容能力是什么、自愈机制,滚动升级全过程、如何进行回滚 (2)什么是ReplicaSet、它和Deployment的关系是什么 (3)动态扩缩容能力(HPA)、蓝绿部署、金丝雀部署 (4)什么是DaemonSet/Job/CronJob、它们的功能是什么、如何创建使用等等 |
菜鸟学Kubernetes(K8s)系列——(三)关于Service、Ingress | 通过本文你将学习到: (1)什么是Service,如何创建它、它的服务发现能力、对外暴露方式 (2)什么是NodePort类型的Service,它的使用方式、工作原理 (3)什么是Ingress,如何创建它、为什么需要Ingress (4)什么的Ingress-Nginx、他和Nginx是什么关系、Ingress的各种功能 (5)什么是headless服务等等 |
通过本文你将学习到: (1)什么是Volume卷、它的几种类型(emptyDir、hostPath、NFS)、这几种类型是使用方式 (2)什么是PV-PVC、为什么要用他们、他们是怎么协作的、如何使用PV-PVC (3)动态配置持久卷是什么,它是怎么工作的、如何实现动态的分配PV等等 | |
通过本文你将学习到: (1)什么是ConfigMap,如何创建它、它能用来做什么事情、在实战中怎么使用ConfigMap (2)什么是Secret,如何创建它,怎么使用它等等 | |
通过本文你将学习到: (1)Api-Server的认证授权流程(2)什么是ServiceAccount(3)什么是Role、ClusterRole、RoleBinding、ClusterRoleBinding,如何使用他们,他们之间是如何关联协作的。等等 | |
通过本文你将学会实现Deployment的动态扩缩容能力(HPA) | |
通过本文你将学会安装Ingress-Nginx |
十二、Kubernetes底层工作原理
1、Kubernetes的核心组件
一个Kubernetes集群是由一组被称作节点(Node)的机器组成,这些节点上会运行由Kubernetes所管理的所有资源。 Kubernetes集群中核心组件有:Control Plane(控制面板)组件、Kubelet组件和Kube-proxy组件。通常情况下,我们称部署Control Plane组件的节点为Master Node(主节点),称部署Kubelet组件和Kube-proxy组件的节点为Worker Node(工作节点)。另外,每个集群至少有一个工作节点。
- Master Node
- Etcd
- Api-Server
- Scheduler
- Controller-Manager
- Worker Node
- Kubelet
- Kube-proxy
- Container Runtime
1.1 Control Plane组件
Control Plane主要负责为集群做出全局决策,使得整个集群正常运转。
- Control Plane中包含四个子组件:Etcd、Api-Server、Schedule、Controller-Manager。接下来我们看看这四个组件分别负责什么工作。
(1)Etcd
在K8s中我们创建的所有资源(Deployment、Service、Pod等等)都是会被持久化存储到Etcd中的。他也是整个集群中唯一存储数据信息的地方。Etcd是一个响应快、分布式、一致的key-value存储。因为他是分布式的,所以可以运行多个Etcd实例来获取更高的性能。
唯一能和Etcd进行通信的就是后面要说的Api-Server。其他组件都是通过Api-Server间接地读取、写入数据到Etcd。这样做的好处就是可以增强乐观锁系统、验证系统的健壮性。同时,通过把实际的存储机制从其他组件中抽离出来,未来在进行替换的时候也会很方便。
乐观并发控制(也就是乐观锁)是指一段数据包含一个版本号,每当客户端(如Kubectl)更新这段数据时,就会检查当前数据的版本值是否在客户端读取数据时间和提交修改时间之间被增加过。如果增加过,那么更新就会被拒绝,客户端必须重写获取新的数据,然后重新尝试更新。当更新成功,这段数据的版本号会加1。因此,当有两个客户端尝试更新同一个数据条目时,只会有一个成功。而当客户端在读取数据时他是不需要判断版本号的。
我们可以看到所有的K8s资源的定义信息中都存在一个resourceVersion属性,这就是他的版本号。
我在系统中随便找了一个pod,然后输出他的yaml文件(kubectl get pod fortune-configmap -o yaml
),可以看到:
K8s资源在Etcd中的存储方式
K8s的资源在Etcd中是以K-V键值对的形式存储的,如下。(注意这个/
只是Etcd中key的一种命名格式,大家不要误认为他是一个目录)
运行命令:
etcdctl --cert /etc/kubernetes/pki/etcd/peer.crt --key /etc/kubernetes/pki/etcd/peer.key --insecure-skip-tls-verify --endpoints=localhost:2379 get / --prefix --keys-only
可以看到打印出了很多的key(我截取了部分的),如果我们在用这个key,就可以再获取到他的具体的value值:
etcdctl --cert /etc/kubernetes/pki/etcd/peer.crt --key /etc/kubernetes/pki/etcd/peer.key --insecure-skip-tls-verify --endpoints=localhost:2379 get /registry/pods/default/fortune-configmap --prefix --keys-only
他这是对value进行了编码,我们大致从里面的信息可以猜出,他这个value存的就是我们资源的定义信息。
(2)Api-Server
Kubernetes系统组件间都只能通过Api-Server进行通信。
- Api-Server除了将客户端(如kubectl)传来的资源信息存入Etcd中,还对这些资源进行校验,这样客户端就不能存入非法的资源信息。
- Api-Server还会处理乐观锁,这样对于并发更新的情况,对对象做更改就不会被其他客户端覆盖。
当我们创建一个资源,Api-Server都做了哪些工作?
当我们通过Kubectl创建一个资源后,他会通过一个HTTP POST请求将资源定义信息发送给Api-Server。当Api-Server接收到创建资源的请求后:
- 通过认证插件认证客户端:确认是谁发送的请求。
他首先会轮流调用所有的认证插件,直到有一个能确认**(因此不用遍历完所有的认证插件)**是谁发送了该请求(这是通过检查HTTP请求来实现的)。
根据认证方式,用户信息可以从客户端证书 或者 HTTP的请求头Authorization获取。插件会抽取客户端的用户名、用户ID和归属组,这些信息会交给下一些段授权是时候使用。
- 通过授权插件授权客户端:决定认证的用户是否可以对请求资源执行请求操作。
认证完成后来到授权阶段,同样,Api-Server中可以配置多个授权插件。
比如,当创建Pod时,Api-Server会轮询所有的授权插件,来确认该用户是否可以在请求命名空间创建Pod。一旦插件确认了用户可以执行该操作**(因此不用遍历完所有的授权插件)**,Api-Server会继续进行下一步骤。
- 通过准入控制插件验证:它主要对传入的资源进行修改完善。
如果请求尝试创建、修改或者删除一个资源,请求需要经过准入控制插件(Adminssion control plugin)的验证。准入控制插件也可以有多个。
这些插件会因为各种原因修改资源,可能会初始化资源定义中漏配的字段为默认值,甚至重写他们(比如我创建一个Pod资源,在资源中忘记写了metadata.namespace属性,那么他会默认补上这个属性,同时赋值为default)。插件甚至会去修改并不在请求中的相关资源,同时也会因为某些原因拒绝一个请求。每个请求传入的资源都必须经过所有的准入控制插件的验证。
注意:如果请求只是尝试读取数据,则不会做准入控制的验证。
- 准入控制插件包括:
- AlwaysPullImages:重写Pod的imagePullPolicy为Always,强制每次部署Pod时拉取镜像。
- ServiceAccount:当资源未明确定义服务账户时,则使用默认的账户。
- NamespaceLifecycle:防止在命名空间中创建正在被删除的Pod,火灾不存在的命名空间中创建Pod。
- ResourceQuota:保证特定命名空间中的Pod只能使用该命名空间分配数量的资源,如CPU和内存等。
- 其他更多的准入控制插件>>>
- 验证资源以及持久化存储
请求通过了所有的准入控制插件以后,Api-Server会验证存储到Etcd的对象,然后返回一个响应给客户端。
Api-Server的监听机制
上面提到了Api-Server会做一些验证工作,然后将资源存储到Etcd中,除此以外,他不会在做任何额外的工作。他不会去创建资源,也不会去部署资源,这些都是交给其他组件来完成的。他只是在资源发生变更时通知这些组件,然后这些组件再执行自己需要完成的任务。(集群中的组件是可以订阅资源被创建、修改或删除的通知的。这就是Api-Server的监听机制。)
这些组件通过创建到Api-Server的HTTP连接来监听变更。通过此连接,各个组件会接收到监听对象的一些列变更通过。每当更新对象,服务器把新版本对象发送至所有监听该对象的组件。
(3)Schedule
Schedule调度器主要用来计算要部署的Pod应该运行在集群的哪个节点上。他会通过Api-Server的监听机制等待新创建的Pod,然后给每个新的、没有节点集的Pod分配节点,通过Api-Server更新Pod资源的定义信息。
Schedule的默认调度算法
选择节点的过程可分为两部分:
- 过滤所有节点,找出能分配给Pod的可用节点列表。
上海杨大妈来到了公园中的相亲角,准备从形形色色的男人们中帮女儿选择一个合适的女婿。首先进行初筛阶段。
- 为了决定哪些节点对Pod可用,调度器会给每个节点下发一组配置好的预测函数。这些函数检查:
为了决定哪些男生可以嫁给自己的女儿,杨大妈会对前来相亲的男生做一系列的考核审查。下面是一些硬性的初筛条件。
- 节点能否满足Pod对硬件资源的请求?
男方是否在上海有车有房?
- 节点是否耗尽资源?
买完车买完房后还是否有存款?
- Pod是否要求被调度到指定节点(通过名字判断),是否是当前节点?
女儿是不是已经有指定的意中人,只是来让杨妈妈来相亲角之间找指定的男方。
- 节点是否有和Pod规格定义里的节点选择器一致的标签(如果定义了的话)?
如果杨妈妈的女儿特意给杨妈妈说,我要身高必须在170cm以上的,而且是单眼皮的。那么杨妈妈会按照指定的这个标准来选女婿。
- 如果Pod要求绑定指定的主机端口,那么这个节点的这个端口是否已经被占用?
如果杨妈妈的女儿还要求,我必须是男方的一婚。那么如果男方是离过婚的,杨妈妈也就不会考虑找他了。
- 如果Pod要求特定类型的卷,该节点是否能为此Pod加载此卷,或者说该节点上是否已经有Pod在使用该卷了?
如果杨妈妈的女儿指定在上海房必须在上海市浦东新区xxx小区xxx单元xxx号,那么如果男方的房不在这里,也就不会被考虑了。
- Pod是否能够容忍节点的污点。(后面会讲到关于污点的概念)
如果男方脸上有麻子,能不能接受?女儿不能接受也是不会被考虑的。
- 上面这些测试都必须通过,节点才有资格调度给Pod。在对每个节点做完这些检查后,调度器得到节点集的一个子集。任何这些节点都可以运行Pod,因为他们都有足够的可用资源,也确认过满足Pod定义的所有要求。
通过了上面重重审核后的男生,才能进入杨妈妈的备选库里,听清楚,你们才有资格嫁给杨妈妈的女儿,虽然说你们足够的优秀。下面还会进入二轮面试,跟杨妈妈的女儿正式见面。
- 对可用节点按优先级排序,找出最优节点。(如果多个节点都有最高的优先级分数,那么则循环分配,确保平均分配给Pod。)
经历重重难过,终于和杨妈妈的女儿要见面了,不过还要排队。因为在进入第二轮的不仅你一个。杨妈妈的女儿会一个一个的见面,看看男生的人品怎么样呀?三观正不正呀?等等。杨妈妈的女儿会从中筛选出最优质的那一个,然后嫁给他!
关于Schedule调度器,我们可以实现自己的调度器,部署到集群中,而不使用K8s默认的调度算法。
(4)Controller-Manager
前面提到:Api-Server只做了存储资源到Etcd和通知组件有变更的工作。Schedule则只是给Pod分配节点。现在还需要有一个**一直活跃的组件来确保集群中各个资源的真实状态朝着资源定义信息中期望的状态收敛。**这个工作是由Controller-Manager中各个控制器来实现的。
什么是资源的真实状态?什么是资源定义信息中的期望状态?
- 资源真实状态就是指的在集群中实际运行的,比如Pod。(我们可以通过
kubectl get pod
来查看)- 而期望的状态指的是,资源定义信息中spec中指定的信息。
apiVersion: apps/v1 kind: Deployment metadata: name: dep-v2 ### 遵循域名编写规范 namespace: default labels: app: test-01 ### 期望状态 spec: replicas: 5 ### 期望副本你数量 selector: ### 选择器,指定Deployment要控制的所有的Pod的共同标签(即帮助Deployment筛选他要控制哪些Pod) matchLabels: pod-name: ppp ### 和模板template里面的Pod的标签必须一样 ### 编写Pod template: metadata: ### Pod的metadata labels: pod-name: ppp spec: containers: - name: nginx-01 image: nginx
比如这个Deployment,他期望可以有5个包含pod-name: ppp标签的Pod副本。
Controller-Manager组合的控制器有:
- ReplicaSet、DaemonSet以及Job控制器
- Deployment控制器
- StatefulSet控制器
- Node控制器
- Service控制器
- Namespace控制器
- PersistentVolume控制器
- 其他控制器
- 自定义的控制器
一个控制器至少追踪一种类型的 Kubernetes 资源。从每个控制器的名字我们几乎就可以知道创建的每个资源对应的控制器是什么。
资源描述了集群中应该运行什么,他的期望是什么,而控制器就是为资源实现目标的工具,也被称作为控制回路。意思就是说他们是一个永不休止的循环器,通过Api-Server监听机制来订阅属于自己控制器管理的资源的变更,然后执行一个“调和”循环,将实际状态调整为期望状态,然后将新的实际状态写入资源的status部分(资源的一个属性)。
这些控制器的工作原理基本相同,下面我们主要讲解几个比较熟悉的控制器。
ReplicaSet控制器
ReplicaSet控制器会通过Api-Server的监听机制订阅可能影响他期望的副本集的数量或者符合条件Pod数量变更事件。任何该类型的变化,都会触发控制器重新检查期望的以及实际的副本数量,然后做出相应的操作。
比如当正在运行的Pod数量少于ReplicaSet所期望的副本数量时,ReplicaSet控制器就会创建新的Pod清单,然后发布给Api-Server,再让Schedule调度器以及Kublet来做调度工作并运行Pod。(Kublet是负责运行Pod的,后面会说)
Deployment控制器
每次Deployment资源被修改后(如果修改会影响到部署的Pod),Deployment控制器都会滚动升级到新的版本。通过创建要给ReplicaSet,然后按照Deployment中定义的策略同时伸缩新、旧ReplicaSet,直到旧的Pod被新的代替。
唤醒控制器
再次强调,所有这些控制器都是通过Api-Server来操作资源对象的,他们不会直接和Kublet通信或者发送任何类型的指令。实际上,他们都不知道Kubelet的存在。控制器更新Api-Server的一个资源后,Kubelet和Kube-proxy会做他们的工作,例如启动Pod容器,加载网络存储,或者就服务而言,创建跨Pod的负载均衡。
(5)埋点
Control Plane的这些组件都是可以直接部署在系统上或者作为Pod来运行的。
咦?以Pod来运行???Control Plane不是用来负责全局决策的么?怎么还能以Pod的方式与运行?这不是一个先有鸡还是先有蛋的问题吗?
在了解了Kubelet创建静态Pod后你就能打消上面的疑惑了。
1.2 Worker Node中的组件
所有的Control Plane的控制器都运行在主节点上,而Kubelet以及Kube-proxy都运行在工作节点上。(实际上也不仅仅是工作节点上,只要有Pod的节点,肯定都离不开这两个组件。)
(1)Kubelet的工作内容
Kubelet是唯一一直作为常规系统组件来运行的组件,他的工作就是创建Pod实例并监控。当Schedule选择好要调度的节点,并通过Api-Server更新Pod资源的定义信息后,目标节点的Kubelet会监听到Api-Server发来的通知,然后创建并运行Pod的容器。随后他会持续监控运行的容器,实时向Api-Server报告他们的状态、事件和资源消耗。
Kubelet也是运行容器存活探针的组件,当探针报错时,他会重启容器。最后一点,当Pod从Api-Server删除时,Kubelet会终止容器,并通知Api-Server,Pod已经被终止了。
Kubelet运行静态Pod
前面我们说到,Kubelet在哪创建什么Pod完全是由Api-Server通知给他的。实际上他还能主动的创建Pod,它可以通过本地指定目录下的Pod资源清单来运行Pod。这也就解释了前面埋的点,为什么可以提前以Pod的形式部署Control Plane的组件。
也可以以同样的方式运行自定义的系统容器,但是还是推荐通过DaemonSet来实现这一操作。
(2)Kube-proxy的作用
除了Kubelet,每个工作节点还会运行一个kube-proxy,用来确保客户端可以通过Kubernetes API连接到你定义的服务。kube-proxy确保对服务IP和端口的连接最终能达到支持服务的某个Pod处。如果一个Service选择了多个Pod,那么kube-proxy会发挥对Pod的负载均衡作用。
Kube-proxy支持多种代理模式,主要的就是iptables和ipvs。不过在v1.11版本后就推广使用ipvs了,因为他的性能更好!
iptables代理方式
在这种模式下,kube-proxy监视Api-Server中Service(和Endpoint)的变化情况。对于每个Service,它都生成相应的iptables规则,这些规则捕获到Service的clusterIP和port的流量,并将这些流量随机重定向(iptables只支持这一种负载均衡模式)到Service后端Pod。当一个Service负载多个Pod,则他会为每一个后端Pod生成一条iptables规则。
ipvs代理方式
为什么要选择ipvs?
iptables难以扩展到成千上万的服务,因为它纯粹是为防火墙而设计的,并且基于内核规则列表。在v1.6版本时Kubernetes集群就可以支持有5000个节点,但是使用iptables的kube-proxy实际上是将集群扩展到5000个节点的瓶颈。比如,我们在5000个节点中创建了2000个NodePort Service,而且每个Service负载了10个Pod,那么这样就会在每个工作节点上至少产生20000个iptables记录,这就会让内核变得非常繁忙。(因为没接收一个请求,他都要从20000个记录中找一个记录)
而使用基于ipvs的集群内服务负载均衡可以为这种情况提供很多帮助。ipvs专门用于负载均衡,并使用更高效的数据结构(哈希表),允许几乎无限的规模扩张。
IPVS (IP Virtual Server)是在 Netfilter 上层构建的,并作为 Linux 内核的一部分,实现传输层负载均衡。
在 ipvs
模式下,kube-proxy 监视 Kubernetes 服务和端点,调用 netlink
接口相应地创建 ipvs
规则, 并定期将 ipvs
规则与 Kubernetes 服务和端点同步。该控制循环可确保 ipvs
状态与所需状态匹配。访问服务时,ipvs
将流量定向到后端 Pod 之一。
说明:
要在 IPVS 模式下运行 kube-proxy,必须在启动 kube-proxy 之前使 IPVS 在节点上可用。
开启ipvs的方式:
#1、查看默认kube-proxy 使用的模式kubectl logs -n kube-system kube-proxy-28xv4 #2、需要修改 kube-proxy 的配置文件,修改mode 为ipvs。默认iptables,但是集群大了以后就很慢 kubectl edit cm kube-proxy -n kube-system # 修改如下 ipvs: excludeCIDRs: null minSyncPeriod: 0s scheduler: "" strictARP: false syncPeriod: 30s kind: KubeProxyConfiguration metricsBindAddress: 127.0.0.1:10249 mode: "ipvs" ### 这里改为ipvs ###修改了kube-proxy的配置,为了让重新生效,需要杀掉以前所有的Kube-proxy kubectl get pod -A|grep kube-proxy ###有三个 kubectl delete pod kube-proxy-pqgnt -n kube-system kubectl delete pod kube-proxy-pqgnt -n kube-system kubectl delete pod kube-proxy-pqgnt -n kube-system ### 修改完成后可以重启kube-proxy以生效
当 kube-proxy 以 IPVS 代理模式启动时,它将验证 IPVS 内核模块是否可用。 如果未检测到 IPVS 内核模块,则 kube-proxy 将退回到以 iptables 代理模式运行。
ipvs支持多种负载均衡模式:
- rr:轮替(Round-Robin)
按依次循环的方式将请求调度到不同的服务器上
- lc:最少链接(Least Connection),即打开链接数量最少者优先
这个算法会根据后端 RS 的连接数来决定把请求分发给谁,比如 RS1 连接数比 RS2 连接数少,那么请求就优先发给 RS1
- dh:目标地址哈希(Destination Hashing)
该算法是根据目标 IP 地址通过散列函数将目标 IP 与服务器建立映射关系,就算出现服务器不可用或负载过高的情况下,发往该目标 IP 的请求会固定发给该服务器。
- sh:源地址哈希(Source Hashing)
与目标地址散列调度算法类似,但它是根据源地址散列算法进行静态分配固定的服务器资源。
- sed:最短预期延迟(Shortest Expected Delay)
- nq:从不排队(Never Queue)
1.3 总结
我们发现,整个Kubernetes系统是由相对小的、完善功能划分的松耦合的组件构成。Api-Server、Schedule、Controller-Manager中的控制器、Kubelet以及kube-proxy一起合作来保证在Kubernetes中运行的实例和我们在资源中定义期望的状态达到一致。
2、各个组件的协作流程
当我们创建一个Deployment资源,通过kubectl发送HTTP POST请求到Kubernetes api-server后,controller、schedule、kubelet就开始通过api-server监听他们各自监听的资源类型的变化了。下面看看各个组件到底是如何协作的。
- 在我们部署任何资源前,集群中的Scheduler、Controller-Manager、Kubelet都一直监听Master的Api-Server发来的事件变化(for ::)
- 当我们通过
kubectl apply
提交一个Deployment资源到Api-Server后,Api-Server首先会进行资源验证。- 验证通过后将Deployment存储到Etcd中。
- 接着Controller-Manager(中的Deployment控制器)会监听到Api-Server中创建Deployment的事件,然后他会处理这个事件。
- Deployment控制器会按照这个Department资源定义创建一个ReplicaSet资源,并交给Api-Server。(Api-Server会交给Etcd保存)
前面我们了解到Deployment控制ReplicaSet,ReplicaSet管理Pod。
- 新创建ReplicaSet的事件会被ReplicaSet控制器监听到,ReplicaSet控制器会检查看正在运行的Pod(需要标签是匹配的)的数量有没有达到ReplicaSet中期望的副本数。
- 如果正在运行的Pod没有达到它预期的数量,则ReplicaSet控制器会基于ReplicaSet的Pod模板创建Pod资源,并交给Api-Server。(Api-Server会交给Etcd保存)
- 接着Schedule会监控Api-Server中新创建的且nodeName属性还没有被设置的Pod。
- 每发现一个,Schedule就会为这个Pod计算看他应该被部署到哪个节点上,然后将要部署的节点信息写到Pod定义中,发送给Api-Server再保存到Etcd中。
- 所有工作节点的Kubelet会专门监听Api-Server,判断看有没有Pod被调度到了自己的节点上。
- 如果有那就会在自己的Node上部署这个Pod,部署成功后将信息返回给Api-Server。
2.1 通过一个场景了解Kubernetes的工作原理
我们把整个K8s集群当作一个公司集团。Control Plane就是集团的总部,即Master Node;不同的Worker Node相当于集团的分部。总部总会有一个决策者来进行决策公司需要做什么项目,这个决策者即Controller Manager。他签署的决策文件将会存储在etcd中,当然整理文件信息的事不是由他来做,他做出决策后会由部门秘书,即Api Server,来将这些决策文件存储在etcd中,这个etcd相当于是公司的档案管理中心,来存储重要文件信息。决策者做完决策后需要由不同的分厂来进行实现,那具体由谁来做呢,就需要Scheduler调度者来进行调度,他会根据不同厂的不同特性,来将项目进行分配。当然scheduler也会将他的决策信息交给部门秘书,让她存储在etcd中,然后部门秘书在通知不同的分厂来完成这个项目,不同的分部也会有一个管理者——厂长,即kubelet,来监控控制自己部门的运行情况。(每个应用都是由当前所在机器节点的kubelet来负责应用的启停销毁等操作。)厂长会时不时的探测自己负责的节点的应用运行情况,如果哪个应用实在不能正常工作了,他就会汇报给总部,打电话给秘书(Api Server),说我们厂的这个项目实在做不了了,秘书部会通知决策者,A厂无法完成交给他的项目了,这时决策者就会决策,那就把这个项目交给其他厂(并没有指明哪个厂),然后这将个决策信息会传给秘书,秘书存在etcd中,然后秘书在通知调度者,刚刚领导人说让别人去完成这个项目了,你重新分配一下,然后调度者在动态计算看应该让哪个分厂去完成这个项目,然后把这条信息存在etcd中。当领导和调度者都决策完了以后,秘书会通知工作节点的kubelet(其实也不是秘书主动通知,而是每个厂的厂长每天都会跟秘书通电话,打通电话后,秘书会说今天告诉你个好消息,有个项目需要在你们厂来完成)。项目启动后,厂长会每天监控项目的情况,然后跟秘书通电话。
如果有人需要访问某个项目,就会来到一个分部,问门卫大爷,即kube-proxy(该分厂的访问入口,kube-proxy负责所有应用的访问,比如应用A想要访问应用B,就先问问kube-proxy,大爷,应用B在哪。大爷就会告诉他应用B在A厂和B厂都有),你们厂的这个项目都在哪,如果这个项目不在这个厂,看门大爷就会说,我们厂没有做这个项目,你应该去B厂去找。至于看门大爷为什么会轻车熟路知道这个项目是在B厂完成的,是因为看门大爷没太多事,总是和不同厂的大爷坐在一块唠嗑,互相打探消息,同步信息,所以他们之间消息是互通的。
其实k8s集群的总部是一个傀儡,真正决定做什么项目是由我们程序员决定的,程序员敲一行命令
kubectl create deploy myapp --image=nginx
,告诉k8s给我部署一个nginx的应用。程序员发送的这条命令其实也是发送给的秘书部(Api Server),秘书在传给决策者。
2.2 总结
- 集群中所有组件的交互都是通过Api Server
- 集群中所有的网络访问都是通过kube-proxy
- 集群中运行的所有应用程序都要有容器运行时环境
- 集群中每个节点都要有一个监工:kubectl
未完,待续>>>
参考:Kubernetes in Action