文章目录
1. 背景
充分借助 K8s 的优点,减少运维人员的压力,最大限度的提升设施资源的利用率。对 K8s 的核心组件,及其拥有的能力的进行调研。
1.1 K8s 系统架构图
Kubermetes 各个核心组件功能很清晰:
- API Server:提供了资源对象的唯一操作入口,其他所有组件都必须通过它提供的 API 来操作资源数据,通过对相关的资源数据「全量查询」+ 「变化监听」,这些组件可以很「实时」地完成相关的功能,比如某个新的 Pod 一旦被提交到 API Server 中,Controller Manager 就会立即发现并开始调度。
- Controller Manager:集群内部的管理控制中心,其主要目的是实现 Kubernetes 集群的故障检测和恢复的自动化工作:
- 根据 RC 的定义完成 Pod 的复制或移除,以确保 Pod 实例数符合 RC 副本的定义
- 根据 Service 与 Pod 的管理关系,完成服务的 Endpoints 对象的创建和更新
- Node 的发现、管理和状态监控、死亡容器所占磁盘空间及本地缓存的镜像文件的清理等工作
- Scheduler:集群中的调度器,负责 Pod 在集群节点中的调度分配
- Etcd:高可用的 key/value 存储系统,用于持久化存储集群中的所有资源对象,例如集群中的 Node、Service、Pod、RC、Namespace 等。
- Kubelet:负责本 Node 节点上的 Pod 的创建、修改、监控、删除等全生命周期管理,同时 Kubelet 定时「上报」本 Node 的状态信息到 API Server 里
- Proxy:实现 Service 的代理及软件模式的负载均衡器
- Kubectl 和 Kubectl Proxy:
- 在 Kubernetes 集群内部的客户端可以直接使用 Kubectl 命令管理集群
- Kubectl Proxy 是 API Server 的一个反向代理,在 Kubernetes 集群外部的客户端可以使用 Kubectl Proxy 来访问 API Server
- cAdvisor:是谷歌的开源项目,用于实时监控 Docker 上运行的容器性能指标
1.2 K8s 节点及组件交互流程介绍
Kubernets 集群由两类节点组成 — Master 和 Node:
-
在 Master 上运行 etcd、API Server、Controller Manager 和 Scheduler 四个组件。
注:其中 API Server、Controller Manager 、Scheduler 是 Kubernetes 的总控中心,负责对集群所有资源进行管控和调度。
-
在每个 Node 上运行 Kubelet 、Proxy 和 Docker Daemon 三个组件,负责对本节点上的 Pod 的生命周期进行管理,以及实现服务代理的功能。
下面以 RC 与相关 Service 创建的完整流程为例,来说明 Kubernetes 里各个服务(组件)的作用以及它们之间的交互关系。
- 通过 Kubectl 提交一个创建 RC 的请求(假设 Pod 副本数为 1),该请求通过 API Server 被写入 etcd 中。
- Controller Manager 通过 API Server 的监听资源变化的接口监听到这个 RC 事件,于是根据 RC 里的 Pod 模板定义生成一个 Pod 对象,通过 API Server 写入 etcd 中。
- 上述 Pod 对象写入 etcd 中事件被 Scheduler 发现,它立刻执行一个复杂的调度流程,为这个新的 Pod 选定一个运行的 Node,可称这个过程为绑定(Pod Binding),然后又通过 API Server 将这个一结果写入到 etcd 中。
- 目标 Node 上运行的 Kubelet 进程通过 API Server 检测到这个 Pod 并且按照它的定义,启动该 Pod 并且负责管理其生命周期。
- 通过 Kubectl 提交一个映射到该 Pod 的 Service 的创建请求,Controller Manager 会通过 Label 标签查询到相关联的 Pod 实例,然后生成 Service 的 Endpoints 信息并通过 API Server 写入到 etcd 中。
- 接下来,所有 Node 上运行的 Proxy 进程通过 API Server 查询并监听 Service 对象与其对应的 Endpoints 信息,建立一个软件方式的负载均衡器来实现 Service 访问到后端 Pod 的流量转发功能。
2. API Server 分析
2.1 功能说明
- 提供集群管理的 API 接口
- 成为集群内各个功能模块之间数据交互和通信的中心枢纽
- 拥有完备的集群安全机制
注:Kubernetes 还提供了命令行工具 Kubectl ,用它来将 API Server 的 API 包装成简单的命令集供我们使用。
2.1.1 集群访问
以下是对上图各种访问路径的详细说明(每个数字表示一种访问的路径):
- 集群内部各组件、应用或集群外部应用访问 API Server
- 集群外部系统访问 Service
- 该情况包括:
- 集群内跨节点访问 Pod
- 集群内跨节点访问容器
- 集群内跨节点访问 Service
- 该情况包括:
- 集群内的容器包含 Pod
- 集群内的容器访问其他集群内的容器
- 集群内的容器访问 Service
2.1.2 模块之间的通信
API Server 作为集群的核心,负责集群各个功能模块之间的通信。集群内部的功能模块通过 API Server 将信息存入 etcd,其他模块通过 API Server(用 get 、list 或 watch 方式)读取这些信息,从而实现模块之间的信息交互。
- Node 节点上的 Kubelet 每隔一个时间周期,通过 API Server 报告自身状态,API Server 接受到这些信息后,将节点状态信息保存在 etcd 中。
- Controller Manager 中的 Node Controller 通过 API Server 定期读取这些节点状态信息,并做相应处理。
- Scheduler 监听到某个 Pod 创建的信息后,检索所有符合该 Pod 要求的节点列表,并将 Pod 绑定到节点列表中最符合要求的节点上;如果 Scheduler 监听到某个 Pod 被删除,则调用 API Server 删除该 Pod 资源对象。
- Kubelet 监听 Pod 信息,如果监听到 Pod 对象被删除,则删除本地节点上的相应的 Pod 实例;如果监听到 修改 Pod 信息,则 Kubelet 监听到变化后,会相应地修改本地节点的 Pod 实例等。
3. Controller Manager
Controller Manager 作为集群内部的管理控制中心,负责集群内的 Node、Pod 副本、服务端点(Endpoint)、命名空间(Namespace)、服务账户(ServiceAccount)、资源定额(ResourceQuota)等的管理并执行自动化修复流程,确保集群处于预期的工作状态。
注:在某个 Node 意外宕机时,Controller Manager 会在集群的其他节点上自动补齐 Pod 副本。
一般来说,智能系统和自动系统通常会通过一个操纵系统来不断修正系统的状态。在 Kubernetes 集群中,Controller Manager 是 Controller 的管理者,每个 Controller 就是一个操纵系统,它通过 API Server 监控系统的共享状态,并尝试将系统状态从「现有状态」修正到「期望状态」
3.1 Replication Controller
Replication Controller 的核心作用是确保在任何时候集群中的一个 RC 所关联的 Pod 都保持一定数量的 Pod 副本处于正常运行状态。
Pod 的状态值列表:
状态值 | 描述 |
---|---|
pending | API Server 已经创建该 Pod,但 Pod 内还有一个或多个容器的镜像没有创建 |
running | Pod 内所有容器均已创建,且至少有一个容器处于运行状态或正在启动或重启 |
succeeded | Pod 内所有容器均成功中止,且不会再重启 |
failed | Pod 内所有容器均已退出,且至少有一个容器因为发生错误而退出 |
3.2 Node Controller
Node Controller 负责发现、管理和监控集群中的各个 Node 节点。Kubelet 在启动时通过 API Server 注册节点信息,并定时向 API Server 发送节点信息。API Server 接受到这些信息后,将这些信息写入 etcd。
注:存入 etcd 的节点信息包括节点健康状况、节点资源、节点名称、节点地址信息、操作系统版本、Docker 版本、Kubelet 版本等。
节点健康状况包括「就绪(True)」、「未就绪(False)」和「未知(Unknown)」三种。
3.3 ResourceQuota Controller
ResourceQuota Controller 确保了指定的对象在任何时候都不会超量占用系统资源,避免了由于某些业务进程的设计或实现的缺陷导致整个系统运行紊乱甚至意外宕机,对整个集群的平稳运行和稳定性有非常重要的作用。
思考:目前开发的服务,就是因为混部,在单一服务消耗资源(比如内存)过高时,其他服务无法使用该资源,进而整体服务不可用
目前 Kubernetes 支持如下三个层次的资源配额管理:
- 容器级别,可以对 CPU 和 Memory 进行限制
- Pod 级别,可以对一个 Pod 内所有容器的可用资源进行限制
- Namespace 级别,为 Namespace (可以用于多租户) 级别的资源限制
3.4 Namespace Controller
用户通过 API Server 可以创建新的 Namespace 并保存在 etcd 中,Namespace Controller 定时通过 API Server 读取这些 Namespace 信息。
注:如果 Namespace 被 API 标识为优雅删除(设置删除期限, DeletionTimestamp 属性被设置),则将该 Namespace 的状态设置为「Terminating」并保存到 etcd 中。同时 Namespace Controller 删除该 Namespace 下的 ServiceAccount、Replication Controller 、Pod、Secret、PersistentVolume、ListRange、ResourceQuota 和 Event 等资源对象。
3.5 ServiceAccout Controller 与 Token Controller
ServiceAccount Controller 与 Token Controller 是与安全相关的两个控制器。
ServiceAccount Controller 在 Controller Manager 启动时被创建。它监听 Service Account 的删除事件和 Namespace 的创建、修改事件。
注:如果在该 Service Account 的 Namespace 中没有 default Service Account,那么 Service Account Controller 为该 Service Account 的 Namespace 创建一个 default Service Account。
Token Controller 在 Controller Manager 启动时根据配置选择创建或者不创建。Token Controller 对象监听 Service Account 和 Secret 的创建、修改和删除事件,并根据事件的不同做不同的处理。
3.6 Service Controller 与 Endpoint Controller
Service Controller 监控 Service 的变化,如果发生变化的 Service 类型是 LoadBalancer 类型的,则 Service Controller 确保外部的 LoadBalancer 被相应地创建和删除。
Service 类型定义的 「spec.type」字段,其可选值有三类:
- ClusterIP:默认值,仅使用集群内部虚拟 IP (集群 IP、Cluster IP)
- NodePort:使用虚拟 IP(集群 IP、Cluster IP),同时通过在每个节点上暴露相同的端口来暴露 Service
- LoadBalancer:使用虚拟 IP(集群 IP、Cluster IP )和 NodePort ,同时请求云服务商作为转向 Service 的负载均衡器
注:Kubernetes Service 是一个定义 Pod 集合的抽象,或者被访问者看做一个访问策略,有时也称为微服务。
Endpoints Controller 通过 Store 来缓存 Service 和 Pod 信息,它监控 Service 和 Pod 的变化。
-
通过 API Server 监控 etcd 的「/registry/services」目录(用 Watch 和 List 方式)
-
通过 API Server 监控 etcd 的「/registry/pods」目录(以 Watch 和 List 方式)
4. Kubenetes Scheduler
Kubernetes Scheduler 在整个系统中承担了「承上启下」的重要功能:
- 承上:是指它负责接收 Controller Manager 创建的新 Pod,为其寻找一个合适的 Node 节点。
- 启下:是指目标 Node 上的 Kubelet 服务进程负责接管 Pod 后,负责管理 Pod 的整个生命周期。
细化的作用描述即:
Kubenetes Scheduler 的作用是将待调度的 Pod (API 新创建的 Pod、Controller Manager 为补足副本而创建的 Pod 等)按照特定的调度算法和调度策略绑定(Binding)到集群中的某个合适的 Node 上,并将绑定信息写入 etcd 中。
注:上述的复杂描述,简而言之,就是通过调度算法调度为待调度 Pod 列表中的每个 Pod 从 Node 列表中选择一个合适的 Node。
整个调度过程涉及三个对象,分别是,待调度 Pod 列表,可用 Node 列表,以及调度算法和策略。
Scheduler 流程图解,当前提供的默认调度流程分为以下两个步骤:
- 预先策略调度过程,即遍历所有目标 Node,筛选出符合要求的候选节点。
- 确定最优节点,在上一步的基础上,采取优选策略计算出每个候选节点的积分,积分最高者胜出。
-
预选策略:输入是所有节点,输出是满足预选条件的节点。
-
优选策略:输入是预选阶段筛选出的节点,优选会根据优选策略为通过预选的 Nodes 进行打分排名,选择得分最高的 Node。
注:比如,资源越富裕,负载越小的 Node 可能具有越高的排名。
总结预选和优选策略,预选负责解决候选有哪些的问题,优选负责从合适的 Node 节点中选择最优的一个。
Kubernetes 支持编写自己的调度其,通过 spec.schedulername 参数指定调度器名字,可以为 Pod 选择某个调度器进行调度。
5. Kubelet
在 Kubernetes 集群中,在每个 Node 节点上都会启动一个 Kubelet 服务进程。该进程用于处理 Master 节点下发到本节点的任务,管理 Pod 及 Pod 中的容器。每个 Kubelet 进程会在 API Server 上注册节点自身信息,定期向 Master 节点汇报节点资源的使用情况,并通过 cAdvise 监控容器和节点资源。
5.1 Node 管理
Node 通过设置 Kubelet 的启动参数「–register-node」,来决定是否向 API Server 注册自己。
注:–register-node 为 true 表示向 API Server 注册自己。
5.2 Pod 管理
以非「Static Pod」的管理为例,当 Kubelet 读取监听信息,如果是创建和修改 Pod 任务,则做如下处理:
- 为 Pod 创建一个数据目录
- 从 API Server 读取该 Pod 相关配置
- 为该 Pod 挂载外部卷(Extenal Volume)
- 下载 Pod 用到的 Secret
- 检查已经运行在节点中的 Pod,如果该 Pod 没有容器或 Pause 容器没有启动,则先停止 Pod 里所有容器的进程。如果在 Pod 中有需要删除的容器,则删除这些容器。
- 用 「kubernetes/pause」镜像为每个 Pod 创建一个容器。该 Pause 容器用于接管 Pod 中所有其他容器的网络。每创建一个新的 Pod,Kubelet 都会先创建一个 Pause 容器,然后创建其他容器。
- 为 Pod 中的每个容器做如下处理:
- 为容器计算一个 hash 值,然后用容器的名字去 Docker 查询对应容器的 hash 值。若查到容器,且两者 hash 值不同,则停止 Docker 中容器的进程,并停止与之关联的 Pause 容器进程:若两者相同,则不做任何处理。
- 如果容器被终止,且容器没有指定 restartPolicy,则不做任何处理
- 调用 Docker Client 下载并运行容器
注:所有以非 API Server 方式创建的 Pod 都叫做 Static Pod
5.3 容器监控检查
Pod 通过两类探针来检查容器的健康状态。
- LivenessProbe 探针,用于判断容器是否健康,告诉 Kubelet 一个容器什么时候处于不健康的状态。如果一个 LivenessProbe 探针探测到容器不健康,则 Kubelet 将删除该容器,并根据容器的重启策略做相应的处理。
- ReadinessProbe 探针,用于判断容器是否启动完成,且准备接收请求。如果 ReadinessProbe 探针检测失败,则 Pod 的状态将被修改。Endpoint Controller 将从 Service 的 Endpoint 中删除包含该容器所在 Pod 的 IP 地址的 Endpoint 条目。
6. cAdvisor
cAdvisor 是一个开源的分析容器资源使用率和性能特性的代理工具。它是因为容器而产生的,因此自然支持 Docker 容器。在 Kubernetes 项目中,cAdvisor 被集成到 Kubernetes 代码中。cAdvisor 自动查找所有在其节点上的容器,自动采集 CPU、内存、文件系统和网络使用统计。cAdvisor 通过它所在节点机的 Root 容器,采集并分析该节点机的全面使用情况。
7. 碎碎念
希望每一天都能够活的自由且尽兴:
- 总会有那么几个瞬间,让你忽然觉得,生活温柔且有趣。
- 你可以听很丧的歌,但我希望你看看外面的太阳、星星、月亮、行人、树木、花香、雨滴、动物,看到这个世界也是亮晶晶的。
- 会有沮丧失意的时候,但经常会跟自己讲,如果在这一件事情上运气不好,那一定会在别的什么事情上还回来,所以没什么好难过的,人要学会往前走,走下去,就总能看到更多更好的风景了。