书籍名称:[基于 Kubernetes 的容器云实战]
Kubernetes 的核心概念
与其他技术一样,Kubernetes 也会采用一些专用词汇,这可能对初学者的理解和掌握这项技术造成一定的障碍。本节就一些常用的术语进行说明,以帮助读者快速理解 Kubernetes 的基本概念。
Pod
Kubernetes 的基本调度单元称为 “Pod”,一个 Pod 可以包含一个或多个容器。这样可以保证同一个 Pod 内的容器运行在同一个宿主机上,并且可以共享资源。这些容器使用相同的网络命名空间,IP 地址和端口。
kubernetes 中的每个 Pod 都被分配一个唯一的 IP 地址,这样就可以允许应用程序使用端口而不会有冲突的风险。另外,同一个 Pod 的容器还可以共享一块存储卷空间,可以定义一个卷,如本地磁盘目录或网络磁盘。在 Kubernetes 中创建,调度和管理的最小单元是 Pod,而不是 Docker 容器。用户可以通过 Kubernetes API 手动管理 Pod,也可以委托给控制器来管理 Pod。
Replication Controller
Replication Controller 用于管理,控制 Pod 的副本数,用于解决 Pod 的扩容,缩容问题。
通常,分布式应用为了性能或高可用性的考虑,需要复制多份资源,并且根据负载情况实现动态伸缩。通过 Replication Controller,我们可以指定一个应用需要几份副本,Kubernetes 将为每份副本创建一个 Pod,并且保证实际运行 Pod 数量总是与该副本数量相等。如果少于指定数量的 Pod 副本,Replication Controller 会重新启动新的 Pod 副本,反之会杀死多余的副本以保证数量不变。
Service
Service 是真实应用服务的抽象,定义了 Pod 的逻辑集合和访问这个集合的策略。
Service 是一组协同工作的 Pod,就像多层架构应用中的一层,是 Pod 的路由代理抽象,用于解决 Pod 之间的服务发现问题。因为 Pod 的运行状态可动态变化(比如 Pod 迁移到其他机器或者在缩容过程中被终止等),所以访问端不能以固定 IP 的方式去访问该 Pod 提供的服务。Service 的引入旨在保证 Pod 的动态变化对访问端透明,访问端只需要知道 Service 的地址,由 Service 来提供代理。构成服务的 Pod 组通过 Label 选择器来定义。Kubernetes 通过给服务分配静态 IP 地址和域名来提供服务发现机制,并且以轮询调度的方式将流量负载均衡到能与选择器匹配的 Pod 的 IP 地址的网络连接上(即使故障导致 Pod 从一台机器移动到另一台机器)。
默认情况下,一个服务会暴露在集群中(例如,多个后端 Pod 可能被分组成一个服务,前端 Pod 的请求在它们之间负载均衡);但是一个服务也可以暴露在集群外部(例如,从客户端访问前端 Pod)。
Lable 及 Label Selector
Kubernetes 将称为 Label 的键值对附加到系统中的任何 API 对象上,如 Pod,Service,Replication Controller 等。实际上,Kubernetes 中的任意 API 对象都可以通过 Label 进行标识。每个 API 对象可以有多个 Label,但每个 Label 的 Key 只能是唯一值。相应的,Label Selector 则是针对匹配对象的标签来进行查询。Label 和 Label Selector 是 Kubernetes 中的主要分组机制,用于确定操作适用的组件。
例如,如果应用程序的 Pod 具有系统的标签 tier(如:”front-end”, “back-end”)和一个 release_track(如:”canary”, “production”),那么对所有 back-end 和 canary 节点的操作可以使用如下所示的 Label Selector:
1 | tier=back-end AND release_track=canary |
Node
Node 也称为 Worker 或 Minion 节点,是主从分布式集群架构的计算单元,是分配给 Pod 并运行 Pod 的宿主机。
Kubernetes 集群中的每个计算节点都必须运行 Docker 引擎以及下面提到的组件,以便与这些容器的网络配置进行通信。每个 Node 节点主要由三个模块组成:kubelet,kube-proxy,runtime。
Master
Master 是 Kubernetes 分布式集群的管理控制中枢,所有任务分配都来自与此。
Master 节点主要由四个模块组成:
- API Server
- scheduler
- controller manager
- etcd
Kubernetes 架构及组件
尽管 Docker 为容器管理提供了一个有用的抽象层和工具层,但 Kubernetes 不仅带来了类似的协助,还可以进行大规模容器编排并管理完整的应用程序栈。
Kubernetes 为我们提供了自动化和工具来确保高可用性和服务可移植性。Kubernetes 还可以更好的控制资源使用情况,如整个基础架构中的 CPU,内存和磁盘空间。Kubernetes 的大多数管理交互都是通过 kubectl 脚本或 Restful 服务调用 API 来完成的。下图是 Kubernetes 的架构图
Kubernetes 管理集群及其工作负载的关键是:对比期望状态和实际状态。所有 Kubernetes 都在不断监测当前的实际状态,并通过 API 服务器或 Kubectl 脚本与管理员定义的期望状态进行同步。有时候这些状态不匹配,但系统总是在努力调和这两个状态。
Master 节点
客户端通过 kubectl 命令行工具或 kubectl Proxy 来访问 Kubernetes 系统,在 Kubernetes 集群内部的客户端可以直接使用 kubectl 命令管理集群。kubectl Proxy 是 API 服务器的一个反向代理,在 Kubernetes 集群外部,客户端可以通过 kubectl Proxy 来访问 API 服务器。
从本质上讲,Kubernetes 管理节点是 Kubernetes 集群的大脑。Kubernetes 管理节点包含 API 服务器,它提供基于 Restful 的 Web Service 接口以用于查询或者定义我们所需要的各种集群和状态。需要注意的是,所有 Kubernetes 集群对象的增、删、改、查操作只能通过访问 Kubernetes 管理集群的主管理节点来操作,不能直接访问各 Node 节点。
API 服务器内部有一套完整的安全机制,包括认证,授权及准入控制等相关模块。API 服务器在收到一个 REST 请求后,会首先执行认证,授权和准入控制的相关逻辑,过滤非法请求,然后将请求发送给 API 服务器中的 REST 服务模块以执行资源的具体操作逻辑。
此外,Kubernetes 管理节点还包含调度程序,该程序与 API 服务器协同工作,以 Node 节点上的实际 Pod 为单位进行工作负载调度。默认情况下,基本 Kubernetes 调度程序将各 Pod 分散到集群中,并使用不同的节点来匹配 Pod 副本。Kubernetes 还允许为每个容器指定必要的资源,因此可以通过这些附加因素来改变调度策略。
复制控制器与 API 服务器一起工作,以确保在任何给定时间正确运行 Pod 副本数量。如果我们的复制控制器定义了三个副本,并且我们的实际状态是两个 pod 副本,那么调度程序将被调用以在集群中某处添加第三个 Pod 副本。如果在任何给定时间发现集群中运行的 Pod 副本数较多,则会销毁部分 Pod 副本。通过这种方式,Kubernetes 总是保持用户预先设定的集群状态。
最后,Kubernetes 将 Etcd 作为分布式配置存储,各种 Kubernetes 状态存储在 etcd 中,Etcd 允许第三方软件监视值的变化,因此,可以将 Etcd 理解成 Kubernetes 的共享记忆。
接下来,所有 Node 节点上运行的 Proxy 进程通过 API 服务器查询并监听 Service 对象及其对应的 Endpoint(端点)信息,建立一个软件方式的负载均衡器来实现 Service 访问到后端 Pod 的流量转发功能。
从上面的分析来看,Kubernetes 的各个组件的功能是很清晰的:
API 服务器: 提供了 Kubernetes 资源对象的唯一操作入口,其他组件都必须通过它提供的 API 来操作资源数据,通过对相关的资源数据 “全量查询 + 变化监听”,这些组件可以很 “实时” 地完成相关的业务功能,比如新建 Pod 的请求一旦被提交到 API 服务器中,Controller Manager 就会立即发现并开始调度。
Controller Manager: 集群内部的管理控制中心,其主要目的是实现 Kubernetes 集群的故障检测和恢复的自动化工作。比如,根据 Replication Controller(RC,复制控制器)的定义完成 Pod 的复制或移除,以确保 Pod 实例数符合 RC 副本的定义;根据 Service 与 Pod 的管理管理,完成服务的 Endpoint 对象的创建和更新;其他诸如 Node 的发现,管理和状态监控,已杀死容器所占磁盘空间及本地缓存的镜像文件的清理等工作也都由 Controller Manager 来完成。
Schedule:负责集群的资源调度,以及 Pod 在集群中的调度分配。资源调度在整个 Kubernetes 管理节点中是一个独立的组件,也就意味着可以根据客户需求定制化开发自己的调度器或者替换成第三方调度器。
Node 节点
在每个 Node 节点中,都有几个关键组件。
Kubelet 与 API 服务器交互以更新状态并启动调度程序调用的新工作负载,kubelet 负责管理 Pod 和它上面的容器,Images(镜像),Volumes(卷)等。
kube-proxy 提供基本的负载均衡,并将指定的服务的流量指向后端正确的 Pod,正如 Kubernetes API 所定义的这些服务,可以在各类终端中以轮询的方式做一些简单的 TCP 和 UDP 传输。
在 Node 节点运行的 kubelet 服务中内嵌了一个 Advisor 服务,Advisor 是 Google 的另外一个开源项目,用于实时监控 Docker 上运行的容器的性能指标。
调度控制原理
Controller Manager 是 Kubernetes 集群内部的管理控制中心,负责 Kubernetes 集群内的 Node,Pod,服务端点,服务,资源配额,命名空间,服务账号等资源的管理,自动化部署,健康监测,并对异常资源执行自动化修复,确保集群各资源始终处于预期的工作状态。
Controller Manager 是一个控制器集合,包含:
- Replication Controller
- Node Controller
- Resourcequota Controller
- Namespace Controller
- Serviceaccount Controller
- Token Controller
- Service Controller
- Endpoint Controller
Controller Manager 是这些控制器的核心管理者。一般来说,智能系统和自动系统通常会通过一个操纵系统来不断的修正系统的状态。在 Kubernetes 集群中,每个控制器的核心工作原理就是:每个控制器通过 API 服务器来查看系统的运行状态,并尝试着将系统状态从 “现有状态” 修正到 “期望状态”.
在 Kubernetes 集群中与 Controller Manager 并重的另一个组件是 Kubernetes Scheduler。
Kubernetes Scheduler 的主要作用是将待调度的 Pod 按照给定的调度算法和调度策略绑定到 Kubernetes 集群中某个合适的 Node 上,并将绑定信息写入 Etcd 中进行存储。
在整个调度过程中涉及三个对象:
- 待调度 Pod 列表
- 可用 Node 列表
- 调度算法和调度策略
简单的说,就是依据调度算法和调度策略,从可用 Node 列表中筛选出最适合的一个 Node 给待调度 Pod。
随后,目标节点上的 Kubelet 通过 API 服务器监听到 Kubernetes Scheduler 产生的 Pod 绑定事件,获取对应的 Pod 清单,下载 image 镜像并启动容器,然后再将 Pod 创建结果反馈给 API 服务器。
集群功能模块间的通讯
作为 Kubernetes 集群的核心,API 服务器负责 Kubernetes 集群各功能模块之间的信息交互。Kubernetes 集群内的功能模块都是通过 API 服务器的接口函数调用将信息存入 Etcd 的,其他模块可通过 API 服务器(用 get,list 或 watch方式)来读取这些信息,从而实现模块之间的信息交互。
例如,Node 节点上的 Kubelet 每隔一个时间周期,通过 API 服务器报告自身状态,API 服务器接收到这些信息后,将 Node 节点状态信息保存到 Etcd 中。Controller Manager 中的 Node Controller 通过 API 服务器定期读取这些 Node 节点状态信息,并做相应处理。又比如,Scheduler 监听到某个 Pod 创建的信息后,检索所有符合该 Pod 要求的 Node 节点列表,并将 Pod 绑定到节点列表中最符合要求的 Node 节点上;如果 Scheduler 监听到某个 Pod 被删除,则调用 API 服务器删除该 Pod 资源对象。Kubelet 一直监听 Pod 信息,一旦监听到 Pod 对象被删除,则删除本节点上相应的 Pod 实例;如果 Kubelet 监听到要修改 Pod 信息,则 Kubelet 修改本节点的 Pod 实例等。
为了缓解集群各个模块对 API 服务器的访问压力,各功能模块都采用缓存机制来缓存数据。各功能模块定时通过 API 服务器接口调用方式获取指定资源对象信息(通过 list 及 watch 方式),并将信息进行本地缓存。这样一来,在一些情况下各功能模块通过访问本地缓存的方式来获取数据信息,而不需要直接访问 API 服务器。
Kubernetes 高可用方案
系统的高可用性一直是用户重点关注的话题。在生产环境中,任何系统都需要持续,可靠的运行,特别是针对 Kubernetes 这样的云管理平台,因为 Kubernetes 系统承载着大量的应用,它的任何故障都可能使大面积的业务受影响,重要性不言而喻。
Kubernetes 系统属于主从分布式架构,它的重要数据都集中存储在 Etcd 上,Etcd 在整个 Kubernetes 集群中处于核心数据库的地位,数据层的可靠性至关重要,为保证 Kubernetes 集群的高可用性,首先要保证数据库不是单点故障。Etcd 需要以集群的方式进行部署,以实现 Etcd 数据存储的冗余,备份与高可用性。
Kubernetes 作为容器应用的管理中心,对集群内所有容器的生命周期进行管理,结合自身的健康检查及错误恢复机制,实现了集群内部应用层的高可用性。
Kubernetes Master 服务扮演着总控制中心的角色,其主要的三个服务 kube-apiserver,kube-controller-manager 和 kube-scheduler 通过不断与工作节点上 Kubelet 和 kube-proxy 进行通信来维护整个集群的健康状态。
Kubernetes Node 运行后将会注册到 Kubernetes Master,并定时上报心跳信息以说明其可用。Kubernetes Master 调度 Pod 到可用的 Kubernetes Node 部署运行,如果 Master 服务无法访问到某个 Node,则会将该 Node 标记为不可用,并不再向其调度新建的 Pod。如果 Kubernetes Node 发生宕机,Kubernetes Master 会将该 Kubernetes Node 设置为不可用状态,然后 Replication Controller 会重新创建 Pod,从而调度到新的 Kubernetes Node 上。当然,Kubernetes Node 的数目至少要大于 2 才可以保障 Pod 的高可用性。
以 Master 的 kube-apiserver,kube-controller-manager 和 kube-scheduler 三个服务作为一个部署单元,类似于 Etcd 集群的典型部署配置。使用至少三台服务器安装 Master 服务,并且使用 Active-Standby-Standby 模式,保证任何时候总有一套 Master 能够正常工作。所有 工作节点上的 Kubelet 和 kube-proxy 服务则需要访问 Master 集群的统一访问入口地址,例如,可以使用 Pacemaker 等工具来实现。下图展示了一种典型的部署方式
Kubernetes 部署方案总结
Kubernetes 可以在多种平台运行,从笔记本电脑到云服务商的虚拟机,再到机架上的裸机服务器。要创建一个 Kubernetes 集群,根据不同的场景需要做的也不尽相同,可能是运行一条命令,也可能是配置自己的定制集群。
如果用户只想试试 Kubernetes 的功能,我们推荐基于 Docker 的本地方案。本地服务器方案可在一台物理机上创建一个或者多个 Kubernetes 计算节点的单机集群。创建过程是全自动的。但是这种单击集群的规模和可用性都受限于单台机器。当用户准备好扩展到多台机器和更高可用性时,托管解决方案是最容易搭建和维护的。
全套云端方案只需要少数几个命令就可以在更多的云服务提供商搭建 Kubernetes 集群。并且有很活跃的社区支持,如 GCE,AWS,Azure。
定制方案需要花费更多的精力,但是覆盖了从零开始搭建 Kubernetes 集群的通用建议到分步骤的细节指引。
Kubernetes 官方和社区针对不同系统和平台提供了自动化部署脚本,具体情况如下表:
laaS Provider | Config.Mgmt | OS(操作系统) | Networking |
---|---|---|---|
GKE | GCE | ||
Vagrant | SaltStack | Fedora | Flannel |
GCE | SaltStack | Debian | GCE |
Azure | CoreOS | CoreOS | Weave |
Docker Single Node | custom | N/A | local |
Docker Multi Node | Flannel | N/A | local |
Bare-metal | Ansible | Fedora | Flannel |
Bare-metal | custom | Fedora | none |
Bare-metal | custom | Fedora | Fannel |
libvirt | custom | Fedora | Flannel |
KVM | custom | Fedora | Flannel |
AWS | CoreOS | CoreOS | Flannel |
GCE | CoreOS | CoreOS | Flannel |
Vagrant | CoreOS | CoreOS | Flannel |
Bare-metal(Offline) | CoreOS | CoreOS | Flannel |
Bare-metal | CoreOS | CoreOS | Calico |
CloudStack | Ansible | CoreOS | Flannel |
VMware | Debian | OVS | |
Bare-metal | custom | CentOS | none |
AWS | juju | Ubuntu | flannel |
OpenStack/HPCloud | Juju | Ubuntu | Flannel |
Joyent | Juju | Ubuntu | Flannel |
AWS | SaltStack | Ubuntu | OVS |
Azure | SaltStack | Ubuntu | OpenVPN |
Bare-metal | custom | Ubuntu | Flannel |
Bare-metal | custom | Ubuntu | Calico |
libvirt/KVM | CoreOS | CoreOS | Libvirt/KVM |
Rackspace | CoreOS | CoreOS | Flannel |
表格中各列说明
- laaS Provider 是指提供 Kubernetes 运行环境的虚拟机或物理机(节点)资源的提供商
- OS 是指节点上运行的基础操作系统
- Config.Mgmt 是指节点上安装和管理 Kubernetes 软件的配置管理系统
- Networking 是指实现网络模型的软件,none 表示只支持一个节点,或支持单物理节点上的虚拟机节点
Kubernetes 从开发至今,其部署方式已经变得越来越简单。常见的有以下三种方式:
- 最简单的就是使用 Minikube 方式,下载一个二进制文件即可拥有一个单机版的 Kubernetes,而且支持各个平台;
- 从源码安装。使用这种方式可以进行一些简单的配置,然后执行 kube-up.sh 就可以部署一个 Kubernetes 集群。可参见官方文档
- 通过 kubeadm 部署,可参见官方文件;
除了上面三种方式外,一些 Linux 发行版还提供了 Kubernetes 的安装包(比如 CentOS 7),直接执行 yum install -y etcd kubernetes 即可安装 Kubernetes,然后做些配置就可以完成部署了。
现在简单化的部署昂视屏蔽了很多细节,使得我们对于各个模块的感知少了很多,而且很容易觉得 Kubernetes 的内部部署细节非常麻烦或者复杂,但其实并非如此,因此强烈建议自行纯手工安装一套 Kubernetes 系统,对深入理解 Kubernetes 解决方案有很强的辅助作用。