作者: turboxu
Kubernetes 作为容器编排生态圈中重要一员, 是 Google 大规模容器管理系统 borg 的开源版本实现, 吸收借鉴了 google 过去十年间在生产环境上所学到的经验与教训 Kubernetes 提供应用部署维护 扩展机制等功能, 利用 Kubernetes 能方便地管理跨机器运行容器化的应用当前 Kubernetes 支持 GCEvShpereCoreOSOpenShiftAzure 等平台, 除此之外, 也可以直接运行在物理机上. kubernetes 是一个开放的容器调度管理平台, 不限定任何一种言语, 支持 java/C++/go/python 等各类应用程序
kubernetes 是一个完备的分布式系统支持平台, 支持多层安全防护准入机制多租户应用支撑透明的服务注册服务发现内建负载均衡强大的故障发现和自我修复机制服务滚动升级和在线扩容可扩展的资源自动调度机制多粒度的资源配额管理能力, 完善的管理工具, 包括开发测试部署运维监控, 一站式的完备的分布式系统开发和支撑平台
一. 系统架构
kubernetes 系统按节点功能由 master 和 node 组成
Master
Master 作为控制节点, 调度管理整个系统, 包含以下组件:
API Server 作为 kubernetes 系统的入口, 封装了核心对象的增删改查操作, 以 RESTful 接口方式提供给外部客户和内部组件调用它维护的 REST 对象将持久化到 etcd
Scheduler: 负责集群的资源调度, 为新建的 pod 分配机器这部分工作分出来变成一个组件, 意味着可以很方便地替换成其他的调度器
Controller Manager: 负责执行各种控制器, 目前有两类:
Endpoint Controller: 定期关联 service 和 pod(关联信息由 endpoint 对象维护), 保证 service 到 pod 的映射总是最新的
Replication Controller: 定期关联 replicationController 和 pod, 保证 replicationController 定义的复制数量与实际运行 pod 的数量总是一致的
Node
Node 是运行节点, 运行业务容器, 包含以下组件:
Kubelet: 责管控 docker 容器, 如启动 / 停止监控运行状态等它会定期从 etcd 获取分配到本机的 pod, 并根据 pod 信息启动或停止相应的容器同时, 它也会接收 apiserver 的 HTTP 请求, 汇报 pod 的运行状态
Kube Proxy: 负责为 pod 提供代理它会定期从 etcd 获取所有的 service, 并根据 service 信息创建代理当某个客户 pod 要访问其他 pod 时, 访问请求会经过本机 proxy 做转发
借用一张网图, 表达功能组件之间关系:
二. 基本概念
Node
node 是 kubernetes 集群中相对于 master 而言的工作主机, 在较早版本中也被称为 minionNode 可以是一台物理主机, 也可以是一台虚拟机 (VM) 在每个 node 上运行用于启动和管理 pod 的服务 kubelet, 并能够被 master 管理在 node 上运行的服务进程包括 kubeletkube-proxy 和 docker daemon
Node 的信息如下:
node 地址: 主机的 IP 地址或者 nodeid
node 的运行状态: pending,running,terminated
node condition: 描述 running 状态 node 的运行条件, 目前只有一种条件 Ready, 表示 node 处于健康状态, 可以接收 master 发来的创建 pod 的指令
node 系统容量: 描述 node 可用的系统资源, 包括 CPU 内存最大可调度 pod 数量等
Pod
pod 是 kubernetes 的最基本操作单元, 包括一个或多个紧密相关的容器, 一个 pod 可以被一个容器化的环境看作应用层的逻辑宿主机 ( Logical host ) 一个 pod 中的多个容器应用通常是紧耦合的 Pod 在 node 上被创建启动或者销毁
为什么 kubernetes 使用 pod 在容器之上再封装一层呢? 一个很重要的原因是, docker 容器之间通信受到 docker 网络机制的限制在 docker 的, 世界中, 一个容器需要通过 link 方式才能访问另一个容器提供的服务 (端口) 大量容器之间的 link 将是一个非常繁重的工作通过 pod 的概念将多个容器组合在一个虚拟的主机内, 可以实现容器之间仅需通过 localhost 就能相互通信了
一个 pod 中的应用容器共享一组资源, 如:
pid 命名空间: pod 中的不同应用程序可以看到其他的进程 PID
网络命名空间: pod 中的多个容器能够访问同一个 IP 和端口范围
IPC 命名空间: pod 中的多个容器能够使用 systemV ipc 或 POSIX 消息队列进行通信
UTS 命名空间: pod 中的多个容器共享一个主机名
Volumes(共享存储卷):pod 中的各个容器可以访问在 pod 级别定义的 volumes
Label
label 是 kubernetes 系统中的一个核心概念 Label 以 key/value 键值对的形式附加到各种对象上, 如 podserviceRCNode 等 Label 定义了这些对象的可识别属性, 用来对它们进行管理和选择 Label 可以在创建对象时附加到对象上, 也可以在对象创建后通过 API 进行管理
在为对象定义好 label 后, 其他对象就可以使用 label selector 来定义其他作用的对象了
label selector 的定义由多个逗号分隔的条件组成:
- label: {
- key1: value1,
- key2: value2
- }
- Resource controller(RC)
Resource controller(RC)是 kubernetes 系统中的核心概念, 用于定义 pod 副本的数量在 master 的 Controller manager 进程通过 RC 的定义来完成 pod 的创建监控启停等操作
根据 replication controller 的定义, kubernetes 能够确保在任意时刻都能运行用户指定的 pod 副本 (replica) 数量如果有过多的的 pod 副本在运行, 系统会停掉一些 pod; 如果运行的 pod 副本数量太少, 系统就会再启动一些 pod, 总之, 通过 RC 的定义, kubernetes 总是保证集群中运行着用户期望副本数量
Service(服务)
在 kubernetes 的世界里, 虽然每个 pod 都会被分配一个单独的 IP 地址, 但这个 IP 地址会随着 pod 的销毁而消失这就引出一个问题: 如果有一组 pod 组成一个集群来提供服务, 那么如何来访问它们呢?
kubernetes 的 service 就是用来解决这个问题的核心概念一个 service 可以看作一组提供相同服务的 pod 的对外访问接口 Service 作用于哪些 pod 是通过 label selector 来定义的
pod 的 IP 地址是 docker daemon 根据 docker0 网桥的 IP 地址段进行分配的, 但 service 的 Cluster IP 地址是 kubernetes 系统中的虚拟 IP 地址, 由系统动态分配 Service 的 ClusterIP 地址相对于 pod 的 IP 地址来说相对稳定, service 被创建时即被分配 IP 地址, 在销毁该 service 之前, 这个 IP 地址都不会再变化
由于 service 对象在 Cluster IP Range 池中分配到的 IP 只能在内部访问, 所以其他 pod 都可以无障碍地访问到它但如果这个 service 作为前端服务, 准备为集群外的客户端提供服务, 我们就需要给这个服务提供公共 IP 了
kubernetes 支持两种对外提供服务的 service 的 type 定义: nodeport 和 loadbalancer
Volume(存储卷)
volume 是 pod 中能够被多个容器访问的共享目录 Kubernetes 的 volume 概念与 docker 的 volume 比较类似, 但并不完全相同 Kubernetes 中的 volume 与 pod 生命周期相同, 但与容器的生命周期不相关当容器终止或重启时, volume 中的数据也不会丢失另外, kubernetes 支持多种类型的 volume, 并且一个 pod 可以同时使用任意多个 volume
(1)EmptyDir: 一个 EmptyDir volume 是在 pod 分配到 Node 时创建的从它的名称就可以看出, 它的初始内容为空在同一个 pod 中所有容器可以读和写 EmptyDir 中的相同文件当 pod 从 node 上移除时, EmptyDir 中的数据也会永久删除
(2)hostPath: 在 pod 上挂载宿主机上的文件或目录通常用于:
容器应用程序生成的日志文件需要永久保存, 可以使用宿主机的高速文件系统进行存储;
需要访问宿主机上的 docker 引擎内部数据结构的容器应用, 可以通过定义 hostPath 为宿主机 / var/lib/docker 目录, 使容器内部应用可以直接访问 docker 的文件系统
(3)gcePersistentDick: 使用这种类型的 volume 表示使用谷歌计算引擎 (Google Compute Engine, GCE) 上永久磁盘 (persistent disk,PD) 上的文件与 EmptyDir 不同, PD 上的内容会永久保存, 当 pod 被删除时, PD 只是被卸载 (unmount), 但不会被删除需要注意的是, 你需要先创建一个永久磁盘(PD) 才能使用 gcePersistentDisk
(4)awsElasticBlockStore: 与 GCE 类似, 该类型的 volume 使用 Amazon 提供的 Amazon web Service(AWS)的 EBS Volume, 并可以挂载到 pod 中去需要注意的是, 需要先创建一个 EBS Volume 才能使用 awsElasticBlockStore
(5)nfs: 使用 NFS(网络文件系统)提供的共享目录挂载到 Pod 中在系统中需要一个支行中的 NFS 系统
(6)iscsi: 使用 iSCSI 存储设备上的目录挂载到 pod 中
(7)glusterfs: 使用开源 BlusterFS 网络文件系统的目录挂载到 pod 中
(8)rbd: 使用 Linux 块设备共享存储 (Rados Block Device) 挂载到 pod 中
(9)gitRepo: 通过挂载一个空目录, 并从 GIT 库 clone 一个 git repository 以供 pod 使用
(10)secret: 一个 secret volume 用于为 pod 提供加密的信息, 你可以将定义在 kubernetes 中的 secret 直接挂载为文件让 pod 访问 Secret volume 是通过 tmfs(内存文件系统)实现的, 所以这种类型的 volume 总是不会持久化的
(11)persistentVolumeClaim: 从 PV(persistentVolume)中申请所需的空间, PV 通常是种网络存储, 如 GCEPersistentDiskAWSElasticBlockStoreNFSiSCSI 等
Namespace(命名空间)
namespace(命名空间)是 kubernetes 系统中另一个非常重要的概念, 通过将系统内部的对象分配到不同的 namespace 中, 形成逻辑上分组的不同项目小组或用户组, 便于不同的分组在共享使用整个集群的资源的同时还能分别管理
kubernetes 集群在启动后, 会创建一个名为 default 的 namespace 接下来, 如果不特别指明 namespace, 则用户创建的 podRCService 都将被系统创建到名为 default 的 namespace 中
使用 namespace 来组织 kubernetes 的各种对象, 可以实现对用户的分组, 即多租户管理对不同的租房还可以进行单独的资源配额设备和管理, 使得整个集群配置非常灵活方便
Annotation(注解)
annotation 与 label 类似, 也使用 key/value 键值对的形式进行定义 Label 具有严格的全名规则, 它定义的是 kubernetes 对象的元数据(metadata), 并且用于 label selectorAnnotation 则是用户任意定义的附加信息, 以便于外部工具进行查找
用 annotation 来记录的信息包括:
build 信息 release 信息 docker 镜像信息等, 如时间戳 release id 号 PR 号镜像 hash 值 docker Controller 地址等
典型流程
以创建一个 Pod 为例, kubernetes 典型的流程如下图所示:
三. 组件
Replication Controller
为了区分 Controller Manager 中的 Replication Controller(副本控制器)和资源对象 Replication Controller, 我们将资源对象简写为 RC, 而 Replication Controller 特指副本控制器
Replication Controller 的核心作用是确保在任何时间集群中一个 RC 所关联的 pod 都保持一定数量的 pod 副本处于正常运行状态如果该类 pod 的 pod 副本数量太多, 则 Replication Controller 会销毁一些 pod 副本; 反之 Replication Controller 会添加 pod 副本, 直到该类 pod 的 pod 副本数量达到预设的副本数量最好不要超过 RC 直接创建 pod, 因为 Replication Controller 会通过 RC 管理 pod 副本, 实现自动创建补足替换删除 pod 副本, 这样就能提高系统的容灾能力, 减少由于节点崩溃等意外状况造成的损失即使应用程序只用到一个 pod 副本, 也强烈建设使用 RC 来定义 pod
Replication Controller 管理的对象是 pod, 因此其操作与 pod 的状态及重启策略息息相关
副本控制器的常用使用模式:
(1)重新调度: 不管想运行 1 个副本还是 1000 副本, 副本控制器能够确保指定 pod 数量的副本存在于集群中, 如果节点故障或副本被终止运行等意外情况, 将会重新调度直到达到预期的副本正常运行
(2)弹性伸缩: 手动或通过自动扩容代理修改副本控制器的 spec.replicas 属性值, 非常容易实现扩大或缩小副本的数量
(3)滚动更新: 副本控制器被设计成通过逐个替换 pod 的方式来辅助服务的滚动更新推荐的方式是创建一个新的只有一个副本的 RC, 若新的 RC 副本数量加 1, 则旧的 RC 的副本数量减 1, 直到这个旧的 RC 副本数量为零, 然后删除该旧的 RC
在滚动更新的讨论中, 我们发现一个应用在滚动更新时, 可能存在多个版本的 release 事实上, 在生产环境中一个已经发布的应用程序存在多个 release 版本是很正常的现象通过 RC 的标签选择器, 我们能很方便地实现对一个应用的多版本 release 的跟踪
node controller
Node Controller 负责发现管理和监控集群中的各个 node 节点 Kubelet 在启动时通过 API Server 注册节点信息, 并定时向 API Server 发送节点信息 API Server 接收到这些信息后, 将这些信息写入 etcd 存入 etcd 的节点信息包括节点健康状况节点资源节点名称节点地址信息操作系统版本 docker 版本 kubelet 版本等节点健康状况包含就绪 (true) 未就绪 (false) 和未知 (unknown) 三种
(1)Controller Manager 在启动时如果设置了 cluster-cidr 参数, 那么为每个没有设置 spec.podCIDR 的 node 生成一个 CIDR 地址, 并用该 CIDR 设置节点的 spec.PodCIDR 属性, 这样的目的是防止不同节点的 CIDR 地址发生冲突
(2)逐个读取节点的信息, 多次尝试修改 nodeStatusMap 中的节点状态信息, 将该节点信息和 node controller 的 nodeStatusMap 中保存的节点信息比较如果判断中没有收到 kubelet 发送的节点信息第一次收到节点 kubelet 发送的节点信息, 或在该处理过程中节点状态变成非健康状态, 则在 nodeStatusMap 中保存该节点的状态信息, 并用 node controller 所在节点的系统时间作为探测时间和节点状态变化时间
如果判断出在某一段时间内没有收到节点的状态信息, 则设置节点状态为未知(unknown), 并且通过 api server 保存节点状态
(3)逐个读取节点信息, 如果节点状态变为非就绪状态, 则将节点加入待删除队列, 否则将节点从该队列中删除如果节点状态为非就绪状态, 且系统指定了 Cloud Provider, 则 node controller 调用 Cloud Provider 查看节点, 若发现并节点故障, 则删除 etcd 中的节点信息, 并删除和该节点相关的 pod 等资源的信息
ResourceQuota controller
作为容器集群的管理平台, kubernetes 也提供了资源配额管理这一高级功能, 资源配额管理确保指定的对象在任何时候都不会超量占用系统资源, 避免了由于某些业务进程的设计或实现的缺陷导致整个系统运行紊乱甚至意外宕机, 对整个集群的平稳运行和稳定性有非常重要的作用
目前 kubernetes 支持三个层次的资源配额管理:
(1)容器级别, 可以对 CPU 和内存的资源配额管理
(2)pod 级别, 可以对 pod 内所有容器的可用资源进行限制
(3)namespace 级别, 为 namespace(可以用于多租户)级别的资源限制, 包括: pod 数量 replication Controller 数量 service 数量 ResourceQuota 数量 secret 数量可持有的 PV(persistent volume)数量
kubernetes 的配额管理是通过准入机制 (admission control) 来实现的, 与配额相关的两种准入控制器是 LimitRanger 和 ResoureQuota, 其中 LimitRanger 作用于 pod 和 container 上, ResourceQuota 则作用于 namespace 上此外, 如果定义了资源配额, 则 scheduler 在 pod 调度过程中也会考虑这一因素, 确保 pod 调度不会超出配额限制
典型的资源控制流程如下图所示:
namaspace controller
用户通过 API Server 可以创建新的 namespace 并保存在 etcd 中, namespace controller 定时通过 api server 读取这些 namespace 信息如果 namespace 被 API 标识为优雅删除(设置删除期限, deletionTimestamp 属性被设置), 则将该 namespace 的状态设置为 terminating 并保存到 etcd 中同时 namespace controller 删除该 namespace 下的 serviceAccountRCPodSecretPersistentVolumeListRangeSesourceQuota 和 event 等资源对象
当 namespace 的状态被设置为 terminating 后, 由 Adminssion Controller 的 NamespaceLifecycle 插件来阻止为该 namespace 创建新的资源同时, 在 namespace controller 删除完该 namespace 中的所有资源对象后, Namespace Controller 对该 namespace 执行 finalize 操作, 删除 namespace 的 spec.finalizers 域中的信息
如果 Namespace Controller 观察到 namespace 设置了删除期限(即 DeletionTimestamp 属性被设置), 同时 namespacer 的 spec.finalizers 域值是空的, 那么 namespace controller 将通过 API Server 删除该 namespace 资源
kubernetes 安全控制
ServiceAccount Controller 和 token Controller 是与安全相关的两个控制器 ServiceAccount Controller 在 Controller Manager 启动时被创建它监听 Service Account 的删除事件和 Namespace 的创建修改事件如果在该 Service Account 的 namespace 中没有 default Service Account, 那么 ServiceAccount Controller 为该 Service Account 的 namespace 创建一个 default ServiceAccount
在 API Server 的启动中添加 admission_control=ServiceAccount 后, API Server 在启动时会自己创建一个 key 和 crt(/var/run/kubernetes/apiserver.crt 和 apiserver.key), 然后在启动./kube-controller-manager 时添加参数 service_account_privatge_key_file=/var/run/kubernetes/apiserver.key, 这样启动 kubernetes master 后, 就会发现在创建 Service Account 时系统会自动为其创建一个 secret
如果 Controller Manager 在启动时指定参数为 service-account-private-key-file, 而且该参数所指定的文件包含一个 PEM-encoded 的编码的 RSA 算法的私钥, 那么, Controler Manager 会创建 token controller 对象
Token controller
token controller 对象监听 Service Account 的创建修改和删除事件, 并根据事件的不同做不同的处理如果监听到的事件是创建和修改 Service Account 事件, 则读取该 Service Account 的信息; 如果该 Service Account 没有 Service Account Secret(即用于访问 Api server 的 secret), 则用前面提及的私钥为该 Service Account 创建一个 JWT Token, 将该 Token 和 ROOT CA(如果启动时参数指定了该 ROOT CA)放入新建的 secret 中, 将该新建的 secret 放入该 Service Account 中, 同时修改 etcd 中 Service Account 的内容如果监听到的事件是删除 Service Account 事件, 则删除与该 Service Account 相关的 secret
token controller 对象同时监听 secret 的创建修改和删除事件, 并根据事件的不同做不同的处理如果监听到的事件是创建和修改 secret 事件, 那么读取该 secret 中 annotation 所指定的 Service Account 信息, 并根据需要为该 secret 创建一个和其 Service Account 相关的 token; 如果监听到的事件是删除 secret 事件, 则删除 secret 和相关的 Service Account 的引用关系
service controller&endpoint controller
Kubernetes service 是一个定义 pod 集合的抽象, 或者被访问都看作一个访问策略, 有时也被称为微服务
kubernetes 中的 service 是种资源对象, 各所有其他资源对象一样, 可以通过 API Server 的 POST 接口创建一个新的实例在下面的例子代码中创建了一个名为 MyServer 的 Service, 它包含一个标签选择器, 通过该标签选择器选择所有包含标签为 app=MyApp 的 pod 作为该 service 的 pod 集合 Pod 集合中的每个 pod 的 80 端口被映射到节点本地的 9376 端口, 同时 kubernetes 指派一个集群 IP(即虚拟 IP)给该 service
- {
- kind: service,
- apiVersion: v1,
- metadata: {
- name: MyService
- },
- spec: {
- selector: {
- app: MyApp
- },
- ports: [
- {
- protocol: TCP,
- port: 80,
- targetPort: 9376
- }
- ]
- },
}
四. 功能特性
Service 集群访问流程(服务发现)
在 kubernetes 集群中的每个 node 上都运行着一个叫 kube-proxy 的进程, 该进程会观察 master 节点添加和删除 service 和 endpoint 的行为, 如图中第 1 步所示
kube-proxy 为每个 service 在本地主机上开一个端口 (随机选择) 任何访问该端口的连接都被代理到相应的一个后端 pod 上 Kube-proxy 根据 round robin 算法及 service 的 session 粘连 (SessionAffinity) 决定哪个后台 pod 被选中, 如第 2 步所示
最后, 如第 3 步所示, kube-proxy 在本机的 iptables 中安装相应的规则, 这些规则使得 iptables 将捕获的流量重定向到前面提及的随机端口通过该端口流量再被 kube-proxy 转到相应的后端 pod 上
在创建了服务后, 服务 endpoint 模型会创建后端 pod 的 IP 和端口列表(包含中 endpoint 对象中),kube-proxy 就是从这个 endpoint 列表中选择服务后端的集群内的节点通过虚拟 IP 和端口能够访问 service 后台的 pod
在默认情况下, kubernetes 会为 server 指定一个集群 IP(或虚拟 IPcluster IP), 但在某些情况下, 希望能够自己指定该集群 IP 为了给 service 指定集群 IP, 用户只需要在定义 service 时, 在 service 的 spec.clusterIP 域中设置所需要的 IP 地址即可
Scheduler(调度)
scheduler 在整个 kubernetes 系统中承担了承上启下的重要功能, 承上是指它负责接收 Controller Manager 创建的新 pod, 为其安排一个落脚的家目标 node; 启下是指安置工作完成后, 目标 node 上的 kubelet 服务进程接管后继工作, 负责 pod 生命周期中的下半生
具体来说, scheduler 的作用是将待调度的 pod(API 新创建的 PodController Manager 为补足副本而创建的 pod 等)按照特定的调度算法和调度策略绑定 (binding) 到集群中的某个合适的 node 上, 并将绑定信息写入 etcd 中在整个调度过程中涉及三个对象, 分别是: 待调度的 pod 列表可用 node 列表以及调度算法和策略简单地说, 就是通过调度算法调度, 为待调度 pod 列表中的每个 pod 从 node 列表中选择一个最适合的 node
随后, 目标 node 上的 kublet 通过 API Server 监听到 scheduler 产生的 pod 绑定事件, 然后获对应的取 pod, 下载 image 镜像, 并启动容器
Scheduler(调度策略)
scheduler 当前提供的默认调度流程分为两步:
(1)预选调度过程, 即遍历所有目标 node, 筛选出符合要求的候选节点为此 kubernetes 内置了多种预先策略 (xxx predicates) 供用户选择
(2)确定最优节点, 在第一步的基础上, 采用优先策略 (xxx priority) 计算出每个候选节点的积分, 积分最高都胜出
scheduler 的调度流程是通过插件方式加载的调度算法提供者 (AlgorithmProvider) 具体实现的一个 AlgorithmProvider 其实就是包括了一组预选策略与一组优选策略的结构体, 注册 AlgorithmProvider 的函数如下:
func RegisterAlgorithmProvider(name string, predicateKeys, priorityKeys util.StringSet)
它包含 3 个参数, name string 参数为算法名;
predicateKeys 参数为算法集合用到的预选策略集合
priorityKeys 参数为算法用到的优选策略集合
scheduler 中可用的预选策略包含 7 个, 每个节点只有通过 PodFitsPortsPodFitsResourcesNoDiskConflictPodSelectorMatchesPodFitsHost 5 个默认预先策略后, 才能初步被选中, 进入下一个流程
每个节点通过优选策略时都会算出一个得分, 计算各项得分, 最终选出得分值最大的节点作为优选的结果(也是调度算法的结果)LeastRequestedPriority, 选择资源消耗最小节点:
(1)计算出所有备选节点上运行的 pod 和备选 pod 的 CPU 占用量 totalMilliCPU
(2)计算出所有备选节点上运行的 pod 和备选 pod 的内存占用量 totalMomory
(3)计算每个节点的得分, 计算规则大致如下:
score=int(((nodeCpuCapacity-totalMilliCPU)10)/nodeCpuCapacity+((nodeMemoryCapacity-totalMemory)10/nodeMemoryCapacity)/2)
CalculateNodeLabelPriority, 根据 CheckNodeLabelPresence 策略打分
BalancedResourceAllocation, 选择资源使用最均衡节点
(1)计算出所有备选节点上运行的 pod 和备选 pod 的 CPU 占用量 totalMilliCPU
(2)计算出所有备选节点上运行的 pod 和备选 pod 的内存占用量 totalMomory
(3)计算每个节点的得分, 计算规则大致如下:
score=int(10-math.abs(totalMilliCPU/nodeCpuCapacity-totalMemory/nodeMemoryCapacity) * 10)
节点管理
节点管理包含节点的注册状态上报 Pod 管理容器健康检查资源监控等部分
节点注册
在 kubernetes 集群中, 在每个 node 节点上都会启动一个 kubelet 服务进程该进程用于处理 master 节点下发到本节点的任务, 管理 pod 及 pod 中的容器每个 kubelet 进程会在 API Server 上注册节点自身信息, 定期向 master 节点汇报节点资源使用情况, 并通过 cAdvisor 监控容器和节点资源
节点通过设置 kubelet 的启动参数 register-node, 来决定是否向 API Server 注册自己如果该参数为 true, 那么 kubelet 将试着通过 API Server 注册自己作为自注册, kubelet 启动还包含下列参数:
--api-servers, 告诉 kubelet API Server 的位置;
--kubeconfig, 告诉 kubelet 在哪儿可以找到用于访问 API Server 的证书;
--cloud-provider, 告诉 kubelet 如何从云服务商 (IAAS) 那里读取到和自己相关的元数据
状态上报
kubelet 在启动时通过 API Server 注册节点, 并定时向 API Server 发送节点新消息, API Server 在接收到这些信息后, 将这些信息写入 etcd 通过 kubelet 的启动参数 node-status-update-frequency 设置 kubelet 每隔多少时间向 API Server 报告节点状态, 默认为 10 秒
Pod 管理
kubelet 通过以下几种方式获取自身 node 上所要运行的 pod 清单:
(1)文件: kubelet 启动参数 --config 指定的配置文件目录下的文件通过 file-check-frequency 设置检查该文件目录的时间间隔, 默认为 20 秒
(2)HTTP 端点(URL): 通过 manifest-url 参数设置通过 http-check-frequency 设置检查该 HTTP 端点的数据时间间隔, 默认为 20 秒
(3)API Server:kubelet 通过 API Server 监听 etcd 目录, 同步 pod 清单
所有以非 API Server 方式创建的 pod 都叫作 static podKubelet 将 static pod 的状态汇报给 API Server,API Server 为 static pod 创建一个 mirror pod 和其相匹配 Mirror pod 的状态将真实反映 static pod 的状态当 static pod 被删除时, 与之相对应的 mirror pod 也会被删除 Kubelet 通过 API Server client 使用 watch+list 的方式监听 / registry/node/<当前 node 名称>和 / registry/pods 目录, 将获取的信息同步到本地缓存中
kubelet 监听 etcd, 所有针对 pod 的操作将会被 kubelet 监听到如果发现有新的绑定到本节点的 pod, 则按照 pod 清单的要求创建该 pod 如果发现本地的 pod 被修改, 则 kubelet 会做出相应的修改, 如删除 pod 中的某个容器时, 则通过 docker client 删除该容器如果发现删除本节点的 pod, 则删除相应的 pod, 并通过 docker client 删除 pod 中的容器
kubelet 读取监听到的信息, 如果是创建和修改 pod 任务, 则做如下处理:
(1)为该 pod 创建一个数据目录
(2)从 API Server 读取该 pod 清单
(3)为该 pod 挂载外部卷(Extenal Volume)
(4)下载 pod 用到的 secret
(5)检查已经运行在节点中的 pod, 如果该 pod 没有容器或 pause 容器没有启动, 则先停止 pod 里所有容器进程如果在 pod 中有需要删除的容器, 则删除这些容器
(6)用 kubernetes/pause 镜像为每个 pod 创建一个容器, 该 pause 容器用于接管 pod 中所有其他容器的网络
(7)为 pod 中的每个容器做如下处理:
为容器计算一个 hash 值, 然后用容器的名字去 docker 查询对应容器的 hash 值若查到容器, 且两者 hash 值不同, 则停止 docker 中容器进程, 并停止与之关联的 pause 容器进程; 若两者相同不做任何处理
如果容器被中止了, 且容器没有指定的 restartPolicy(重启策略), 则不做任何处理
调用 docker client 下载容器镜像, 调用 docker client 运行容器
容器健康检查
pod 通过两类探针来检查容器的健康状态一个是 LivenessProbe 探针, 用于判断容器是否健康, 告诉 kubelet 一个容器什么时候处于不健康的状态如果 LivenessProbe 探针探测到容器不健康, 则 kubelet 将删除容器, 并根据容器的重启策略做相应的处理如果一个容器不包含 LivenessProbe 探针, 那么 kubelet 认为该容器的 LivenessProbe 探针返回的值永远是 success. 另一类是 ReadinessProbe 探针, 用于判断容器是否启动完成, 且准备接收请求如果 ReadinessProbe 探针检测到失败, 则 pod 的状态将被修改 Endpoint controller 将从 service 的 endpoint 中删除包含该容器所在 pod 的 IP 地址的 endpoint 条目
参考
kubernetes 权威指南
文章来源 公众号小时光茶社(Tech Teahouse)
来源: https://cloud.tencent.com/developer/article/1004400