之前写过一篇 k8s(kubernetes)简介 同名的文章,但是刚开始不会使用简书的编辑器,现在重新研究了一下,把之前的文章更新了一下。
k8s(kubernetes)简介
kubernetes能做什么
传统部署时代:
早期,各个组织机构在物理服务器上运行应用程序。无法为物理服务器中的应用程序定义资源边界,这会导致资源分配问题。 例如,如果在物理服务器上运行多个应用程序,则可能会出现一个应用程序占用大部分资源的情况,结果可能导致其他应用程序的性能下降。 一种解决方案是在不同的物理服务器上运行每个应用程序,但是这样会造成资源利用不足,而且不易扩展, 同时物理服务器的运维成本很高。
虚拟化部署时代:
作为解决方案,引入了虚拟化。虚拟化技术允许你在单个物理服务器的 CPU 上运行多个虚拟机(VM)。 虚拟化允许应用程序在 VM 之间隔离,并提供一定程度的安全,因为一个应用程序的信息不能被另一应用程序随意访问。
虚拟化技术能够更好地利用物理服务器上的资源,并且因为可轻松地添加或更新应用程序而可以实现更好的可伸缩性,降低硬件成本。
每个 VM 是一台完整的计算机,在虚拟化硬件之上运行所有组件,包括其自己的操作系统。所以,VM本身会占用大量的硬件资源。
容器部署时代:
容器类似于 VM,但是它们具有被放宽的隔离属性,可以在应用程序之间共享操作系统(OS)。 因此,容器技术更加轻量级。容器与 VM 类似,具有自己的文件系统、CPU、内存、进程空间等。 由于它们与基础架构分离,因此可以跨云和跨系统发行版本进行移植。相比于VM,容器本身所需要的硬件资源小得多。
kubernetes部署时代:
容器是打包和运行应用程序的很好方式。在生产环境中,你只需要管理运行应用程序的容器,并确保不会停机。 例如,如果一个容器发生故障,则需要启动另一个容器。如果把容器的启停交给软件处理,会不会更容易?这就是 kubernetes 解决的问题!
kubernetes 提供以下功能:
-
服务发现和负载均衡
kubernetes 可以使用 DNS 名称或自己的 IP 地址公开容器,如果进入容器的流量很大, kubernetes 可以负载均衡并分配网络流量。
-
存储编排
kubernetes 允许你自动挂载你选择的存储系统,例如本地存储、网络存储。
-
自动部署和回滚
你可以使用 kubernetes 描述已部署容器的所需状态,它可以以受控的速率将实际状态更改为期望状态。例如,你可以自动化 kubernetes 来为你的部署创建新容器, 删除现有容器并将它们的所有资源用于新容器。
-
自动完成资源配置
kubernetes 允许你指定每个容器所需 CPU 和内存(RAM)。 当容器指定了资源请求时,kubernetes 可以做出更好的决策来管理容器的资源。
-
自我修复
kubernetes 能重新启动失败的容器、替换容器、杀死不响应的容器。
-
密钥与配置管理
kubernetes 允许你存储和管理敏感信息,例如密码和 ssh 密钥。 你可以在不重建容器镜像的情况下更新密钥和应用程序配置。
k8s集群架构以及组成
控制平面(Control Plane)
控制平面对集群做出全局决策(比如调度),以及检测和响应集群事件(例如,当容器数量不足时,启动新的容器)。
控制平面可以在集群中的任何节点上运行。 但是,为了简单起见,控制平面通常在单独的计算机上运行,并且不会在此计算机上运行用户容器。
apiserver
apiserver公开了 kubernetes的核心接口。kubernetes的所有组件都要通过apiserver才能与其他组件进行通信。例如:当调度器scheduler将任务发给工作节点时,不直接与节点通信,而是将计划告诉apiserver,再由apiserver将任务发送给工作节点。
apiserver 设计上考虑了水平伸缩,也就是说,它可通过部署多个实例进行伸缩。 你可以运行apiserver 的多个实例,并在这些实例之间平衡流量。
etcd
etcd 是兼具一致性和高可用性的键值数据库,可以作为保存 kubernetes 所有集群数据的后台数据库,etcd保存了kubernetes的所有状态信息。
scheduler
scheduler负责调度新创建的pods,选择节点让 pod在上面运行。
调度决策考虑的因素包括资源需求、硬件/软件/策略约束、亲和性和反亲和性、数据位置、工作负载间的干扰和时限等。
controller-manager
controller-manager包括:
节点控制器(Node Controller): 负责在节点出现故障时进行通知和响应
任务控制器(Job controller): 管理 job对象,然后创建 pods 来运行这些job直至完成
端点控制器(Endpoints Controller): 填充端点(Endpoints)对象(即加入 Service 的 Pod)
服务帐户和令牌控制器(Service Account & Token Controllers): 为新的命名空间创建默认帐户和 API 访问令牌
Node 组件
node组件在每个节点上运行,包括控制平面节点,维护运行的 pod并提供 kubernetes 运行环境。
kubelet
在每个节点上运行,保证容器都运行在pod中。
kubelet 接收 PodSpecs(pod的运行参数),确保这些 PodSpecs 中描述的容器处于运行状态且健康。 kubelet 不会管理不是由 kubernetes 创建的容器。
kube-proxy
kube-proxy是集群中每个节点上运行的网络代理,实现 kubernetes中service概念的一部分。
kube-proxy 维护节点上的网络规则。这些网络规则允许从集群内部或外部的网络会话与pod进行网络通信。
如果操作系统提供了数据包过滤层并可用的话,kube-proxy 会通过它来实现网络规则。否则, kube-proxy 仅转发流量本身。
容器运行环境(Container Runtime)
容器运行环境是负责运行容器的软件,如docker。
kubernetes 支持多个容器运行环境: Docker、 containerd、CRI-O 以及任何实现 kubernetes CRI (容器运行环境接口)的软件。
k8s高可用架构
堆叠(Stacked) etcd 拓扑
堆叠(Stacked) HA(High Availability )集群是一种这样的拓扑,其中 etcd 分布式数据存储集群堆叠在控制平面节点上,作为控制平面的一个组件运行。
每个控制平面节点运行 kube-apiserver
,kube-scheduler
和 kube-controller-manager
实例。
kube-apiserver
使用负载均衡器暴露给工作节点。
每个控制平面节点创建一个本地 etcd 成员(member),这个 etcd 成员只与该节点的 kube-apiserver
通信。这同样适用于本地 kube-controller-manager
和 kube-scheduler
实例。
这种拓扑将控制平面和 etcd 成员耦合在同一节点上。相对使用外部 etcd 集群,设置起来更简单,而且更易于副本管理。
然而,堆叠集群存在耦合失败的风险。如果一个节点发生故障,则 etcd 成员和控制平面实例都将丢失,因此,应该为 HA 集群运行至少三个堆叠的控制平面节点。
这是 kubeadm 中的默认拓扑。当使用 kubeadm init
和 kubeadm join --control-plane
时,在控制平面节点上会自动创建本地 etcd 成员。
外部 etcd 拓扑
具有外部 etcd 的 HA 集群是一种这样的拓扑,其中 etcd 分布式数据存储集群在独立于控制平面节点的其他节点上运行。
就像堆叠的 etcd 拓扑一样,外部 etcd 拓扑中的每个控制平面节点都运行 kube-apiserver
,kube-scheduler
和 kube-controller-manager
实例。同样, kube-apiserver
使用负载均衡器暴露给工作节点。但是,etcd 成员在不同的主机上运行,每个 etcd 主机与每个控制平面节点的 kube-apiserver
通信。
这种拓扑结构解耦了控制平面和 etcd 成员。因此,失去控制平面实例或者 etcd 成员的影响较小,并且不会像堆叠的 HA 拓扑那样影响集群冗余。
但是,此拓扑需要两倍于堆叠 HA 拓扑的主机数量。
具有此拓扑的 HA 集群至少需要三个用于控制平面节点的主机和三个用于 etcd 节点的主机。
etcd集群中的数据一致性
1、etcd是什么
etcd是一个键值存储系统,集群中的每一个成员都保持着全量的数据。
2、数据一致性--etcd集群选举
etcd集群中的角色分为Leader, Follower, Candidate。同一时间只存在一个Leader,Leader处理所有来自客户端写(读可由Follower处理)操作。
当Follower在一定时间内没有收到来自主节点的心跳,会将自己角色改变为Candidate(自封为候选人),并发起一次选主投票;当收到包括自己在内超过半数节点赞成后,选举成功;当收到票数不足半数选举失败。若本轮未选出主节点,将进行下一轮选举。为了避免陷入选主失败循环,每个节点未收到心跳发起选举的时间是一定范围内的随机值,这样能够避免2个节点同时发起选主。Candidate节点收到来自主节点的信息后,会立即终止选举过程,进入Follower角色。
在选主逻辑中,为了保障数据是最新的,对能够成为主的节点加以限制,确保选出的节点以已经包含了集群已经提交的所有日志。如果新选出的主节点已经包含了集群所有提交的日志,那就不需要从和其他节点比对数据了。简化了流程,缩短了集群恢复服务的时间。这里存在一个问题,加以这样限制之后,还能否选出主呢?答案是:只要仍然有超过半数节点存活,这样的主一定能够选出。因为已经提交的日志必然被集群中超过半数节点持久化。
3、数据一致性--节点数量
etcd使用RAFT协议保证各个节点之间的状态一致。根据RAFT算法原理,节点数目越多,会降低集群的写性能。这是因为每一次写操作,需要集群中大多数节点将日志落盘成功后,Leader节点才能将修改内部状态机,并返回将结果返回给客户端。
也就是说在等同配置下,节点数越少,集群性能越好。显然,只部署1个节点是没什么意义的。通常,按照需求将集群节点部署为3,5,7,9个节点。
4、数据一致性--数据读写
为了保证数据的强一致性,etcd 集群中所有的数据流向都是一个方向,从 Leader (主节点)流向Follower,也就是所有 Follower 的数据必须与 Leader 保持一致,如果不一致会被覆盖。
读取: 由于集群所有节点数据是强一致性的,读取可以从集群中随便哪个节点进行读取数据
写入: etcd 集群有 leader,如果写入往 leader 写入,可以直接写入,然后Leader节点会把写入分发给所有 Follower。如果往 follower 写入,请求会路由到Leader,然后Leader节点会把写入分发给所有 Follower。
5、etcd读写性能
按照官网给出的资料,在2CPU,1.8G内存,SSD磁盘这样的配置下,单节点的写性能可以达到16K QPS,,而先写后读也能达到12K QPS。这个性能还是相当可观的。