写点什么

Kubernetes 概念篇:基本概念和术语

用户头像
xcbeyond
关注
发布于: 2021 年 01 月 15 日

在开始使用之前,应当先了解一下关于Kubernetes的相关概念术语,对后续的学习、使用将有很大的帮助。(Kubernetes的概念比较多,建议加强理解,并清楚各种所处位置及关联!)


Kubernetes

中的大部分概念,如:NodePodReplication ControllerService等都可以看作是一种资源对象,几乎所有资源对象都可以通过Kubernetes提供的kubectl工具(或者 API 接口)执行增、删、改、查等操作并将其保存在etcd中持久化存储。


从这个角度来看,Kubernetes其实是一个高度自动化的资源控制系统,它通过跟踪对比etcd库里保存的“资源期望状态”与当前环境中的“实际资源状态”的差异来实现自动控制和自动纠错的高级功能。


本文将介绍Kubernetes中重要的资源对象,即:Kubernetes的基本概念和术语。


1、Master


Master是指Kubernetes集群中的控制节点(Master Node),在每个Kubernetes集群里都需要有一个Master来负责整个集群的管理和控制,基本所有的控制命令都发给它,它负责具体的执行过程,后续执行的所有命令基本都是在Master上运行。


Master提供集群的独特视角,并且拥有一系列组件,比如Kubernetes API ServerAPI Server提供可以用来和集群交互的 REST 端点。可以通过命令行或图形化界面来维护 Pod、副本和服务。



在 Master 上包括以下组件:


  • etcd: 分布式 key-value 存储,保存集群的状态数据、资源对象数据。

  • API Server(kube-api-server): Kubernetes 提供的 HTTP Rest 接口,是所有资源的增、删、改、查等操作的唯一入口,也是集群控制的入口进程。

  • Controllers(kube-controller-manager): Kubernetes 里所有资源对象的自动化控制中心。

  • Scheduler(kube-scheduler): 负责资源调度(Pod 调度)的进程,相当于公交公司的"调度室"。

2、Node


除了 Master,Kubernetes 集群中的其他集群被称为Node,即:Worker Node(工作节点)。与 Master 一样,Node 可以是一台物理主机,也可以是一台虚拟机。


Node是 Kubernetes 集群中的工作负载节点,每个 Node 都会被 Master 分配一些工作负载,当某个 Node 宕机时,其上的工作负载会被 Master 自动转移到其他节点上。


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

  • kubelet: 负责 Pod 对应的容器创建、启停等任务,同时与 Master 密切协作,实现集群管理的基本功能。

  • kube-proxy: 实现 Kubernetes Service 的通信与负载均衡机制的重要组件。

  • Container Runtime: 下载镜像、运行容器。如 Docker 引擎,负责本机的容器创建和管理工作。


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


执行命令kubectl get nodes可以查看在集群中有多少个 Node:

[xcbeyond@localhost ~]$ kubectl get nodesNAME       STATUS   ROLES    AGE   VERSIONminikube   Ready    master   17d   v1.19.0
复制代码


然后通过kubectl describe node <node_name>查看某个 Node 的详细信息:

[xcbeyond@localhost ~]$ kubectl describe node minikubeName:               minikubeRoles:              masterLabels:             beta.kubernetes.io/arch=amd64                    beta.kubernetes.io/os=linux                    kubernetes.io/arch=amd64                    kubernetes.io/hostname=minikube                    kubernetes.io/os=linux                    ……
复制代码


3、Pod


Pod是 Kubernetes 中的原子对象,是基本构建单元。


Pod表示集群上一组正在运行的容器。通常创建 Pod 是为了运行单个主容器。Pod 还可以运行可选的 sidecar 容器,以实现诸如日志记录之类的补充特性。(如:在 Service Mesh 中,和应用一起存在的istio-proxyistio-init容器)


通常用 Deployment 来管理 Pod。


一个Pod中可以包含多个容器(其他容器作为功能补充),负责处理容器的数据卷、秘钥、配置。


如下图所示是Pod的组成示意图,我们可以看到每个Pod都有一个特殊的被称为“根容器”的 Pause 容器。Pause 容器对应的镜像属于 Kubernetes 平台的一部分,除了 Pause 容器,每个 Pod 还包含一个或多个紧密相关的用户业务容器。


