02-Kubernetes 简介

Kubernetes

Kubernetes 源于希腊语,意为“舵手”。kubernetes(简称K8s),k8s 缩写是因为 k 和 s 之间有八个字符的原因。它是 Google 在 2015 开源的容器调度编排的平台。它是建立在 Google 大规模运行生产工作负载(Borg系统)十几年经验的基础上,结合了社区中最优秀的想法和实践,已经成为了目前容器编排的事实标准。

其实看到 Docker 和 Kubernetes 的 Logo,就可以明白 Kubernetes 的作用。Docker 的 Logo 是一条鲸鱼船,运载着许多封装好的集装箱(container),代表着一次打包到处运行的意图。而 Kubernetes 的 Logo 就是这条船的方向舵

Kubernetes 用于管理云平台中多个主机上的容器化的应用,Kubernetes 的目标是让部署容器化的应用简单并且高效,K8s 提供了应用部署、规划、更新、维护的一种机制。

传统的应用部署方式是通过插件或脚本来安装应用。这样做的缺点是应用的运行、配置、管理、所有生存周期将与当前操作系统绑定,这样做并不利于应用的升级更新/回滚等操作,当然也可以通过创建虚拟机的方式来实现某些功能,但是虚拟机非常重,并不利于可移植性。

新的方式是通过部署容器方式实现,每个容器之间互相隔离,每个容器有自己的文件系统,容器之间进程不会相互影响,能区分计算资源。相对于虚拟机,容器能快速部署,由于容器与底层设施、机器文件系统解耦的。

Kubernetes 前身

Kubernetes 的基础特性是 Google 公司在容器化基础设施领域多年来实践经验的沉淀与升华。这个实践与升华的过程,就是 Kubernetes 的前身Borg系统

Borg 系统一直以来都被誉为 Google 内部最强大的“秘密武器”,是 Google 整个基础设施的核心依赖。很多应用框架已经运行在 Borg 上多年,其中包括了内部的 MapReduce、GFS、BigTable、Megastore 等,上层应用程序更是有这些耳熟能详的产品:Gmail、Google Docs、Google Search等。

其架构图如下所示:

架构分析:

  1. 集群分为 Master 节点与 Worker 节点
  2. Master 节点由多台机器构成,一主多备
  3. BorgMaster 由主进程和 scheduler 进程组成,主进程处理 clientRpc 请求,scheduler 负责调度 tasks。
  4. Borglet 是 Worker 节点上的代理进程,用于启停 tasks

根据 2015 年 4 月 google 发布的 Large-scale cluster management at Google with Borg 与其 2020 年 7 月发布的 Borg: the next generation,两篇论文中的数据表明:Borg 系统通过对在线任务与离线任务进行混合部署,可以节约20%-30%的资源,极大提高了资源利用率。

下表是 2011 年与 2019 年的 Borg 集群,与 2015 年 AWS、Facebool、Twitter 数据中心资源利用率的对比图。

项目 cpu利用率 内存利用率
2011年Borg 30%-40% 40%
2019年Borg 53%-60% 60%
2015年AWS、Facebook、Twitter数据中心 30% 30%

对于成熟高效的 Borg 系统,继承者 Kubernetes 从中获得了宝贵的经验:

  1. Pods。Pod 是 Kubernetes 中调度的单位。 它是一个或多个容器在其中运行的资源封装。保证属于同一 Pod 的容器可以一起调度到同一台计算机上,并且可以通过本地卷共享状态。Borg 有一个类似的抽象,称为 alloc(“资源分配”的缩写)。
  2. Service。Kubernetes 使用服务抽象支持命名和负载均衡:带名字的服务,会映射到由标签选择器定义的一组动态 Pod 集。集群中的任何容器都可以使用服务名访问服务。
  3. Labels。通过使用标签组织 Pod,Kubernetes 比 Borg 支持更灵活的集合,标签是用户附加到 Pod(实际上是系统中的任何对象)的任意键值对。
  4. Ip-per-Pod。Borg容器只能共享主机网络,必须将端口作为调度的资源。在 Kubernetes 中 IP 是以 Pod 为单位分配的,一个Pod内部的所有容器共享一个网络堆栈。

