精通Kubernetes
上QQ阅读APP看书,第一时间看更新

本节将简要介绍许多与Kubernetes相关的重要概念,并提供一些案例来说明这些概念的重要性和相互间的关系,以便熟悉这些术语和概念。接着,介绍如何将这些概念编排在一起以实现令人敬畏的效果。读者可将其中的许多概念视为构建块。一些概念被视作一个Kubernetes组件来执行,如节点和主节点。这些组件处于不同的抽象级,这将在1.5节中进行详细讨论。

图1.1是著名的Kubernetes架构。

0101

图1.1 Kubernetes架构

集群是主机存储和网络资源的集合,Kubernetes使用集群来运行组成系统的各种工作负载。一个完整的系统可以由多个集群组成。之后会详细讨论集群联邦的高级用例。

节点是单个主机,它可以是物理机或虚拟机,职责是运行Pod。每个Kubernetes节点运行多个Kubernetes组件,如Kuberlet和Kube代理。节点由Kubernetes主控制器管理,这些节点类似于Kubernetes的工蜂,肩负重担,过去它们被称为下属(Minion)。如果读者曾阅读过以往的文献资料,请不要被混淆,下属即指节点。

主节点是Kubernetes的控制面板,由几个组件组成,包含API服务器、调度器和控制器管理器。主节点负责节点在全局、集群水平的调度和事件处理。通常,所有的主控制器组件都设置在一个单一主机上,在考虑到高可用性场景或大型集群时,会倾向于采用多个主节点。在第4章中将详细说明高可用性集群。

Pod是Kubernetes的工作单元,每个Pod包含一个或多个容器,Pod通常在同一台机器上运行并一起调度。Pod中的所有容器具有相同的IP地址和端口空间,它们可通过本地主机或标准进程进行通信。此外,Pod中的所有容器都可以访问承载于Pod的节点上的本地共享存储,共享存储会存在于每个容器上。Pod是Kubernetes的重要特征,通过作为运行于多个进程的主Docker应用程序的超级管理员,可以实现在单个Docker容器中运行多个应用程序,但出于以下几点,并不鼓励这种做法。

  • 透明性:使Pod内的容器对基础设施可见,使得基础设施能够向这些容器提供服务,例如流程管理和资源监控,这为用户提供了许多便利。
  • 解耦软件依赖:可以独立地对单个容器进行版本化、重建和重新部署。Kubernetes甚至有望支持单个容器的实时更新。
  • 易用性:用户无须运行自有进程管理器,也不需要担心信号和退出代码的事务传播等。
  • 效率:由于基础设施将承担更多的职责,因此容器可以更加轻量。

对于相互依赖且需要在同一主机上协作以实现其目标的容器组,Pod提供了很好的解决方案。切记,Pod被认为是临时、可替代的实体,需要的话可以被丢弃和替换,Pod可破坏任何Pod存储。每个Pod都有一个唯一的ID(UID),因此,区分它们仍是可实现的。

标签是用来组合对象集合(通常是Pod)的键值对。这对于其他几个概念非常重要,例如副本控制器、副本集以及需要在对象动态组上进行操作、标识组成员的服务。对象和标签之间存在N×N的关系,每个对象可以具有多个标签,并且每个标签可以应用于不同的对象。标签的设计有一定的限制,对象上的每个标签都必须且有唯一密钥,标签密钥必须遵守严格的语法。它的语法包含两个部分:前缀和名称。前缀是可选的,如果它存在,则通过前斜杠(/)与名称分离,并且必须是有效的DNS子域,前缀最多包含253个字符。名称是强制的,最多包含63个字符。名称必须以字母、数字、字符(a~z、A~Z、0~9)开头和结尾,并且只包含字母、数字、字符、点、破折号和下划线。值的规则与名称相同。需注意的是,标签只用于标识对象,而不会将任何元数据附加到对象中。这便是注解的目的(参见1.2.6节)。

注解可使任意元数据与Kubernetes对象关联。Kubernetes只存储注解并使其元数据可用。与标签不同的是,它对字符类型和大小没有严格要求。复杂的系统通常需要这样的元数据,而Kubernetes可识别这样的需求并提供开箱即用的元数据,这样用户则不必提取自己单独的元数据存储进行映射。

这里已涵盖了大部分Kubernetes的概念,也对其进行了简要概括。在1.2.7节中,将从其设计动机、内部结构与实现、源代码方面继续研究Kubernetes的体系结构。

标签选择器根据标签选择对象,基于相等的选择器指定键名和值。基于值的等式或不等式,它有两个运算符:=(或==)和!=,代码如下。

role = webserver

这将选择所有具有该标签键和值的对象。

标签选择器可以用多个逗号分隔,代码如下。

role = webserver, application != foo

基于集合的选择器扩展性能并允许基于多个值进行选择,代码如下。

role in (webserver, backend)

