Kubernetes 核心架构



与传统的高性能计算及虚拟化云平台类似,Kubernetes 也遵循主从结构。通常将固定规模的计算节点组成一个集群,在集群中挑选数台计算节点作为管理节点(Master),其余的计算节点作为工作节点(Minion)。针对较大规模的集群,建议将独占节点作为管理节点,而针对较小规模的集群,可以将管理节点和工作节点混用。


如图 所示,管理节点和非管理节点的区别是, 管理节点上运行的是控制平面组件 ,而工作节点运行的是用户业务。 Kubernetes 还拥有各种功能插件,例如监控模块、日志模块、DNS 服务、 Ingress 等,这些组件通常以用户态应用的形式存在。


Kubernetes 架构基础 核心控制平面组件_数据库

核心控制平面组件



控制平面组件是由集群管理员部署和维护的,用来支撑平台运行的组件,Kubernetes的主要控制平面组件包括API Server、etcd、Scheduler 和Controller Manager。通常将控制平面组件安装在多个主节点上,彼此协同工作,保证平台的高可用性。

是否需要进行高可用配置,以及创建多少个高可用副本,是依据具体生产化需求而定的,具体细节会在第构建高可用集群中详述,本章将介绍单节点上控制平面组件的细节。


etcd



etcd 是高可用的键值对的分布式安全存储系统,用于持久化存储集群中所有的资源对象,例如集群中的Node、Service、Pod 的状态和元数据,以及配置数据等。为了持久性和高可用性,生产环境中的etcd 集群成员需分别在多个节点上运行,并定期对其进行备份。


如图 所示,在多个 etcd 成员组成的 etcd 集群中, etcd 成员间 使用Raft 共识算法复制请求并达成协议。


 

Kubernetes 架构基础 核心控制平面组件_负载均衡_02


 对于 etcd ,这里有几个概念:领导者、选举和任期。 任何etcd 集群成员都可以处理读 请求,不需要共识。但只有领导者才能处理写请求,包括更改、新增、删除等。 如图所示,当来自客户端API Server 的写请求被提交到 etcd 成员处时,如果它不是领导者, 那么它会将此请求转移给领导者。领导者会将请求复制到集群的其他成员中进行仲裁,当超过半数成员同意更改时,领导者才将更改后的新值提交到日志wal 中,并通知集群成员进行相应的写操作,将日志中的新值写入磁盘中。



每个集群在任何给定时间都只能有一个领导者。如果领导者不再响应,那么其余成员在预定的选举计时器超时后会开始新的选举, 将自己标记为候选者并请求其他节点投票来开始新的选举 。每个节点为请求其投票的第一个候选者投票。



如果候选人从集群中的大多数节点获得投票,那么它将成为新的领导者。每个节点维护的选举计时器的超时时间不同,因此第一个候选人通常会成为新的领导者。但是,如果存在多个候选人并获得相同数目的选票,则现有的选举任期将在没有领导人的情况下结束,而新任期将以新的随机选举计时器开始。因此,我们建议在部署etcd 集群时采用奇数个成员为佳。



根据Raft 的工作机制, 每个写请求需要集群中的每个成员做仲裁因此我们建议etcd 集群成员数量不要超过7 个,推荐是5 个,个数越多仲裁时间会越多,写的吞吐量会越低。如果集群中的某个成员处理请求特别慢,就会让整个etcd 集群不稳定,且性能受到限制。因此,我们要实时监测每个etcd 成员的性能,及时修复或者移除性能差的成员。


API Server



API Server,也就是常说的kube-API Server。它承担API 的网关职责,是用户请求其他系统组件与集群交互的唯一入口。所有资源的创建、更新和删除都需要通过调用API Server 的API 接口来完成

  1. 对内,API Server 是各个模块之间数据交互的通信枢纽,提供了etcd 的封装接口API,这些API 能够让其他组件监听到集群中资源对象的增、删、改的变化。
  2. 对外,它充当着网关的作用,拥有完整的集群安全机制,完成客户端的身份验证(Authentication)和授权(Authorization),并对资源进行准入控制(Admission Control)。