K8S功能

  • 自动装箱。

    • 基于容器对应用运行环境的资源配置要求自动部署应用容器。Kubernetes 允许你指定每个容器所需 CPU 和内存(RAM)。当容器指定了资源请求时,Kubernetes 可以做出更好的决策来管理容器的资源。
  • 自我修复(自愈能力)

    • 当容器失败时,会对容器进行重启。
    • 当所部署的 Node节点有问题时,会对容器进行重新部署和重新调度。
    • 当容器未通过监控检查时,会关闭此容器直到容器正常运行时,才会对外提供服务。
    • 如果某个服务器上的应用不响应了,Kubernetes 会自动在其它的地方创建一个。
  • 弹性伸缩(水平扩展)

    • 通过简单的命令、用户 UI 界面或基于 CPU 等资源使用情况,对应用容器进行规模扩大或规模剪裁(容器的副本数),以保证应用业务高峰并发时的高可用性,且能在业务低峰时期回收资源,减少成本运行服务。
  • 服务发现和负载均衡

    • 无需修改你的应用程序即可使用陌生的服务发现机制。K8s 为容器提供了内部IP地址和一个DNS名称,并且可以在它们之间实现负载均衡,使得用户无需考虑容器IP的问题。
    • 对外提供统一的入口,让它来做节点的调度和负载均衡, 相当于微服务里面的网关?
      image-20200928101711968
  • 滚动更新和回滚

    • 可以使用 Kubernetes 描述已部署容器的所需状态,它可以以受控的速率将实际状态更改为期望状态。例如,你可以自动化 Kubernetes 来为你的部署创建新容器,删除现有容器并将它们的所有资源用于新容器。
    • 可以根据应用部署情况,对应用容器运行的应用,进行历史版本即时回退。类似于Git中的回滚。
  • 密钥和配置管理

    • Kubernetes 允许你存储和管理敏感信息,例如密码、OAuth 令牌和 ssh 密钥。你可以在不重建容器镜像的情况下部署和更新密钥和应用程序配置,也无需在堆栈配置中暴露密钥,类似热部署。
  • 存储编排

    • Kubernetes 允许你自动挂载你选择的存储系统,特别对有状态应用实现数据持久化非常重要。
    • 存储系统可以来自于本地目录、网络存储(NFS、Gluster、Ceph 等)、公共云存储服务。
  • 批处理

    • 提供一次性任务,定时任务;满足批量数据处理和分析的场景。

集群架构与组件

Kubernetes 集群架构以及相关的核心组件如下图所示:一个 Kubernetes 集群一般包含一个 Master 节点和多个 Node 节点,一个节点可以看成是一台物理机或虚拟机。



1、Master

Master 是 K8S 的集群控制节点,每个 K8S 集群里需要有一个 Master 节点来负责整个集群的管理和控制,基本上 K8S 所有的控制命令都是发给它,它来负责具体的执行过程。

Master 节点通常会占据一个独立的服务器,因为它太重要了,如果它不可用,那么所有的控制命令都将失效。

Master 节点上运行着以下关键组件:

  • kube-apiserver

    • 集群的统一入口,各组件协调者,以 HTTP Rest 提供接口服务,所有对象资源的增、删、改、查和监听操作都交给 apiserver 处理后再提交给 Etcd 存储。
    • 提供认证、授权、访问控制、API注册和发现等机制。
  • kube-controller-manager

    • K8S 里所有资源对象的自动化控制中心,处理集群中常规后台任务,一个资源对应一个控制器。
    • controller-manager 就是负责管理这些控制器的。
  • kube-scheduler

    • 根据调度算法为新创建的 Pod 选择一个 Node 节点,可以任意部署,可以部署在同一个节点上,也可以部署在不同的节点上。
  • etcd

    • 是一个分布式的,一致的 key-value 存储,主要用途是共享配置和服务发现,保存集群状态数据,比如 Pod、Service 等对象信息。

Kubernetes 架构具备高可用:一方面 Master 节点高可用;另一方面所部署的业务也是高可用的。系统高可用的核心在于冗余部署,当某一个节点或程序出现异常时,其他节点或程序能分担或替换工作。

Master 节点高可用,主要由以下几个方面的设计实现:

  1. Master 由多台服务器构成
  2. API Server 多实例同时工作,负载均衡
  3. etcd 多节点,一主多从
  4. controller-manager 与 scheduler 抢主实现

2、Node