为什么 Kubernetes 会设计出一个全新的 Pod 概念,并且 Pod 要有这样特殊的组成结构?


  • 在一组容器作为一个单元整体的情况下,我们难以对“整体”简单地进行判断及有效地进行控制。比如,一个容器死亡了,此时算是整体死亡么?引入业务无关并且不易死亡的 Pause 容器作为 Pod 的根容器,以它的状态代表整体容器组的状态,就简单、巧妙地解决了这个难题。

  • Pod 里的多个业务容器共享 Pause 容器的 IP,共享 Pause 容器挂接的 Volume,这样既简化了密切关联的业务容器之间的通信问题,也很好地解决了它们之间的文件共享问题。


Kubernetes 为每个 Pod 都分配了唯一的 IP 地址,称之为 Pod IP,一个 Pod 里的多个容器共享 Pod IP 地址。


Kubernetes 要求底层网络支持集群内任意两个 Pod 之间的 TCP/IP 直接通信,这通常采用虚拟二层网络技术来实现,例如 Flannel、Open vSwitch 等,因此我们需要牢记一点:在 Kubernetes 里,一个 Pod 里的容器与另外主机上的 Pod 容器能够直接通信。


Pod 有两种类型:

  • 普通的 Pod

  • 静态 Pod(Static Pod)


后者比较特殊,它并不存放在 Kubernetes 的 etcd 存储里,而是存放在某个 Node 上的一个有个文件中,并且只在此 Node 上启动运行。而普通的 Pod 一旦被创建,就会被放入到 etcd 中存储,随后会被 Kubernetes Master 调度到某个具体的 Node 上并进行绑定(Binding),随后该 Pod 被对应的 Node 上的 kubelet 进程实例化成一组相关的 Docker 容器并且启动起来。


在默认情况下,当 Pod 里的某个容器停止时,Kubernetes 会自动检测到这个问题并且重新启动这个 Pod(重启 Pod 里的所有容器),如果 Pod 所在的 Node 宕机,则会将这个 Node 上的所有 Pod 重新调度到其他节点上。Pod、容器与 Node 的关系图如下图所示。


Pod 的生命周期是不确定的,可能非常短暂,但 Pod 具有很强的再生能力,在死后可以自动重新启动(重启机制)。Pod 生命周期整个过程中,通常可能处于以下五个阶段之一:


  • Pending Pod 定义正确,提交到 Master,但其所包含的容器镜像还未完全创建。通常,Master 对 Pod 进行调度需要一些时间,Node 进行容器镜像的下载也需要一些时间,启动容器也需要一定时间。

  • Running Pod 已经被分配到某个 Node 上,并且所有的容器都被创建完毕,至少有一个容器正在运行中,或者有容器正在启动或重启中。

  • Succeeded Pod 中所有的容器都成功运行结束,并且不会被重启。这是 Pod 的一种最终状态。

  • Failed Pod 中所有的容器都运行结束了,其中至少有一个容器是非正常结束的(exit code 不是 0)。这也是 Pod 的一种最终状态。

  • Unknown 无法获得 Pod 的状态,通常是由于无法和 Pod 所在的 Node 进行通信。

4、Label


Label(标签)是 Kubernetes 中另外一个核心概念。一个 Label 是一个 key=value 的键值对,其中 key 与 value 由用户自己指定。Label 可以被附加到各种资源对象上,例如 Node、Pod、Service、RC 等,一个资源对象可以定义任意数量的 Label,同一个 Label 也可以被添加到任意数量的资源对象上。Label 通常在资源对象定义时确定,也可以在对象创建后动态添加或删除。


一般来说,我们会给指定的资源对象定义多个 label,来实现多维度的资源分组管理,以便灵活、方便地进行资源分配、调度、配置、部署等管理工作。例如:部署不同版本的应用到不同的环境中,或者监控和分析应用(日志记录,监控,报警等)。一些常用的 Label 示例如下:


  • 版本标签:release:stablerelease: canary

  • 环境标签:environment: devenvironemnt: qaenvironment: production

  • 架构标签:tier: frontendtier: backendtier: middleware

  • ……


某个资源对象定义了 Label 后,可以通过 Label Selector(标签选择器)查询和筛选 Label 的资源对象,Kubernetes 通过这种方式实现了类似 SQL 的对象查询机制。


通常我们通过描述文件中的spec.selector字段来指定 Label,从而 Kubernetes 寻找到所有包含你指定 Label 的对象,进行管理。


