带你玩转kubernetes-k8s(第35篇:核心组件运行机制-kube-proxy与 manger-controller)

释放双眼,带上耳机,听听看~!

独特的Kubernetes Proxy API接口

      前面讲到,Kubernetes API Server最主要的REST接口是资源对象的增、删、改、查接口,除此之外,它还提供了一类很特殊的REST接口—Kubernetes Proxy API接口,这类接口的作用是代理REST请求,即Kubernetes API Server把收到的REST请求转发到某个Node上的kubelet守护进程的REST端口,由该kubelet进程负责响应。
首先来说说Kubernetes Proxy API里关于Node的相关接口。该接口的REST路径为/api/v1/proxy/nodes/{name},其中{name}为节点的名称或IP地址,包括以下几个具体接口:


1
2
3
4
5
1/api/v1/proxy/nodes/{name}/pods/   #列出指定节点内所有Pod的信息
2/api/v1/proxy/nodes/{name}/stats/   #列出指定节点内物理资源的统计信息
3/api/v1/proxy/nodes/{name}/spec/    #列出指定节点的概要信息
4
5

例如,当前Node的名称为k8s-node1,用下面的命令即可获取该节点上所有运行中的Pod


1
2
1curl localhost:8080/api/v1/proxy/nodes/k8s-node1/pods
2

      需要说明的是:这里获取的Pod的信息数据来自Node而非etcd数据库,所以两者可能在某些时间点有所偏差。此外,如果kubelet进程在启动时包含–enable-debugginghandlers =true参数,那么Kubernetes Proxy API还会增加下面的接口:


1
2
3
4
5
6
7
8
9
1/api/v1/proxy/nodes/{name}/run           #在节点上运行某个容器
2/api/v1/proxy/nodes/{name}/exec          # 在节点上的某个容器中运行某条命令
3/api/v1/proxy/nodes/{name}/attach        # 在节点上attach 某个容器
4/api/v1/proxy/nodes/{name}/prorFoward    # 在节点上的Pod端口转发
5/api/v1/proxy/nodes/{name}/logs          # 列出节点的各类日志信息
6/api/v1/proxy/nodes/{name}/metrics       # 列出和该节点相关的Metrics信息
7/api/v1/proxy/nodes/{name}/runingpods    # 列出节点内运行的pod信息
8/api/v1/proxy/nodes/{name}/debug/pprof   # 包括CPU占用情况和内存使用情况
9

        接下来说说Kubernetes Proxy API 里关于Pod的相关接口,通过这些接口,我们可以访问Pod里某个容器提供的服务(如 Tomcat在8080端口的服务):


1
2
3
4
5
1/api/v1/proxy/namespaces/{namespace}/pods/{name}/{path:*}  # 访问pod的某个服务接口
2/api/v1/proxy/namespaces/{namespace}/pods/{name}             #访问Pod
3/api/v1/namespaces/{namespace}/pods/{name}/proxy/{path:*}  # 访问pod的某个服务接口
4/api/v1/namespaces/{namespace}/pods/{name}/proxy    # 访问pod
5

      在上面的4个接口里,后面两个接口的功能与前面两个完全一样,只是写法不同。下

      Pod的Proxy接口的作用和意义了:在Kubernetes集群之外访问某个Pod容器的服务(HTTP服务)时,可以用Proxy API实现,这种场景多用于管理目的,比如逐一排查Service的Pod副本,检查哪些Pod的服务存在异常。

      最后说说Service。Kubernetes Proxy API也有Service的Proxy接口,其接口定义与Pod的接口定义基本一样:/api/v1/proxy/namespaces/{namespace}/services/{name}。比如,若我们想访问MyWeb这个Service,则可以在浏览器里输入http://192.168.18.131:8080/api/v1/proxy/namespaces/default/services/myweb/demo/。

集群功能模块之间的通信

   Kubernetes API Server作为集群的核心,负责集群各功能模块之间的通信。集群内的各个功能模块通过API Server将信息存入etcd,当需要获取和操作这些数据时,则通过API Server提供的REST接口(用GET、LIST或WATCH方法)来实现,从而实现各模块之间的信息交互。

     常见的一个交互场景是kubelet进程与API Server的交互。每个Node上的kubelet每隔一个时间周期,就会调用一次API Server的REST接口报告自身状态,API Server在接收到这些信息后,会将节点状态信息更新到etcd中。此外,kubelet也通过API Server的Watch接口监听Pod信息,如果监听到新的Pod副本被调度绑定到本节点,则执行Pod对应的容器创建和启动逻辑;如果监听到Pod对象被删除,则删除本节点上相应的Pod容器;如果监听到修改Pod的信息,kubelet就会相应地修改本节点的Pod容器。