副本控制器和副本集管理由标签选择器标识的一组Pod,确保一定数量的Pod始终运行。它们之间的主要区别在于,副本控制器通过名称匹配来测试成员资格,副本集则通过基于集合的选择器。副本集更新,并被指定为下一代副本控制器。它还处于测试阶段,且在编写时不能被所有工具支持。但也许读者在读到这本书时,它已完全成熟。

Kubernetes会保证在副本控制器或副本集中保持相同数量的Pod运行。在因主机节点或Pod本身的问题而导致数量下滑时,Kubernetes将启动新的用例。需注意的是,如果人为启动Pod并超过指定数量,则副本控制器将结束多余Pod的进程。

副本控制器曾经是许多工作流的中心,例如滚动更新和运行一次性作业。随着Kubernetes的发展,它引入了对很多类似工作流的直接支持,例如Deployment、Job和DaemonSet等专用对象。这些将在下面的章节中提到。

服务向用户或其他服务暴露一些功能。它们通常包含一组Pod,由标签进行区分。服务可提供对外部资源的访问路径,或者直接控制虚拟IP的Pod。本地Kubernetes服务器通过便捷的端点暴露功能。需注意的是,服务在第3层(TCP/UDP)进行。Kubernetes 1.2添加了入口对象,该对象提供对HTTP对象的访问,后续会对这一部分展开详谈。服务可通过以下两种机制之一被发布或发现:DNS或环境变量。服务可以由Kubernetes均衡负载。但当服务使用外部资源或需要特殊处理时,开发人员可自行管理和均衡负载。

与IP地址、虚拟IP地址和端口空间相关的细节,都将在之后的章节中深入讨论。

Pod上的存储是临时的,会随Pod一起消失。如果只是在节点的容器间交换数据,这已经足够,但有时数据需要在Pod上存储更长的时间,或在Pod间传递数据,存储卷的概念便支持了这种需求。需注意的是,虽然Docker中也有存储卷的概念,但它仍比较有限(尽管功能越来越强大)。Kubernetes使用自有的存储卷,并且支持额外的容器类型(如rkt),因此在根本上它独立于Docker的存储卷。

存储卷类型有多种,Kubernetes目前直接支持所有类型。如果可添加间接层,则抽象存储卷插件也许会被开发。emptyDir存储卷类型会在每个容器上安装一个卷,该卷会默认在宿主机器的任意可用容器上备份。如果需要,可以请求存储介质。当Pod由于任何原因终止时,此存储会被删除。对于特定的云环境、各种联网的文件系统,甚至Git存储库,都有许多存储卷类型。一个比较有意思的存储卷类型是PersistentDiskClaim,它概括了部分细节,并在开发者的云提供商环境中使用默认的持久存储。

如果关注Pod上的数据,则可以使用持久化存储。但若需要Kubernetes管理诸如Kubernetes或MySQL Galera分布式数据存储库,便不能用常规的Pod和服务来模拟它,因为这些集群存储使数据分布在唯一的节点上。说回有状态服务集,前文讨论了宠物与牲畜的关系,以及牲畜是如何管理和执行的。有状态服务集介于二者之间。有状态服务集能够确保给定数量的具有唯一标识的宠物在任意给定时间运行(类似于复制控制器)。宠物具有以下特性。

  • 在DNS中可用的稳定主机名。
  • 序数索引。
  • 与序数和主机名相连接的稳定存储。

有状态服务集可以帮助对等体发现、添加或移除宠物。

密钥对象是包含敏感信息的小型对象,如凭据和令牌。它们以明文的形式存储在etcd中,可通过Kubernetes API服务器访问,并在需要访问时作为文件装入Pod中(使用负载于常规容量上的专用密钥对象容量)。相同的密钥对象可被安装到多个Pod中。Kubernetes本身已为它的组件加密,开发者也可以创造自有密钥对象。另一种方法是使用密钥对象作为环境变量。需注意的是,为获得更好的安全性,在预制密钥对象的情况下,Pod中的密钥对象一般存储于tmpfs内存中。

Kubernetes中的每个对象都由UID和名称标识,该名称用于引用API调用中的对象。名称应不超过253个字符,并使用小写字母数字字符、下划线(_)和圆点(.)。如果删除对象,则可以创建与已删除对象具有相同名称的另一对象,但UID在集群生命周期中必须是唯一的。UID由Kubernetes生成,因此无须担心其重复。

命名空间是一个虚拟集群。由命名空间分隔的多个虚拟集群可组成一个单独的物理集群。每个虚拟集群与其他虚拟集群完全隔离,它们只能通过公共接口交换信息。需注意的是,节点对象和持久化存储卷不存在于命名空间中。Kubernetes可以调度来自不同命名空间的Pod在同一节点运行。同样,来自不同命名空间的Pod可以使用相同的持久存储。

在使用命名空间时,必须考虑网络策略和资源配额,以确保物理集群资源的正确访问和分配。