Kubernetes 目前支持两种类型的 Label Selector:


  • 基于等式的 Selector(Equality-based):等式雷表达式匹配标签。

  • 基于集合的 Selector(Set-based):集合操作类表达式匹配标签。


使用Label可以给对象创建一组或多组标签,LabelLabel Selector共同构成了 Kubernetes 系统中最核心的应用模型,使得对象能够精细分组、管理,同时实现了集群的高可用性。




5、Replication Controller


Replication Controller,简称 RC,是 Kubernetes 中核心概念之一,定义了一个期望的场景,即:声明某种 Pod 的副本数量在任意时刻都符合某个预期值。


RC 的定义包括以下几个部分:

  • Pod 预期的副本数量。

  • 用于筛选目标 Pod 的 Label Selector。

  • 当 Pod 的副本数量小于预期数量时,用于创建新 Pod 的 Pod 模板。


下面以有 3 个 Node 的集群为例进行,说明 Kubernetes 如何通过 RC 来实现 Pod 副本数量自动控制的机制。


假如在我们的 RC 里定义 redis-slave 这个 Pod 需要保持 2 个副本,系统将可能在其中的两个 Node 创建 Pod,如下图所示:

假如 Node 2 上的 Pod 意外终止,则根据 RC 定义的 replicas 数量 2,Kubernetes 将自动创建并启动一个新的 Pod,以保证整个集群中始终有两个 redis-slave 运行。如下图所示,Kubernetes 可能选择 Node 3 或者 Node 1 来创建一个新的 Pod。


此外,在运行时,我们可以通过修改 RC 的副本数量,来实现 Pod 的动态缩放(Scaling),可通过执行kubectl scale rc redis-slave --replicas=3命令一键完成。执行结果示意如下图所示:

注意:删除 RC 并不会影响通过该 RC 创建好的 Pod。 删除所有 Pod,可以设置 replicas 的值为 0,然后更新该 RC。另外,kubectl 也提供了 stop 和 delete 命令来一次性删除 RC 和 RC 控制的全部 Pod。


最后,总结一下 RC 的特性和作用:


  • 大多数情况下,通过自定义一个 RC 实现 Pod 的创建过程及副本数量的自动控制。

  • RC 里包含完整的 pod 定义模板。

  • RC 通过 label selector 机制实现对 pod 副本的自动控制。

  • 通过改变 RC 里的 Pod 副本数量,实现对 Pod 的扩容和缩容功能

  • 通过改变 RC 里 Pod 模板中的镜像版本,可以实现 Pod 的滚动升级功能


6、Deployment


Deployment是 Kubernetes 在 1.2 版本中引入的新概念,用于更好地解决 Pod 的编排问题。为此,Deployment在内部使用了 Replica Set 来实现,无论从 Deployment 的作用、YAML 定义,还是从它的具体命令行操作来看,我们都可以把它看作是 RC 的一次升级。


Deployment相对于 RC 的一个最大升级是我们可以随时知道当前 Pod 部署的进度。


典型使用场景:

  • 创建 Deployment 对象来生成对应的 Replica set 并完成 Pod 副本的创建。

  • 检查 Deployment 的状态来看部署动作是否完成(Pod 副本数是否达到预期值)。

  • 更新 Deployment 来创建新的 Pod。

  • 如果当前 Deployment 不稳定,则回滚到一个先前的 Deployment 版本。

  • 暂停 Deployment 以便于一次性修改多个 PodTemplateSpec 的配置项,之后再恢复 Deployment,进行新的发布。

  • 扩展 Deployment 以应对高负载。

  • 查看 Deployment 状态,以此作为发布是否成功的指标。


7、StatefulSet


在 Kubernetes 中,Pod 的管理对象 RC、Deployment、DaemonSet 和 Job 都是面向无状态的服务。但现实中有很多服务是有状态的,特别是一些复杂的中间件集群,例如 MySQL 集群、MongoDB 集群、Kafka 集群、Zookeeper 集群等,这些应用集群有以下一些共同点。


  • 每个节点都有固定的身份 ID,通过这个 ID,集群中的成员可以相互发现并且通信。

  • 集群的规模是比较固定的,集群规模不能随意变动。

  • 集群里的每个节点都是有状态的,通常会持久化数据到永久存储中。

  • 如果磁盘损坏,则集群里的某个节点无法正常运行,集群功能受损。