另一个交互场景是kube-controller-manager进程与API Server的交互。kube-controller-manager中的Node Controller模块通过API Server提供的Watch接口实时监控Node的信息,并做相应处理。
还有一个比较重要的交互场景是kube-scheduler与API Server的交互。Scheduler通过API Server的Watch接口监听到新建Pod副本的信息后,会检索所有符合该Pod要求的Node列表,开始执行Pod调度逻辑,在调度成功后将Pod绑定到目标节点上。
为了缓解集群各模块对API Server的访问压力,各功能模块都采用缓存机制来缓存数据。各功能模块定时从API Server获取指定的资源对象信息(通过List-Watch方法),然后将这些信息保存到本地缓存中,功能模块在某些情况下不直接访问API Server,而是通过访问缓存数据来间接访问API Server。

Controller Manager原理解析

    一般来说,智能系统和自动系统通常会通过一个“操作系统”来不断修正系统的工作状态。在Kubernetes集群中,每个Controller都是这样的一个“操作系统”,它们通过API Server提供的(List-Watch)接口实时监控集群中特定资源的状态变化,当发生各种故障导致某资源对象的状态发生变化时,Controller会尝试将其状态调整为期望的状态。比如当某个Node意外宕机时,Node Controller会及时发现此故障并执行自动化修复流程,确保集群始终处于预期的工作状态。Controller Manager是Kubernetes中各种操作系统的管理者,是集群内部的管理控制中心,也是Kubernetes自动化功能的核心

    Controller Manager内部包含Replication Controller、Node Controller、ResourceQuota Controller、Namespace Controller、ServiceAccount Controller、Token Controller、Service Controller及Endpoint Controller这8种Controller,每种Controller都负责一种特定资源的控制流程,而Controller Manager正是这些Controller的核心管理者。
由于ServiceAccount Controller与Token Controller是与安全相关的两个控制器,并且与Service Account、Token密切相关,所以我们将对它们的分析放到后面讲解。

     在Kubernetes集群中与Controller Manager并重的另一个组件是Kubernetes Scheduler,它的作用是将待调度的Pod(包括通过API Server新创建的Pod及RC为补足副本而创建的Pod等)通过一些复杂的调度流程计算出最佳目标节点,然后绑定到该节点上。

Replication Controller

     为了区分Controller Manager中的Replication Controller(副本控制器)和资源对象Replication Controller,我们将资源对象Replication Controller简写为RC,而本节中的Replication Controller是指“副本控制器”,以便于后续分析。

       Replication Controller的核心作用是确保在任何时候集群中某个RC关联的Pod副本数量都保持预设值。如果发现Pod的副本数量超过预期值,则Replication Controller会销毁一些Pod副本;反之,Replication Controller会自动创建新的Pod副本,直到符合条件的Pod副本数量达到预设值。需要注意:只有当Pod的重启策略是Always时(RestartPolicy=Always),Replication Controller才会管理该Pod的操作(例如创建、销毁、重启等)。在通常情况下,Pod对象被成功创建后不会消失,唯一的例外是当Pod处于succeeded或failed状态的时间过长(超时参数由系统设定)时,该Pod会被系统自动回收,管理该Pod的副本控制器将在其他工作节点上重新创建、运行该Pod副本。
RC中的Pod模板就像一个模具,模具制作出来的东西一旦离开模具,它们之间就再也没关系了。同样,一旦Pod被创建完毕,无论模板如何变化,甚至换成一个新的模板,也不会影响到已经创建的Pod了。此外,Pod可以通过修改它的标签来脱离RC的管控。该方法可以用于将Pod从集群中迁移、数据修复等调试。对于被迁移的Pod副本,RC会自动创建一个新的副本替换被迁移的副本。需要注意的是,删除一个RC不会影响它所创建的Pod。如果想删除一个被RC所控制的Pod,则需要将该RC的副本数(Replicas)属性设置为0,这样所有的Pod副本就都会被自动删除。

      最好不要越过RC直接创建Pod,因为Replication Controller会通过RC管理Pod副本,实现自动创建、补足、替换、删除Pod副本,这样能提高系统的容灾能力,减少由于节点崩溃等意外状况造成的损失。即使你的应用程序只用到一个Pod副本,我们也强烈建议你使用RC来定义Pod。

