共计 6151 个字符,预计需要花费 16 分钟才能阅读完成。
综述
学习 Kubernetes 时,发现它的概念和术语还是比较多的,光靠啃官方文档比较晦涩。所以边学习边整理,对主要的概念和术语做一下分类及简要说明。感觉把重要概念都理解了,对 Kubernetes 的设计思想,整体框架也就有了初步的认识。
从功能上来说,我把 Kubernetes 的概念或术语大概分为以下三类:
组件:指实际在集群中运行的 Kubernetes 程序集,分为 Master 组件、Node 组件及附加组件。
对象:对象是一个抽象的概念实体,Kubernetes 把应用、运行场景、功能、集群状态等都抽象成一个个对象,并通过 API 对这些对象进行管理,从而管理整个集群的状态。
标识:对组件和对象的各种表示方式,例如命名、标签、注释等。标识是 KubernetesAPI 与操作对象间的纽带。
组件
Master 组件
Master 组件提供了 k8s 管理集群的核心功能,k8s 通过 Master 组件实现整个集群的调度管理,它就像集群的大脑,会根据集群当前的状态,不断进行调整,使集群一直保持在期望的状态。Master 组件包括以下几个进程:
kube-apiserverapiserver 进程对外暴露 REST API 接口给外部客户端及内部组件调用,它封装了对各个对象的增、删、改、查操作,可以说是整个集群管理的总入口。
kube-schedulerkube-scheduler 做的事情说来简单 – 监控新 pod 的创建,并把 pod 分配到合适的 node 来运行。但实际上,选择“合适的 Node”是一个很复杂的过程,需要考虑的因素包括单 node 及整个集群的资源需求、软硬件资源的限制策略、数据存储、工作负载间的干扰等等。
kube-controllers-managercontrollers-manager 进程从字面上理解,是用来做控制器管理的。controllers-manager 其实是一组守护进程,通过监控集群各组件的状态,并不断调整集群实际状态,使的集群向期望状态调整,它由一组子进程构成:
replication controller
endpoints controller
namespace controller
serviceaccounts controller
Etcd
Etcd 是 Kubernetes 集群的基础组件,用于保存集群所有的元数据信息、配置信息、对象状态等。
Node 组件
运行 Node 组件的节点称为 Node 节点,是 k8s 集群实际的工作负载节点。Node 节点可以是物理机、虚拟机或任何可以运行 Node 组件的设备。所有的业务应用都运行在 Node 节点中。Node 组件包括以下几个部分:
Kubeletkubelet 负责实际的容器管理,Kubernetes 通过 apiserver 给 kubelet 发送 Pod 管理请求,同时把 Pod 及 Node 的运行状态汇报给 apiserver。
kube-proxykube-proxy 负责集群内部的请求转发及负载均衡工作。它通过 Service 对象的配置信息,为 Pod 创建代理服务,实现请求从 Service 到 Pod 的路由转发。
容器运行时
实际的容器运行引擎。Kubernetes 其实支持其他的容器技术比如 rkt,但是 Docker 相比与它们处于绝对的优势地位。所以,Kubernetes 生态中的容器也基本特指指 Docker 容器。
对象
Kubernetes 中,所谓对象指的就是 API 对象。Kubernetes 集群为每个对象维护三类信息:对象元数据 (ObjectMeta)、期望状态(Desired State) 与实际状态(Autual State), 元数据指对象的基本信息,比如命名、标签、注释等等,用于识别对象;期望状态一般由用户配置 spec 来描述的;实际状态是由集群各个组件上报的集群实际的运行情况。Kubernetes 努力使每个对象的实际状态与期望状态相匹配,从而使整个集群的状态与用户配置的期望状态一致。Kubernetes 对象一般用 yaml 文件来描述,有几个个字段是必须的:
apiVersion: 创建该对象所使用的 Kubernetes API 的版本
kind: 想要创建的对象的类型
metadata: 帮助识别对象唯一性的数据,包括一个 name 字符串、UID 和可选的 namespace
spec: 对象期望状态的描述
用户通过命令行工具 kubectl 来操作这些对象,Kubectl 吧 yaml 转换成 JSON 格式来执行 API 请求。下面是一个 POD 对象的描述文件示例及注释:
apiVersion: v1
kind: Pod # 对象名称
metadata: # 对象的基本信息
name: pod-example # 对象唯一标示
spec: # 期望状态
containers: # 指定 pod 中运行的容器镜像及运行参数(类似 Dockerfile)
– name: ubuntu
image: ubuntu:trusty
command: [“echo”]
args: [“Hello World”]
其中,kind 字段描述对象类型 ”Pod”,spec 之前是对象的 ObjectMeta,spec 开始,就是对象期望状态的描述。
根据官方 API 对象参考文档的分类,下面我们把对象分为几大类来分别简要说明。计划以后的文章,会结合实际操作,对各个重要对象做更深入的说明。
Workloads 资源对象
– workloads 类的对象用于管理运行容器实例
Pod:Pod 是 Kubernetes 里最重要的对象,也是 Kubernetes 集群中运行部署应用或服务的最小单位。Pod 对象描述一个 Pod 由哪些容器镜像构成,以及这些容器应该怎么运行。类比传统的业务架构,Pod 更接近于虚拟机的角色而不是应用进程的角色。
ReplicaSet:ReplicaSet 对象是对 Pod 的更高一层抽象,它用来管理一组相同 POD 副本,并确保这组相同 Pod 的数量始终与用户期望一致,并实现 Pod 的高可用。即如果有容器异常退出,ReplicaSet 会自动创建新的 Pod 来替代,保证 Pod 数量永远与用户配置一致。
Deployment:Deployment 对象是 Kubernetes 中最常用的对象之一,用于部署无状态服务。它在 ReplicaSet 对象的基础上,又做了一层抽象。通过管理多组 ReplicaSet 对象,来实现 POD 的滚动升级、回滚、扩容缩容等。
StatefulSet:不同于 Deployment,StatefulSet 对象顾名思义是对有状态服务的一种抽象。所以,StatefulSet 对象在定义时,相比与 Deployment 多了一些与状态相关的内容,比如持久化存储、服务对外的不变的唯一标示、部署、扩容、滚动升级时确保有序等等。
DaemonSet:DaemonSet 对象是 Kubernetes 对守护进程的抽象。当我们需要集群中的每个 Node 都跑一些如日志收集、监控等守护进程时,就可以把这类型进程包装成 Pod,并用调用 DaemonSet 来部署了。DaemonSet 做的事情其实和 Deployment 差不多,只不过 Deployment 对象部署的 Pod,会根据集群情况,在不同 Node 间自动调度。而 DaemonSet 会指定的 NODE 上(默认是集群所有 Node),都部署定义 Pod,确保这些 NODE 都有跑着守护进程 Pod。
Job、CronJob:除了上面几个对象所抽象描述的应用工作场景外,实际业务场景中,还有一类应用或服务并不需要一直运行,比如一些一次性任务,或需要定时执行的任务。这种不需要长时间运行的任务,完成了就可以退出的服务,就可以用 Job 对象来定义。CronJob 和 Job 对象的关系,和 Deployment 与 ReplicaSet 的关系很像,可以类比来理解。首先,Job 也是直接用于管理 Pod 的,同时可以定义这个一次性任务 Pod 的执行时间、超时时间、错误处理(重启还是生成新 Pod)等任务属性。而 CronJob 管理是用来管理 Job,类似 crobtab,它可以通过 yaml 文件中的 schedule 字段配置具体时间,来控制指定 Job 定时执行,从而实现定时执行特定的一次性任务。
Discovery & LB 资源对象
– 该类对象用于服务发现和负载均衡的对象
Service:上面提到的对象都是用于管理 POD 及容器实例的。但是,业务系统光有 POD 实例还不够,还必须对外提供服务。这里就会衍生出两个问题:
Pod 的 IP 地址并不是固定,而是随着编排不断变化的,外面的请求怎么找到对应的 POD,这个也就是大多数分布式业务都会遇到的服务发现问题
多个相同 Pod 一起提供服务的时候,它们的负载均衡怎么实现
而 Service 对象就是用来解决这两个问题的。它用固定的 VIP 或 DNS 名称和指定标识的一组 Pod 对应起来,不管 Pod IP 怎么变,Service 对外的 VIP 都不会变化,并且,自动的将请求在这组 Pod 中负载均衡。
Config & Storage 资源对象
– 该类对象用于初始化容器配置及持久化容器存储的对象
Volume:前面说到,Pod 里的不同容器可以共享存储,这个共享存储就靠 Volume 来配置的。要注意的是,这里 Volume 与 Docker 中的定义不用,Kubernetes 中 Volume 跟 Pod 生命周期一致,Pod 终止了,该 Pod 挂载的 Volume 就失效了(根据挂载 volume 的类型不同,数据可能丢失也可能不丢失)。
PV,PVC:Volume 可以支持多种类型的存储,除了直接在 Volume 字段中去声明所有存储细节,K8S 还抽象出了 PV 和 PVC 对象。简单来说 PV 是对具体存储资源的描述,比如存储类型、地址、访问账户等;而 PVC,是对怎么使用资源的方法的描述,比如只读只写,需要的空间等;而 Pod 通过 Volume 字段挂载具体要使用的 PVC。PV 和 PVC 是独立于 Pod 单独定义的,这样,就把共享存储的配置、分割、挂载等操作都解耦了。比如,一个 NFS 迁移后 ip 地址变了,存储管理员只需要修改 PV 中的配置,而不用关心具体哪个业务 POD 在使用这个 NFS。
ConfigMap,SecuretK8S 中除了常见的存储,还有一类特殊的 Volume,不是为了 Pod 存放数据,而是为了给 Pod 提供数据的。ConfigMap 和 Secret 对象就是用来定义这类型的 Volume。简单来说,可以将它们理解为一份 Key:Value 格式的数据,Pod 可以通过 Volume 挂载它们,将这份数据保存成文件随时调用。唯一的区别是,ConfigMap 对象保存的数据是明文,一般作为应用配置文件;而 Secret 对象保存的对象要求是经过 Base64 转码的,用于提供数据库密码等对安全要求比较高的配置。不过这些配置,直接在做容器镜像时就配置不就好了,为啥要多此一举呢?原因和上面 PV 和 PVC 一样,都是为了尽可能解耦业务核心与经常可能变化的依赖配置。比如数据库更换了账号,只需要修改 Secret 对象,不用重新去构建容器镜像。
Cluster resources objects
– 该类对象定义整个 K8S 集群运行方式的对象
NamespaceKubernetes 作为一个集群管理平台,为不同用户划分不同权限管理,例如多租户等,是必备的功能。而不同用户作用域的隔离,就是靠 Namespace 对象实现的。Namespace 是 Kubernetes 项目中的一个逻辑管理单位,不同 Namespace 的 API 对象,在调用 API 进行操作是,是相互隔离开的。通过不同用户角色与 Namespace 关联,从而实现权限管理。
Metadata resources
– 除了上述分类外的其他对象都归为这一类,一般用来管理集群的特殊功能比如弹性伸缩等
Horizontal Pod Autoscaling 容器作为一个轻量级的承载应用的技术,快速启动和快速部署是它的优点之一。自然的,根据业务负载自动扩缩容等需求,在容器集群的可行性和效率就可以变得很高。而 Kubernetes 中 Horizontal Pod Autoscaling 对象,就是用于进行 POD 自动水平缩放的,这也是 Kubernetes 最能体现运维优势的特性之一。Horizontal Pod Autoscaling 具体的操作对象是 Deployment 和 ReplicaSet,通过不同循环获取每个 Pod 的资源情况,比如 CPU 利用率,并根据设定的目标利率来计算目前需要的 Pod 副本缩放的比例,然后通过访问相应的 Deployment 或 ReplicaSet 对象,来对 Pod 数量进行自动缩放,从而提高了集群资源整体利用率。
标识
标识是 Kubernetes 中最重要的概念,因为它是所有 API 的操作与操作对象间的纽带。Kubernetes 中的标识主要有以下几种:
LabelLabel 可以说是 Kubernetes 中最最重要的核心概念,一个 Lable 是一个 KEY=Value 的键值对。任何对象资源都可以有一个或多个 Label,而同个 Label,也可以配置在多个对象上。然后重点来了,大多数 API 对象的 yaml 字段中,都有 Label Selector 字段,可以实现对 Label 中的 key 或 value 的多维度选择,例如 in、not in、and、or 等等。这样,Kubernetes 对 API 作用对象就能进行多维度,细粒度的选择,从而实现比较精细化的容器编排调度工作,比如, 对所有 ”ENV:release” 执行扩容操作,或者把部分请求灰度到有 ”ver:v1.14.0″ 的 pod 上等等。Label 把资源对象和应用、基础设施都解耦了,你不用关心这个 Pod 具体在那个 Node 上运行,也不用关心具体是什么应用用了哪个容器镜像,只要 Label 符合 Label Selector,就可以通过 API 调用统一进行操作。
Names 除了 Label,所有资源对象肯定还必须有一个全局唯一的标识,即 Names 字段。
AnnotationAnnotation 很好理解,与通常意义的注释一样,用于描述作者、版本、配置说明等等任何需要的信息,需要说明的是,Annotation 也必须是 Key:Value 格式的。
总结
通过上面对 Kubernetes 重要概念的说明,我们可以大致梳理出 Kubernetes 的一些设计理念:
Kubernetes 对容器应用进行了抽象,例如把一个容器或强关联的一组容器抽象为 Pod,把各类存储都抽象成 Volume,把一组 Pod 抽象成 Service 等等基础对象。
在基础对象的层面上,Kubernetes 又对应用使用场景,做了一层抽象。极客时间的 Kubernetes 课程有一张图画的很好:可以看到,Kubernetes 中各个对象实际就是对生产业务场景的各类需求的抽象。
抽象出各类型对象以后,用户可以通过 yaml 文件(或直接命令行调用 API)来描述这些对象的期望状态,确认了各对象些期望状态的集合,也就确认了整个集群的期望状态。这些所有的操作,都是声明式的,而不是命令集群要怎么做
Kubernetes 通过控制器循环不断将各组件收集来的集群实际状态与各对象的期望状态对比,并自动化的将集群实际状态向期望状态转移,这个过程,也就是 Kubernetes 最核心的概念:编排。
本文对 Kubernetes 中的重要概念做了分类和简要,后面的文章会结合集群的实际操作,对每个概念做更详细的说明。