除了 Master,K8S 集群中的其它机器被称为 Node 节点,Node 节点是 K8S 集群中的工作负载节点,每个 Node 都会被 Master 分配一些工作负载,当某个 Node 宕机时,其上的工作负载会被 Master 自动转移到其它节点上去。

每个 Node 节点上都运行着以下关键组件:

  • kubelet:kubelet 是 Master 在 Node 节点上的 Agent(代理),与 Master 密切协作,管理本机运行容器的生命周期,负责 Pod 对应的容器的创建、启停、Pod挂载数据卷、下载secret、获取容器和节点状态等任务,实现集群管理的基本功能。kubelet 将每个 Pod 转换成一组容器。

  • kube-proxy:在 Node 节点上实现 Pod 网络代理,实现 Kubernetes Service 的通信,维护网络规则和四层负载均衡工作。

  • docker engine:Docker 引擎,负责本机的容器创建和管理工作。

Node 节点可以在运行期间动态增加到 K8S 集群中,前提是这个节点上已经正确安装、配置和启动了上述关键组件。在默认情况下 kubelet 会向 Master 注册自己,一旦 Node 被纳入集群管理范围,kubelet 就会定时向 Master 节点汇报自身的情况,例如操作系统、Docker 版本、机器的 CPU 和内存情况,以及之前有哪些 Pod 在运行等,这样 Master 可以获知每个 Node 的资源使用情况,并实现高效均衡的资源调度策略。而某个 Node 超过指定时间不上报信息时,会被 Master 判定为“失联”,Node 的状态被标记为不可用(Not Ready),随后 Master 会触发“工作负载大转移”的自动流程。

核心概念

Pod

Pod 是 K8s 中最重要也是最基本的概念,Pod 是最小的部署单元,也是最小的调度单位。

一个 Pod 简单来说是对一组容器的抽象,它里面会包含一个或多个容器。每个 Pod 都由一个特殊的根容器(Pause 容器)以及一个或多个紧密相关的用户业务容器组成。Pause 容器作为 Pod 的根容器,以它的状态代表整个容器组的状态。K8S 为每个 Pod 都分配了唯一的 IP 地址,称之为 Pod IP。Pod 里的多个业务容器共享 Pause 容器的IP,共享 Pause 容器挂载的 Volume。

用户可以通过 Kubernetes 的 Pod API 生产一个 Pod,让 Kubernetes 对这个 Pod 进行调度。

Volume(存储卷)

Volume 是用来管理 Kubernetes 存储的,声明 Pod 中的容器可以访问文件目录。一个卷可以被挂载在 Pod 中一个或者多个容器的指定路径下面。

默认情况下 Docker 容器中的数据都是非持久化的,在容器消亡后数据也会消失。因此 Docker 提供了 Volume 机制以便实现数据的持久化。Kubernetes 中 Volume 的概念与 Docker 中的 Volume 类似,但不完全相同。

Kubernetes 提供了非常丰富的 Volume 类型:

  1. emptyDir:临时空间,Pod 分配到 Node 时创建,无须指定宿主主机上对应的目录,在 Kubernetes 会自动分配当前 Node 的一个目录,当 Pod 被移除时,emptyDir 中的数据也会永久删除。
  2. hostPath:为 Pod 挂载宿主主机上的文件或目录。用于数据永久保存。在不同的 Node 上具有相同配置的 Pod,可能会因为宿主机上的目录和文件不同而导致 Volume 上的目录和文件的访问结果不一致。
  3. gcePersistentDisk:使用谷歌公有云提供的永久磁盘。数据永久保存。
  4. NFS:NFS 是 Network File System 的缩写,即网络文件系统。Kubernetes 中通过简单地配置就可以挂载 NFS 到 Pod 中,而 NFS 中的数据是可以永久保存的,同时 NFS 支持同时写操作。k8s 挂载 NFS
  5. Persistent Volume:简称 PV,就是网盘,网络存储,不属于任何 Node,但可以在每个 Node 上访问。

Label

标签,附加到某个资源上,用于关联对象、查询和筛选。

一个 Label 是一个 key=value 的键值对,key 与 value 由用户自己指定。Label 可以附加到各种资源上,一个资源对象可以定义任意数量的 Label,同一个 Label 也可以被添加到任意数量的资源上。