总结一下Replication Controller的职责,如下所述。
(1)确保在当前集群中有且仅有N个Pod实例,N是在RC中定义的Pod副本数量。
(2)通过调整RC的spec.replicas属性值来实现系统扩容或者缩容。
(3)通过改变RC中的Pod模板(主要是镜像版本)来实现系统的滚动升级。

最后总结一下Replication Controller的典型使用场景,如下所述。

(1)重新调度(Rescheduling)。如前面所述,不管想运行1个副本还是1000个副本,副本控制器都能确保指定数量的副本存在于集群中,即使发生节点故障或Pod副本被终止运行等意外状况。
(2)弹性伸缩(Scaling)。手动或者通过自动扩容代理修改副本控制器的spec.replicas属性值,非常容易实现增加或减少副本的数量。
(3)滚动更新(Rolling Updates)。副本控制器被设计成通过逐个替换Pod的方式来辅助服务的滚动更新。推荐的方式是创建一个只有一个副本的新RC,若新RC副本数量加1,则旧RC的副本数量减1,直到这个旧RC的副本数量为0,然后删除该旧RC。通过上述模式,即使在滚动更新的过程中发生了不可预料的错误,Pod集合的更新也都在可控范围内。在理想情况下,滚动更新控制器需要将准备就绪的应用考虑在内,并保证在集群中任何时刻都有足够数量的可用Pod。

Node Controller

     kubelet进程在启动时通过API Server注册自身的节点信息,并定时向API Server汇报状态信息,API Server在接收到这些信息后,会将这些信息更新到etcd中。在etcd中存储的节点信息包括节点健康状况、节点资源、节点名称、节点地址信息、操作系统版本、Docker版本、kubelet版本等。节点健康状况包含“就绪”(True)“未就绪”(False)和“未知”(Unknown)三种。
Node Controller通过API Server实时获取Node的相关信息,实现管理和监控集群中的各个Node的相关控制功能,Node Controller的核心工作流程如图所示。

带你玩转kubernetes-k8s(第35篇:核心组件运行机制-kube-proxy与 manger-controller)

对流程中关键点的解释如下。
(1)Controller Manager在启动时如果设置了–cluster-cidr参数,那么为每个没有设置Spec.PodCIDR的Node都生成一个CIDR地址,并用该CIDR地址设置节点的Spec.PodCIDR属性,这样做的目的是防止不同节点的CIDR地址发生冲突。
(2)逐个读取Node信息,多次尝试修改nodeStatusMap中的节点状态信息,将该节点信息和Node Controller的nodeStatusMap中保存的节点信息做比较。如果判断出没有收到kubelet发送的节点信息、第1次收到节点kubelet发送的节点信息,或在该处理过程中节点状态变成非“健康”状态,则在nodeStatusMap中保存该节点的状态信息,并用Node Controller所在节点的系统时间作为探测时间和节点状态变化时间。如果判断出在指定时间内收到新的节点信息,且节点状态发生变化,则在nodeStatusMap中保存该节点的状态信息,并用Node Controller所在节点的系统时间作为探测时间和节点状态变化时间。如果判断出在指定时间内收到新的节点信息,但节点状态没发生变化,则在nodeStatusMap中保存该节点的状态信息,并用Node Controller所在节点的系统时间作为探测时间,将上次节点信息中的节点状态变化时间作为该节点的状态变化时间。如果判断出在某段时间(gracePeriod)内没有收到节点状态信息,则设置节点状态为“未知”,并且通过API Server保存节点状态。
(3)逐个读取节点信息,如果节点状态变为非“就绪”状态,则将节点加入待删除队列,否则将节点从该队列中删除。如果节点状态为非“就绪”状态,且系统指定了Cloud Provider,则Node Controller调用Cloud Provider查看节点,若发现节点故障,则删除etcd中的节点信息,并删除和该节点相关的Pod等资源的信息。

ResourceQuota Controller

    作为完备的企业级的容器集群管理平台,Kubernetes也提供了ResourceQuota Controller(资源配额管理)这一高级功能,资源配额管理确保了指定的资源对象在任何时候都不会超量占用系统物理资源,避免了由于某些业务进程的设计或实现的缺陷导致整个系统运行紊乱甚至意外宕机,对整个集群的平稳运行和稳定性有非常重要的作用。
