1.2 Kubernetes概述
尽管公开面世不过短短数年时间,Kubernetes业已成为容器编排领域事实上的标准,其近一两年的发展状态也在不断地验证着Urs Hölzle曾经的断言:无论是公有云、私有云抑或混合云,Kubernetes都将作为一个为任何应用、任何环境提供的容器管理框架而无处不在。
1.2.1 Kubernetes简史
Kubernetes(来自希腊语,意为“舵手”或“飞行员”)由Joe Beda、Brendan Burns和Craig McLuckie创立,而后Google的其他几位工程师,包括Brian Grant和Tim Hockin等加盟共同研发,并由Google在2014年首次对外宣布。Kubernetes的开发和设计都深受Google内部系统Borg的影响,事实上,它的许多顶级贡献者之前也是Borg系统的开发者。
Borg是Google内部使用的大规模集群管理系统,久负盛名。它建构于容器技术之上,目的是实现资源管理的自动化,以及跨多个数据中心的资源利用率最大化。2015年4月,Borg论文《Large-scale cluster management at Google with Borg》伴随Kubernetes的高调宣传被Google首次公开,人们终于有缘得窥其全貌。
图1-3 Kubernetes Logo
事实上,正是由于诞生于容器世家Google,并站在Borg这个巨人的肩膀之上,充分受益于Borg过去十数年间积累的经验和教训,Kubernetes甫一面世就立即广受关注和青睐,并迅速称霸了容器编排技术领域。很多人将Kubernetes视为Borg系统的一个开源实现版本,在Google内部,Kubernetes的原始代号曾经是Serven of Nine,即星际迷航中友好的“Borg”角色,它标识中的舵轮有七个轮辐就是对该项目代号的致意,如图1-3所示。
Kubernetes v1.0于2015年7月21日发布,紧随其后,Google与Linux基金会合作组建了Cloud Native Computing Foundation(云原生计算基金会,简称为CNCF),并将Kubernetes作为种子技术予以提供。这之后,Kubernetes进入了版本快速迭代期,从此不断地融入着新功能,如Federation、Network Policy API、RBAC、CRD和CSI,等等,并增加了对Windows系统的支持。
2017年可谓是容器生态发展史上具有里程碑意义的一年。这一年,AWS、Azure和Alibaba Cloud都相继在其原有容器服务上新增了对Kubernetes的支持,而Docker官方也在2017年10月宣布同时支持Swarm和Kubernetes编排系统。这一年,RKT容器派系的CoreOS舍弃掉自己的调度工具Fleet,将其商用平台Tectonic的重心转移至Kubernetes。这一年,Mesos也于9月宣布了对Kubernetes的支持,其平台用户可以安装、扩展和升级多个生产级的Kubernetes集群。这一年,Rancher Labs推出了其2.0版本的容器管理平台并宣布all-in Kubernetes,放弃了其内置多年的容器编排系统Cattle。类似的故事依然在进行,并且必将在一个时期内持续上演。
1.2.2 Kubernetes特性
Kubernetes是一种用于在一组主机上运行和协同容器化应用程序的系统,旨在提供可预测性、可扩展性与高可用性的方法来完全管理容器化应用程序和服务的生命周期的平台。用户可以定义应用程序的运行方式,以及与其他应用程序或外部世界交互的途径,并能实现服务的扩容和缩容,执行平滑滚动更新,以及在不同版本的应用程序之间调度流量以测试功能或回滚有问题的部署。Kubernetes提供了接口和可组合的平台原语,使得用户能够以高度的灵活性和可靠性定义及管理应用程序。简单总结起来,它具有以下几个重要特性。
(1)自动装箱
建构于容器之上,基于资源依赖及其他约束自动完成容器部署且不影响其可用性,并通过调度机制混合关键型应用和非关键型应用的工作负载于同一节点以提升资源利用率。
(2)自我修复(自愈)
支持容器故障后自动重启、节点故障后重新调度容器,以及其他可用节点、健康状态检查失败后关闭容器并重新创建等自我修复机制。
(3)水平扩展
支持通过简单命令或UI手动水平扩展,以及基于CPU等资源负载率的自动水平扩展机制。
(4)服务发现和负载均衡
Kubernetes通过其附加组件之一的KubeDNS(或CoreDNS)为系统内置了服务发现功能,它会为每个Service配置DNS名称,并允许集群内的客户端直接使用此名称发出访问请求,而Service则通过iptables或ipvs内建了负载均衡机制。
(5)自动发布和回滚
Kubernetes支持“灰度”更新应用程序或其配置信息,它会监控更新过程中应用程序的健康状态,以确保它不会在同一时刻杀掉所有实例,而此过程中一旦有故障发生,就会立即自动执行回滚操作。
(6)密钥和配置管理
Kubernetes的ConfigMap实现了配置数据与Docker镜像解耦,需要时,仅对配置做出变更而无须重新构建Docker镜像,这为应用开发部署带来了很大的灵活性。此外,对于应用所依赖的一些敏感数据,如用户名和密码、令牌、密钥等信息,Kubernetes专门提供了Secret对象为其解耦,既便利了应用的快速开发和交付,又提供了一定程度上的安全保障。
(7)存储编排
Kubernetes支持Pod对象按需自动挂载不同类型的存储系统,这包括节点本地存储、公有云服务商的云存储(如AWS和GCP等),以及网络存储系统(例如,NFS、iSCSI、GlusterFS、Ceph、Cinder和Flocker等)。
(8)批量处理执行
除了服务型应用,Kubernetes还支持批处理作业及CI(持续集成),如果需要,一样可以实现容器故障后恢复。
1.2.3 Kubernetes概念和术语
Kubernetes使用共享网络将多个物理机或虚拟机汇集到一个集群中,在各服务器之间进行通信,该集群是配置Kubernetes的所有组件、功能和工作负载的物理平台。集群中一台服务器(或高可用部署中的一组服务器)用作Master,负责管理整个集群,余下的其他机器用作Worker Node(早期版本中也称为Minion),它们是使用本地和外部资源接收和运行工作负载的服务器,如图1-4所示。集群中的这些主机可以是物理服务器,也可以是虚拟机(包括IaaS云端的VPS)。
图1-4 Kubernetes集群主机
(1)Master
Master是集群的网关和中枢,负责诸如为用户和客户端暴露API、跟踪其他服务器的健康状态、以最优方式调度工作负载,以及编排其他组件之间的通信等任务,它是用户或客户端与集群之间的核心联络点,并负责Kubernetes系统的大多数集中式管控逻辑。单个Master节点即可完成其所有的功能,但出于冗余及负载均衡等目的,生产环境中通常需要协同部署多个此类主机。Master节点类似于蜂群中的蜂王。
(2)Node
Node是Kubernetes集群的工作节点,负责接收来自Master的工作指令并根据指令相应地创建或销毁Pod对象,以及调整网络规则以合理地路由和转发流量等。理论上讲,Node可以是任何形式的计算设备,不过Master会统一将其抽象为Node对象进行管理。Node类似于蜂群中的工蜂,生产环境中,它们通常数量众多。
Kubernetes将所有Node的资源集结于一处形成一台更加强大的“服务器”,如图1-5所示,在用户将应用部署于其上时,Master会使用调度算法将其自动指派至某个特定的Node运行。在Node加入集群或从集群中移除时,Master也会按需重新编排影响到的Pod(容器)。于是,用户无须关心其应用究竟运行于何处。
图1-5 Node组成的虚拟资源池
从抽象的视角来讲,Kubernetes还有着众多的组件来支撑其内部的业务逻辑,包括运行应用、应用编排、服务暴露、应用恢复等,它们在Kubernetes中被抽象为Pod、Service、Controller等资源类型,下面列出了几个较为常用的资源抽象。
(1)Pod
Kubernetes并不直接运行容器,而是使用一个抽象的资源对象来封装一个或者多个容器,这个抽象即为Pod,它也是Kubernetes的最小调度单元。同一Pod中的容器共享网络名称空间和存储资源,这些容器可经由本地回环节口lo直接通信,但彼此之间又在Mount、User及PID等名称空间上保持了隔离。尽管Pod中可以包含多个容器,但是作为最小调度单元,它应该尽可能地保持“小”,即通常只应该包含一个主容器,以及必要的辅助型容器(sidecar),如图1-6所示。
图1-6 Kubernetes Pod示意图
(2)资源标签
标签(Label)是将资源进行分类的标识符,资源标签其实就是一个键值型(key/values)数据。标签旨在指定对象(如Pod等)辨识性的属性,这些属性仅对用户存在特定的意义,对Kubernetes集群来说并不直接表达核心系统语义。标签可以在对象创建时附加其上,并能够在创建后的任意时间进行添加和修改。一个对象可以拥有多个标签,一个标签也可以附加于多个对象(通常是同一类对象)之上,如图1-7所示。
图1-7 Kubernetes资源标签
(3)标签选择器
标签选择器(Selector)全称为“Label Selector”,它是一种根据Label来过滤符合条件的资源对象的机制。例如,将附有标签“role: backend”的所有Pod对象挑选出来归为一组就是标签选择器的一种应用,如图1-8所示。用户通常使用标签对资源对象进行分类,而后使用标签选择器挑选出它们,例如将其创建为某Service的端点。
图1-8 标签选择器
(4)Pod控制器
尽管Pod是Kubernetes的最小调度单元,但用户通常并不会直接部署及管理Pod对象,而是要借助于另一类抽象——控制器(Controller)对其进行管理。用于工作负载的控制器是一种管理Pod生命周期的资源抽象,它们是Kubernetes上的一类对象,而非单个资源对象,包括ReplicationController、ReplicaSet、Deployment、StatefulSet、Job等。以图1-9中所示的Deployment控制器为例,它负责确保指定的Pod对象的副本数量精确符合定义,否则“多退少补”。使用控制器之后就不再需要手动管理Pod对象了,用户只需要声明应用的期望状态,控制器就会自动对其进行进程管理。
图1-9 Deployment控制器示意图
(5)服务资源(Service)
Service是建立在一组Pod对象之上的资源抽象,它通过标签选择器选定一组Pod对象,并为这组Pod对象定义一个统一的固定访问入口(通常是一个IP地址),若Kubernetes集群存在DNS附件,它就会在Service创建时为其自动配置一个DNS名称以便客户端进行服务发现。到达Service IP的请求将被负载均衡至其后的端点——各个Pod对象之上,因此Service从本质上来讲是一个四层代理服务。另外,Service还可以将集群外部流量引入到集群中来。
(6)存储卷
存储卷(Volume)是独立于容器文件系统之外的存储空间,常用于扩展容器的存储空间并为它提供持久存储能力。Kubernetes集群上的存储卷大体可分为临时卷、本地卷和网络卷。临时卷和本地卷都位于Node本地,一旦Pod被调度至其他Node,此种类型的存储卷将无法访问到,因此临时卷和本地卷通常用于数据缓存,持久化的数据则需要放置于持久卷(persistent volume)之上。
(7)Name和Namespace
名称(Name)是Kubernetes集群中资源对象的标识符,它们的作用域通常是名称空间(Namespace),因此名称空间是名称的额外的限定机制。在同一个名称空间中,同一类型资源对象的名称必须具有唯一性。名称空间通常用于实现租户或项目的资源隔离,从而形成逻辑分组,如图1-10所示。创建的Pod和Service等资源对象都属于名称空间级别,未指定时,它们都属于默认的名称空间“default”。
图1-10 名称空间
(8)Annotation
Annotation(注解)是另一种附加在对象之上的键值类型的数据,但它拥有更大的数据容量。Annotation常用于将各种非标识型元数据(metadata)附加到对象上,但它不能用于标识和选择对象,通常也不会被Kubernetes直接使用,其主要目的是方便工具或用户的阅读及查找等。
(9)Ingress
Kubernetes将Pod对象和外部网络环境进行了隔离,Pod和Service等对象间的通信都使用其内部专用地址进行,如若需要开放某些Pod对象提供给外部用户访问,则需要为其请求流量打开一个通往Kubernetes集群内部的通道,除了Service之外,Ingress也是这类通道的实现方式之一。