kubernetes API Server的功能:

  1. 提供了集群管理的REST API接口(包括认证授权、数据校验以及集群状态变更);
  2. 提供其他模块之间的数据交互和通信的枢纽(其他模块通过API Server查询或修改数据,只有API Server才直接操作etcd);
  3. 是资源配额控制的入口;
  4. 拥有完备的集群安全机制.

kube-apiserver工作原理图

Kubernetes 架构基础 核心控制平面组件_数据库_03

用户可以通过kubectl 命令行或RESTful 来调用HTTP 客户端(例如curl、wget 和浏览器)并与API Server 通信。通常,API Server 的HTTPS 安全端口默认为6443(可以通过--secure-port 参数指定)HTTP 非安全端口(可以通过--insecure-port 参数指定,默认值为8080)在新版本中已经被弃用。Kubernetes 集群可以是包含几个节点的小集群,也可以扩展到成千节点的规模。作为集群的 “大脑”,API Server 的高可用性是至关重要的。




如图 1-11 所示,一个集群允许有多个 API Server 的实例。 API Server 本身是无状态的,可以横向扩展。借助Haproxy 或负载均衡器就能非常容易地让他们协同工作。kubesphere配置:


  controlPlaneEndpoint:
domain: lb.kubesphere.local
address: ""
port: 6443

在图1-11中,我们通过10.2.1.4:443 或者API Server.cluster.example.io:443,就能访问到集群中的某个 API Server。具体是哪个实例,根据负载均衡器的转发策略(例如 round-robin、least-connection 等)来定。不管是用Haproxy 还是负载均衡器(软件或硬件)的方式,都需要支持Health Check,以防某API Server 所在的Master 节点宕机,其上的流量能够迅速转移到其API Server 上。

    livenessProbe:
failureThreshold: 8
httpGet:
host: 192.168.100.8
path: /livez
port: 6443
scheme: HTTPS
initialDelaySeconds: 10
periodSeconds: 10
timeoutSeconds: 15
name: kube-apiserver
readinessProbe:
failureThreshold: 3
httpGet:
host: 192.168.100.8
path: /readyz
port: 6443
scheme: HTTPS
periodSeconds: 1
timeoutSeconds: 15



Kubernetes 架构基础 核心控制平面组件_数据库_04


1-11 API Server 的高可用架构


另外, API Server 会在 Default Namespace 下创建一个类名为 Kubernetes 的 Service 对象,同时负责将它自己的podIP 更新到对应的 Endpoint 对象中。依托 CoreDNS 插件的辅助,集群内部的Pod 就可以通过服务名访问 API Server 。