我们可以通过给指定的资源对象捆绑一个或多个不同的 Label 来实现多维度的资源分组管理功能,以便于灵活、方便地进行资源分配、调度、配置、部署等工作。

K8S 通过 Label Selector(标签选择器)来查询和筛选拥有某些 Label 的资源对象。Label Selector 有基于等式(name=label1)和基于集合(name in (label1, label2))的两种方式。

Replication Controller(RC)

RC 是 Kubernetes 系统中的核心概念之一。它能够保证 Pod 持续运行,并且在任何时候都有指定数量的 Pod 副本,在此基础上提供一些高级特性,比如滚动升级和弹性伸缩。

在我们定义了一个 RC 并将其提交到 Kubernetes 集群中后,Master 上的 Controller Manager 组件就会得到通知,定期巡检系统中当前存活的目标 Pod,并确保目标 Pod 实例的数量刚好等于此 RC 的期望值,如果有过多的 Pod 副本在运行,系统就会停掉一些 Pod,过少则会再创建一些 Pod。

相比传统的IT环境,如果程序意外挂掉,需要手工重启,但是在 k8s 通过 RC,就大大减少这些手工运维工作。

ReplicaSet(下一代的RC)

ReplicaSet 实现了 Pod 的多副本管理。使用 Deployment 时会自动创建 ReplicaSet,也就是说 Deployment 是通过 ReplicaSet 来管理 Pod 的多个副本,所以我们通常不需要直接使用 ReplicaSet。

  1. Replication Controller 由于与 Kubernetes 代码中的模块 Replication Controller 同名,并且“Replication Controller”无法准确表达它的本意,所以在 Kubernetes1.2 中,升级为另外一个新概念——Replica Set,官方解释为“下一代的RC”
  2. 我们很少单独使用 Replica Set,它主要被 Deployment 这个更高层的资源对象所使用。

Deployment(应用管理者)

Deployment 是在 Pod 这个抽象上更为上层的一个抽象,它可以定义一组 Pod 的副本数目、以及这个 Pod 的版本。一般大家用 Deployment 这个抽象来做应用的真正的管理,而 Pod 是组成 Deployment 最小的单元。

Kubernetes 是通过 Controller 去维护 Deployment 中 Pod 的数目,它也会去帮助 Deployment 自动恢复失败的 Pod。

比如我可以定义一个 Deployment,这个 Deployment 里面有两个 Pod,当一个 Pod 失败的时候,控制器就会监测到,并把 Deployment 中的 Pod 数目恢复到两个。通过控制器,我们也会帮助完成发布的策略。比如说进行滚动升级,进行重新生成的升级,或者进行版本的回滚。

Deployment 内部使用了 Replica Set 来实现的,我们可以把 Deployment 看做 RC 的一次升级。创建 Deployment 对象后,master 会根据 Deployment 对象的配置文件去描述应用,应用名称,使用的镜像名称,需要几个实例,多少内存,多少CPU资源。

Horizontal Pod Autoscaler(HPA)

HPA 为 Pod 横向自动扩容,也是 K8S 的一种资源对象。HPA 通过追踪分析 RC 的所有目标 Pod 的负载变化情况,来确定是否需要针对性调整目标 Pod 的副本数量。

Service

Service 提供了一个或者多个 Pod 实例的稳定访问地址。

我们看到:一个 Deployment 可能有两个甚至更多个完全相同的 Pod。对于一个外部的用户来讲,访问哪个 Pod 其实都是一样的,所以它希望做一次负载均衡,在做负载均衡的同时,我只想访问某一个固定的 VIP,也就是 Virtual IP 地址,而不希望得知每一个具体的 Pod 的 IP 地址。

还有一种场景,这个 pod 本身可能 terminal go(终止),如果一个 Pod 失败了,可能会换成另外一个新的。对一个外部用户来讲,提供了多个具体的 Pod 地址,这个用户要不停地去更新 Pod 地址,当这个 Pod 再失败重启之后,我们希望有一个抽象,把所有 Pod 的访问能力抽象成一个第三方的一个 IP 地址,实现这个的 Kubernetes 的抽象就叫 Service。