如果用 RC 或 Deployment 控制 Pod 副本数的方式来实现上述有状态的集群,则我们会发现第一点是无法满足的,因为 Pod 的名字是随机产生的,Pod 的 IP 地址也是在运行期才确定且可能有变动的,我们事先无法为每个 Pod 确定唯一不变的 ID,为了能够在其他节点上恢复某个失败的节点,这种集群中的 Pod 需要挂接某种共享存储,为了解决这个问题,Kubernetes 从 v1.4 版本开始引入了 PetSet 这个新的资源对象,并且在 v1.5 版本时更名为StatefulSetStatefulSet从本质上来说,可以看作 Deployment/RC 的一个特殊变种,它有如下一些特性。


  • StatefulSet 里的每个 Pod 都有稳定、唯一的网络标识,可以用来发现集群内的其他成员。假设 StatefulSet 的名字叫 kafka,那么第一个 Pod 叫 kafak-0,第二个 Pod 叫 kafak-1,以此类推。

  • StatefulSet 控制的 Pod 副本的启停顺序是受控的,操作第 n 个 Pod 时,前 n-1 个 Pod 已经时运行且准备好的状态。

  • StatefulSet 里的 Pod 采用稳定的持久化存储卷,通过 PV/PVC 来实现,删除 Pod 时默认不会删除与 StatefulSet 相关的存储卷(为了保证数据的安全)。


StatefulSet除了要与 PV 卷捆绑使用以存储 Pod 的状态数据,还要与 Headless Service 配合使用,即在每个StatefulSet的定义中要声明它属于哪个 Headless Service。Headless Service 与普通 Service 的关键区别在于,它没有 Cluster IP,如果解析 Headless Service 的 DNS 域名,则返回的是该 Service 对应的全部 Pod 的 Endpoint 列表。StatefulSet 在 Headless Service 的基础上又为 StatefulSet 控制的每个 Pod 实例创建了一个 DNS 域名,这个域名的格式为:

$(podname).$(headless service name)
复制代码

比如一个 3 节点的 Kafka 的 StatefulSet 集群,对应的 Headless Service 的名字为 kafka,StatefulSet 的名字为 kafka,则 StatefulSet 里面的 3 个 Pod 的 DNS 名称分别为 kafka-0.kafka、kafka-1.kafka、kafka-3.kafka,这些 DNS 名称可以直接在集群的配置文件中固定下来。


8、Service


Service也是 Kubernetes 里的最核心的资源对象之一,Kubernetes 里的每个 Service 其实就是我们经常提起的微服务架构中的一个“微服务”,上面我们所说的 Pod、RC 等资源对象其实都是为讲解 Kubernetes Service 做铺垫的。下图显示了 Pod、RC 与 Service 的逻辑关系。


从图中我们看到,Kubernetes 的 Service 定义了一个服务的访问入口地址,前端的应用(Pod)通过这个入口地址访问其背后的一组由 Pod 副本组成的集群实例,Service 与其后端 Pod 副本集群之间则是通过 Label Selector 来实现“无缝对接”的。而 RC 的作用实际上是保证 Service 的服务能力和服务质量始终处于预期的标准。


9、Job


Job(批处理任务)通过并行或串行启动多个进程去处理一批工作,在处理完成后,整个批处理任务结束。从 Kubernetes 1.2 版本开始,支持批处理类型的应用,可以通过 Kubernetes Job 这种新的资源对象定义并启动一个批处理任务 Job。与 RC、Deployment、ReplicaSet 类似,Job 也是用来控制一组 Pod 容器。


Job负责批量处理短暂的一次性任务 ,即仅执行一次的任务,它保证批处理任务的一个或多个 Pod 成功结束。


10、Volume


Volume(存储卷)是 Pod 中能够被多个容器访问的共享目录。Kubernetes 的 Volume 概念、用途和目的与 Docker 的 Volume 比较类似,但两者不能等价。首先,Kubernetes 中的 Volume 定义在 Pod 上,然后被一个 Pod 里的多个容器挂载到具体的文件目录下;其次,Kubernetes 中的 Volume 中的数据也不会丢失。最后,Kubernetes 支持多种类型的 Volume,例如 Gluster、Ceph 等先进的分布式文件系统。


11、Namespace


Namespace(命名空间)是 Kubernetes 系统中的另一个非常重要的概念,Namespace 在很多情况下用于实现多租户的资源隔离。Nameaspace 通过将集群内部的资源对象“分配”到不同的 Namespce 中,形成逻辑上分组的不同项目、小组或用户组,便于不同的分组在共享使用整个集群的资源的同时还能被分别管理。