[root@ks-master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.233.0.1 <none> 443/TCP 42d

[root@ks-master ~]# kubectl get ep
NAME ENDPOINTS AGE
kubernetes 192.168.100.8:6443 42d

[root@ks-master ~]# kubectl describe svc kubernetes
Name: kubernetes
Namespace: default
Labels: component=apiserver
provider=kubernetes
Annotations: <none>
Selector: <none>
Type: ClusterIP
IP Families: <none>
IP: 10.233.0.1
IPs: 10.233.0.1
Port: https 443/TCP
TargetPort: 6443/TCP
Endpoints: 192.168.100.8:6443
Session Affinity: None
Events: <none>

Pod 到API Server 的流量只会在集群内部转发,而不会被转发到外部的负载均衡器上。值得注意的是,此Endpoint 对象的Subnets Addresses 数组长度有限制,由API Server 的参数--API Server-count 来指定,默认是1。 也就是说,只需添加保留一个API Server 实例的IP 地址。如果集群中有多个API Server实例,需将此值设置为实际值,否则集群内部通过此Service 访问API Server 的所有流量只会转到一个API Server 实例上。


Controller Manager



控制器是Kubernetes 集群的自动化管理控制中心,里面包含30 多个控制器,有Pod管理的(Replication 控制器、Deployment 控制器等)、有网络管理的(Endpoints 控制器、Service 控制器等)、有存储相关的(Attachdetach 控制器等),等等。在1.2.5 节的例子中,我们已经见识到部分控制器是如何工作的。大多数控制器的工作模式雷同,都是通过API Server 监听其相应的资源对象,根据对象的状态来决定接下来的动作,使其达到预期的状态。


 假设Controller Manager 出现问题导致Endpoint 对象无法及时更新,并且kube-proxy 设置的转发规则也无法及时更新,那么将造成业务数据流向异常,进而影响业务的可用性。


很多场景都需要多个控制器协同工作,比如某个节点宕机, kubelet 将会停止汇报状态到Node 对象。NodeLifecycle 控制器会发现节点状态没有按时更新 ,超过一段时间(可通过参数--pod-eviction-timeout 来指定)后,它将驱逐节点上的 Pod 。如果这个 Pod 属于某个Deployment 对象,那么Deployment 对象所需的副本数量将减少,这时Deployment 控制器将会补齐Pod 副本数量,替换掉因为宕机而被删除的Pod。



控制器采用主备模式和 Leader Election 机制来实现故障转移( Fail Over ),如图 1-12所示,也就是说允许多个副本处于运行状态,但是只有一个副本作为领导者在工作,其他副本作为竞争者则不断尝试获取锁,试图通过竞争成为领导者。一旦领导者无法继续工作,其他竞争者就能立刻竞争上岗,而无须等待较长的创建时间。



在Kubernetes 中, 锁就是一个资源对象,目前支持的资源是 Endpoint 和 Configmap 。控制器的锁在 kube-system Namespace 下名为 kube-controller-manager 的 Endpoint 对象中。


Kubernetes 架构基础 核心控制平面组件_数据库_05

图1-12 Leader Election 的工作机制


Leader Election 有三个与时间相关的参数: leaseDuration 、 renewDeadline 和 retryPeriod




第一个参数 leaseDuration 是指资源锁定后的租约时间,竞争者在该时间间隔内不能锁定


资源,如果领导者在这段时间间隔后没有更新锁时间,则竞争者可以认为领导者已经挂掉


,不能正常工作了,将重新选举领导者。



第二个参数 renewDeadline 是指,领导者主动放弃锁,当它在 renewDeadline 内没有成


功地更新锁,它将释放锁。当然如果更新锁无法成功地执行,那么释放锁大概率也无法成


功地执行,所以在 Kubernetes 中这种情况很少见。


第三个参数 retryPeriod 是指竞争者获取锁和领导者更新锁的时间间隔。这种 Leader El


ection 机制保证了集群组件的高可用性,如果领导者因为某种原因无法继续提供服务,则


由其他竞争者副本竞争成为新的领导者,继续执行业务逻辑。


[root@master ~]# kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
kube-apiserver-master 1/1 Running 2 3d2h
kube-controller-manager-master 1/1 Running 2 3d2h
kube-scheduler-master 1/1 Running 2 3d2h



[root@master ~]# kubectl get ep -n kube-system
NAME ENDPOINTS AGE
coredns 3d1h
etcd 192.168.100.8:2379 3d1h
kube-controller-manager-svc 192.168.100.8:10257 3d1h
kube-scheduler-svc 192.168.100.8:10259 3d1h
kubelet 192.168.100.8:10250,192.168.100.10:10250,192.168.100.8:10255 + 3 more... 3d1h
metrics-server 3d1h
openebs.io-local <none> 3d1h

 

 

Scheduler



集群中的调度器负责Pod 在集群节点中的调度分配。我们常说Kubernetes 是一个强大的编排工具,能够提高每台机器的资源利用率,将压力分摊到各个机器上,这主要归功于调度器。调度器是拓扑和负载感知的,通过调整单个和集体的资源需求、服务质量需求、硬件和软件的策略约束、亲和力和反亲和力规范、数据位置、工作负载间的干扰、期限等,来提升集群的可用性、性能和容量。


与控制器类似,调度器也是采用 Leader Election 的主备模式,通过 kube-system Name space 下名为 kube-scheduler 的 Endpoint 对象进行领导者仲裁。



调度器监听 API Server 处 Pod 的变化,当新的 Pod 被创建后,如果其 Pod 的 spec.nodeName 为空,就会根据这个 Pod 的 Resouces、 Affinity 和 Anti-Affinity 等约束条件和 Node 的实时状态等为该 Pod 选择最优节点,然后更新节点名字到Pod 的 spec.NodeName 字段。接下来后续的工作就由节点上的kubelet 接管了。