实现 Service 有多种方式,Service 对外提供多种入口:

  1. ClusterIP:Service 在集群内的唯一ip地址,虚拟的 IP,只能在 Kubernetes 集群里访问。通过 ClusterIP,负载均衡的访问后端的 Pod。
  2. NodeIP+NodePort:Service 会在集群的每个 Node 上都启动一个端口,通过 NodeIP:NodePort 访问后端的Pod。

kube-proxy 是 kubernetes 核心组件,运行在集群中每一个节点上,负责监控集群中service、endpoint变更,维护各个节点上的转发规则,是实现 servcie 功能的核心部件。

Namespace

Namespace 是用做一个集群内部的逻辑隔离的,它包括鉴权、资源管理等。Kubernetes 的每个资源,比如刚才讲的 Pod、Deployment、Service 都可以属于一个 Namespace,同一个 Namespace 中的资源需要命名的唯一性,不同的 Namespace 中的资源可以重名。

比如像在阿里巴巴,内部会有很多个 business units,在每一个 business units 之间,希望有一个视图上的隔离,并且在鉴权上也不一样,在 cuda 上面也不一样,我们就会用 Namespace 来去给每一个 BU 提供一个他所看到的这么一个看到的隔离的机制。

K8S 集群在启动后,会创建一个名为 default 的 Namespace,如果不特别指明 Namespace,创建的 Pod、RC、Service 都将被创建到 default 下。

当我们给每个租户创建一个 Namespace 来实现多租户的资源隔离时,还可以结合 K8S 的资源配额管理,限定不同租户能占用的资源,例如 CPU 使用量、内存使用量等。

ConfigMap

ConfigMap 顾名思义,是用于保存配置数据的键值对,可以用来保存单个属性,也可以保存配置文件。就是为了让镜像和配置文件解耦,以便实现镜像的可移植性和可复用性,因为一个 configMap 其实就是一系列配置信息的集合,将来可直接注入到 Pod 中的容器使用,而注入方式有两种,一种将 configMap 做为存储卷,一种是将 configMa p通过 env 中 configMapKeyRef 注入到容器中。

Kubernetes 的 API

Kubernetes API 是由 HTTP+JSON 组成的:用户访问的方式是使用 HTTP,访问的 API 中 content 内容是 JSON 格式的。

Kubernetes 的 kubectl、Kubernetes UI、或者有时候用 curl 都是使用 HTTP + JSON。

K8S 中所有的资源对象都可以采用 yaml 或 json 格式的文件定义或描述。

完整流程

  • 通过 Kubectl 提交一个创建 RC(Replication Controller)的请求,该请求通过 APlserver 写入 etcd。
  • 此时 Controller Manager 通过 API Server 的监听资源变化的接口监听到此 RC 事件,分析之后,发现当前集群中还没有它所对应的 Pod 实例,于是根据 RC 里的 Pod 模板定义一个生成 Pod 对象,通过 APIServer 写入 etcd。
  • 此事件被 Scheduler 发现,它立即执行执行一个复杂的调度流程,为这个新的 Pod 选定一个落户的 Node,然后通过 API Server 讲这一结果写入 etcd 中。
  • 目标 Node 上运行的 Kubelet 进程通过 APiserver 监测到这个”新生的Pod。并按照它的定义,启动该 Pod 并任劳任怨地负责它的下半生,直到 Pod 的生命结束。
  • 随后,我们通过 Kubectl 提交一个新的映射到该 Pod 的 Service 的创建请求。
  • ControllerManager 通过 Label 标签查询到关联的 Pod 实例,然后生成 Service 的 Endpoints 信息,并通过 APIServer 写入到 etcd 中。
  • 接下来,所有 Node 上运行的 Proxy 进程通过 APIServer 查询并监听 Service 对象与其对应的 Endponts 信息,建立一个软件方式的负载均衡器来实现 Service 访问到后端 Pod 的流量转发功能。

Kubernetes 中的 k 用大写吗

在 Kubernetes 社区中,有一个共识:将 Kubernetes 中的 k 写成大写。这是因为Kubernetes 是一个商标,并且官方文档和相关资料中都将 k 写成大写。虽然在代码中可以使用小写 k,但是为了与官方保持一致,我们应该尽量使用大写。

Reference


02-Kubernetes 简介
https://flepeng.github.io/042-云原生-02-kubernetes-00-简介-02-Kubernetes-简介/
作者
Lepeng
发布于
2023年3月1日
许可协议