Kubernetes 集群默认会创建一个名为 default 的 Namespace,通过kubectl可以查看:

[xcbeyond@bogon ~]$ kubectl get namespacesNAME                   STATUS   AGEdefault                Active   23distio-system           Active   22dkube-node-lease        Active   23dkube-public            Active   23dkube-system            Active   23dkubernetes-dashboard   Active   23d
复制代码

如果不特别指定 Namespace,则用户创建的 Pod、RC、Service 等都将创建到默认的 default 的 Namespace 中。


12、Annotation


Annotation(注解)与 Label 类似,也使用 key/value 键值对的形式进行定义。不同的是 Label 具有严格的命名规则,它定义的是 Kubernetes 对象的元数据(Metadata),并且用于 Label Selector。而Annotation则是用户任意定义的“附加”信息,以便于外部工具进行查找,很多时候,Kubernetes 的模块自身会通过 Annotation 的方式标记资源对象的特殊信息。


通常来说,用Annotation来记录的信息如下:


build 信息、release 信息、Docker 镜像信息等,例如时间戳、release id 号、PR 号、镜像 hash 值、docker registry 地址等。

日志库、监控库、分析库等资源库的地址信息。

程序调试工具信息,例如工具、版本号等。

团队等联系信息,例如电话号码、负责人名称、网址等。


13、ConfigMap


为了能够准确、深刻理解Kubernetes ConfigMap的功能和价值,可以先从 Docker 说起。我们都知道,Docker 通过将程序、依赖库、数据及配置文件等“打包固化”到一个不变的镜像文件,以解决因应用部署差异的难题,但这同时带来了另一个棘手的问题,即:配置文件中的参数在运行期间如何修改的问题。为了解决这个问题,Docker 提供了以下两种方式:


  • 通过环境变量来传递参数。

  • 通过 Docker Volume 将容器外的配置文件映射到容器内。


在大多数情况下,我们更倾向于后一种方式,应该大多数应用通常拥有多个参数,配置文件映射的方式简洁。但这种方式也有明显的缺陷:必须事先在宿主机上创建好配置文件,然后容器启动时才能够映射到容器里。


如果在分布式系统中,就会变得更加糟糕,多台宿主机上创建相同的配置文件,并且要确保这些配置文件的一致性,是很难实现的。为此,Kubernetes 引入了ConfigMap,巧妙的解决了这种问题。


把所有的配置项都当作 key-value 字符串,如:配置项 host=192.168.1.1、user=root、password=123456 用于表示连接 FTP 服务器的配置参数。这些配置项作为 Map 表中的一项,整个 Map 的数据被持久化存储在 Kubernetes 的 etcd 中,并提供 API 方便 Kubernetes 相关组件或应用 CRUD 操作,这里用来保存配置参数的 Map 就是 Kubernetes ConfigMap 资源对象。


ConfigMap 机制: 将存储在 etcd 中的 ConfigMap 通过 Volume 映射方式变为目标 Pod 内的配置文件,不管目标 Pod 被调度到哪台服务器上,都会自欧东完成映射。如果 ConfigMap 中的 key-value 数据被修改,则映射到 Pod 中的“配置文件”也会随之自动更新。于是,ConfigMap 就形成了分布式系统中最为简单且对应用无侵入的配置中心。


14、总结


上述的这些概念术语也是 Kubernetes 的核心组件,它们共同构成了 Kubernetes 的框架和计算模型。通过对它们进行灵活组合,用户就可以快速、方便地对容器集群进行配置、创建和管理。除了本文介绍的概念外,Kubernetes 中还有许多其他的概念,用于辅助配置资源对象,如:LimitRange、ResourceQuota 等,更多概念术语可参照官方术语表:https://kubernetes.io/zh/docs/reference/glossary/?fundamental=true


参考文章:

1.https://phoenixnap.com/kb/understanding-kubernetes-architecture-diagrams

2.https://k21academy.com/docker-kubernetes/kubernetes-architecture-components-overview-for-beginners/


发布于: 2021 年 01 月 15 日阅读数: 790
用户头像

xcbeyond

关注

不为别的,只为技术沉淀、分享。 2019.06.20 加入

公众号:程序猿技术大咖,专注于技术输出、分享。

评论

发布
暂无评论
Kubernetes概念篇:基本概念和术语