目前Kubernetes支持如下三个层次的资源配额管理。
(1)容器级别,可以对CPU和Memory进行限制。
(2)Pod级别,可以对一个Pod内所有容器的可用资源进行限制。
(3)Namespace级别,为Namespace(多租户)级别的资源限制,包括:
◎ Pod数量;
◎ Replication Controller数量;
◎ Service数量;
◎ ResourceQuota数量;
◎ Secret数量;
◎ 可持有的PV数量。
Kubernetes的配额管理是通过Admission Control(准入控制)来控制的,Admission Control当前提供了两种方式的配额约束,分别是LimitRanger与ResourceQuota。其中LimitRanger作用于Pod和Container,ResourceQuota则作用于Namespace,限定一个Namespace里的各类资源的使用总额。

     如果在Pod定义中同时声明了LimitRanger,则用户通过API Server请求创建或修改资源时,Admission Control会计算当前配额的使用情况,如果不符合配额约束,则创建对象失败。对于定义了ResourceQuota的Namespace,ResourceQuota Controller组件则负责定期统计和生成该Namespace下的各类对象的资源使用总量,统计结果包括Pod、Service、RC、Secret和Persistent Volume等对象实例个数,以及该Namespace下所有Container实例所使用的资源量(目前包括CPU和内存),然后将这些统计结果写入etcd的resourceQuotaStatusStorage目录(resourceQuotas/status)下。写入resourceQuotaStatusStorage的内容包含Resource名称、配额值(ResourceQuota对象中spec.hard域下包含的资源的值)、当前使用值(ResourceQuota Controller统计出来的值)。随后这些统计信息被Admission Control使用,以确保相关Namespace下的资源配额总量不会超过ResourceQuota中的限定值。

Namespace Controller

       用户通过API Server可以创建新的Namespace并将其保存在etcd中,Namespace Controller定时通过API Server读取这些Namespace的信息。如果Namespace被API标识为优雅删除(通过设置删除期限实现,即设置DeletionTimestamp属性),则将该NameSpace的状态设置成Terminating并保存到etcd中。同时Namespace Controller删除该Namespace下的ServiceAccount、RC、Pod、Secret、PersistentVolume、ListRange、ResourceQuota和Event等资源对象。
在Namespace的状态被设置成Terminating后,由Admission Controller的NamespaceLifecycle插件来阻止为该Namespace创建新的资源。同时,在Namespace Controller删除该Namespace中的所有资源对象后,Namespace Controller对该Namespace执行finalize操作,删除Namespace的spec.finalizers域中的信息。
如果Namespace Controller观察到Namespace设置了删除期限,同时Namespace的spec.finalizers域值是空的,那么Namespace Controller将通过API Server删除该Namespace资源。

Service Controller与Endpoints Controller

      本节讲解Endpoints Controller,在这之前,让我们先说下Service、Endpoints与Pod的关系,Endpoints表示一个Service对应的所有Pod副本的访问地址,Endpoints Controller就是负责生成和维护所有Endpoints对象的控制器。
它负责监听Service和对应的Pod副本的变化,如果监测到Service被删除,则删除和该Service同名的Endpoints对象。如果监测到新的Service被创建或者修改,则根据该Service信息获得相关的Pod列表,然后创建或者更新Service对应的Endpoints对象。如果监测到Pod的事件,则更新它所对应的Service的Endpoints对象(增加、删除或者修改对应的Endpoint条目)。
那么,Endpoints对象是在哪里被使用的呢?答案是每个Node上的kube-proxy进程,kube-proxy进程获取每个Service的Endpoints,实现了Service的负载均衡功能。在后面的章节中会深入讲解这部分内容。
接下来说说Service Controller的作用,它其实是属于Kubernetes集群与外部的云平台之间的一个接口控制器。Service Controller监听Service的变化,如果该Service是一个LoadBalancer类型的Service(externalLoadBalancers=true),则Service Controller确保在外部的云平台上该Service对应的LoadBalancer实例被相应地创建、删除及更新路由转发表(根据Endpoints的条目)。

 

小结:

         今天的内容到此为止,最近都是原理蛤,大家简单了解一下就可以了。

         谢谢大家的支持,多多点关注哦。

给TA打赏
共{{data.count}}人
人已打赏
安全运维

故障复盘的简洁框架-黄金三问

2021-9-30 19:18:23

安全运维

OpenSSH-8.7p1离线升级修复安全漏洞

2021-10-23 10:13:25

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索