条分缕析带你充分理解Kubernetes的各个细节与部分:它是什么,它如何解决容器编排问题,它包含哪些你必须掌握的关键对象,以及如何快速上手部署使用Kubernetes。
容器的好处不胜枚举:一致的运行时环境、节省磁盘空间、低开销、良好的隔离性,等等。了解完这些优势,您以及您的同事可能都开始跃跃欲试要把应用程序打包到容器中并准备运行它。然后突然之间或许您会发现,容器运行起来之后有一些问题也接踵而来,您需要一种方法来管理所有正在运行的容器及其生命周期:它们如何相互连接,它们应该运行在什么硬件之上,它们如何获取数据存储,容器因各种原因停止运行的话您该如何处理错误······
这就是Kubernetes大显身手的地方了。
在本文中,我们将了解Kubernetes是什么,它如何解决容器编排问题,它背后是由哪些理论支撑,如何将该理论直接与实际操作绑定,最终帮助您充分理解Kubernetes的各个细节与部分。
Kubernetes: 历史
Kubernetes,也被称为k8s(k... 8个字母...和s)或kube,是希腊语中的单词,意为州长、舵手或船长。拿真正的航海的情景来理解,大型船舶装载着大量现实生活的容器,而船长或舵手则是负责船舶的人。因此,在信息技术的语境下,Kubernetes就是Docker容器的船长、编排者。
Kubernetes最初是谷歌公司在内部使用的,基于谷歌运行容器15年的经验,Kubernetes于2014年开始作为Google的开源项目提供给社区。四年过去,Kubernetes飞速发展,下载及使用量惊人,被大量的中小型企业用户用于开发或生产环境,并已成为业界公认的容器编排管理的标准框架。
Kubernetes的发展势头
Kubernetes的增长态势惊人,在GitHub上拥有超过40,000颗星,在2018年拥有超过60,000个commit,并且比GitHub上的任何其他项目都有更多的pull request和issue。其增长背后的部分原因是其不凡的可扩展性和强大的设计模式,这些我们将在后文中进一步解读。您可以在此链接了解一些大型软件公司的Kubernetes应用案例:
https://kubernetes.io/case-st...
Kubernetes提供的服务
让我们来看看是什么功能及特性让Kubernetes吸引到业界的如此关注。
Kubernetes的核心是以容器为中心的管理环境。它代表用户的工作负载来编排计算、网络和存储基础架构。这提供了平台即服务(PaaS)的简单性和基础架构即服务(IaaS)的灵活性,并实现了跨基础架构提供商的可移植性。Kubernetes不仅仅是一个编排系统。实际上,它让用户不再需要“编排”。“编排”的技术定义是“执行定义的工作流程”:首先执行A,然后运行B,然后运行C。而有了Kubernetes之后,Kubernetes由一组独立的、可组合的控制流程组成,这些流程可将当前状态持续推向所需状态。而你是如何从A进行到C的,在此无关紧要。而且,用户也不再需要集中控制,整个系统也变得更易于使用、功能更强大、可扩展性更佳。
Kubernetes的基本概念
要使用Kubernetes,您可以使用Kubernetes API对象来描述集群的所需状态:您想要运行的应用程序或服务,它们使用的容器镜像、副本数量,您希望提供的网络和磁盘资源等等。您可以通过使用Kubernetes API——kubectl(通常通过命令行界面)创建对象来设置所需的状态。您还可以直接使用Kubernetes API与集群交互,并设置或修改所需的状态。
设置完所需状态后,Kubernetes控制面板会让集群的当前状态与所需状态相匹配。为此,Kubernetes会自动执行各种任务,例如启动或重新启动容器、扩展给定应用程序的副本数量等等。
基本的Kubernetes对象包括: - 节点 - Pod - 服务 - 卷 - 命名空间
此外,Kubernetes包含许多称为controller的高级抽象。controller基于基本对象构建,并提供其他功能和便利的特性。它们包括:
- ReplicaSet
- Deployment
- StatefulSet
- DaemonSet
- Job
下文中我们会逐个介绍这些概念,然后再尝试一些动手练习。
节 点
节点( Node)是Kubernetes中的worker machine,以前称为minion。节点可以是虚拟机(VM)或物理机(具体取决于集群)。每个节点都包含运行pod所需的服务,并由主组件管理。你可以这样理解节点:节点对于pod就像是Hypervisor对于虚拟机。
Pod
Pod是Kubernetes的基本构建块,它是您创建或部署的Kubernetes对象模型中最小和最简单的单元。一个Pod代表着一个部署单元:Kubernetes中的单个应用程序实例,可能包含单个容器或少量紧密组合并共享资源的容器。
Docker是Kubernetes Pod中最常用的容器运行时,但Pods也支持其他容器运行时。
Kubernetes集群中的Pod主要以两种方式使用:第一种是运行单个容器的Pod 。“one-container-per-Pod”模式是最常见的Kubernetes用例; 在这种情况下,您可以将Pod视为单个容器的打包,由Kubernetes而非容器来管理 Pods。第二种是运行多个需要协同工作的容器的Pod。一个Pod可能包含了一个应用程序,这个应用程序是由多个紧密耦合并且需要共享资源的容器组成的。这些共存的容器可能形成一个单一的内聚服务单元——一个容器负责从共享卷将文件公开,而另一个单独的“sidecar”容器负责刷新或更新这些文件。该Pod 将这些容器和存储资源一起封装为一个可管理的实体。
Pod为其组成容器提供两种共享资源:网络和存储。
网络:每个Pod都分配了一个唯一的IP地址。一个Pod中的所有容器都共享网络命名空间,包括IP地址和网络端口。Pod内的容器可以使用localhost相互通信。当Pod内的容器与Pod外的实体通信时,它们必须协调如何使用共享网络资源(例如端口)。
存储:Pod可以指定一组共享存储卷。Pod中的所有容器都可以访问共享卷,允许这些容器共享数据。如果需要重新启动其中一个容器,卷还可以让Pod中的持久数据一直保存着。
服 务
Kubernetes Pods不是不变的,它们被创建又被杀死后并不会重生。即使每个Pod都有自己的IP地址,你也不能完全指望它会随着时间推移却永不改变。这会产生一个问题,如果一组Pods(比如说后端)为Kubernetes集群中的另一组Pods(比如说前端)提供了功能,那些前端pod如何能够与后端pod保持可靠的通信?
这就是服务发挥作用的地方。
Kubernetes服务定义了一个逻辑集Pods和访问它们的策略(有时称为微服务),通常由Label Selector确定。
例如,如果你有一个带有3个Pod的后端应用程序,那些pod是可替代的,前端并不关心它们使用哪个后端。虽然Pods组成后端集的实际情况可能会发生变化,但前端客户端不应该知道这一点,也不需要跟踪后端列表本身。该Service抽象可实现这种分离。
对那些处于同样的Kubernetes集群中的应用,Kubernetes提供了一个简单的Endpoints API,每当服务中的一套Pods改变时,API就会相应地更新。对于集群外的应用程序,Kubernetes提供基于虚拟IP的桥接器,Services可将其重定向到后端Pods。
卷
容器中的磁盘文件是不是永久的,这会给运行在容器中的应用程序带来一些问题。首先,当容器崩溃时,它将由Kubernetes重新启动,但文件会丢失,因为容器总是以干净状态启动的。其次,当在一个pod中运行多个容器时,通常需要在这些容器之间共享文件。Kubernetes Volume就是来解决这两个问题的。
从本质上讲,卷只是一个目录,可能包含一些数据,在Pod中,它可以访问容器。该目录是如何形成的、支持它的介质是什么以及它的内容,是由所使用的特定卷类型决定的。
Kubernetes卷具有明确的生命周期,与创建它的Pod的生命周期相同。总而言之,一个卷超过了在Pod中运行的任何容器,并且在容器重启时保留了数据。通常,当一个Pod不再存在时,卷也将不复存在。Kubernetes支持多种类型的卷,并且Pod可以同时使用任意数量的卷。
命名空间
Kubernetes支持由同一物理集群支持的多个虚拟集群。这些虚拟集群称为命名空间。
命名空间提供了名称范围。在一个命名空间内,每个资源名称都需要是唯一的,不过跨命名空间时就没有这种要求了。
没有必要只是为了分离略有不同的资源而使用多个命名空间,比如说同一软件的不同版本:可以用标签来区分同一命名空间内的不同资源。
ReplicaSet
ReplicaSet确保一次运行指定数量的pod副本。换句话说,ReplicaSet确保pod或同类pod组始终可用。但是,Deployment是一个更高级别的概念,它可以管理ReplicaSets,并为Pods提供声明性更新以及许多其他有用的功能。因此,除非您需要自定义更新编排或根本不需要更新,否则我建议您使用Deployments而不是直接使用ReplicaSets。
这实际上意味着您可能永远不需要直接操纵ReplicaSet对象,而是可以使用Deployment作为替代。
Deployment
Deployment controller为Pods和ReplicaSets提供声明性更新。
您在Deployment对象中描述了所需状态,Deployment controller就将以受控速率将现阶段实际状态更改为所需状态。您可以定义Deployments来创建新的ReplicaSets,或删除现有的Deployments并使用新的Deployments来使用所有资源。
StatefulSets
StatefulSet用于管理有状态应用程序,它管理一组Pods的部署和扩展,并提供有关这些Pod 的排序和唯一性的保证。
StatefulSet的运行模式和controller相同。您可以在StatefulSet对象中定义所需的状态,StatefulSet controller就会进行各种必要的更新以从当前状态到达更新为所需状态。和Deployment类似,StatefulSet管理那些基于相同容器规范的Pods。与Deployment不同的是,StatefulSet为每个Pods保留一个粘性身份。这些Pods是根据相同的规范创建的,但不可互换:每个都有一个永久的标识符,不论如何重新调度,这个标识都保持不变。
DaemonSet
DaemonSet确保所有(或某些)节点运行Pod的副本。随着节点添加到群集中,Pod会随之添加。当将节点从集群中删除后,Pods就成为了垃圾。此时,删除一个DaemonSet就将清理它所创建的Pods。
DaemonSet的一些典型用途有:
- 在每个节点上运行集群存储daemon,例如glusterd、ceph。
- 在每个节点上运行日志收集daemon,例如fluentd或logstash。
- 在每个节点上运行节点监控daemon,例如Prometheus Node Exporter或collectd。
Job
job创建一个或多个pod,并确保在需要的时候成功终止指定数量的pod。Pods成功完成后,job会追踪顺利完成的情况。当达到指定数量时,job本身的任务就完成了。删除Job将清除它所创建的Pods。
一个简单的例子是创建一个Job对象,以便可靠地运行一个对象Pod。如果第一个Pod失败或被删除(例如由于节点硬件故障或节点重启),那么该Job对象将启动一个新Pod。
实际操作中的挑战
现在您已经了解了Kubernetes中的关键对象及概念了,很明显,想要玩转Kubernetes需要了解大量的信息。当你尝试使用Kubernetes时,可能会遇到如下挑战:
- 如何在不同的基础架构中一致地部署?
- 如何跨多个集群(和名称空间)实现和管理访问控制?
- 如何与中央身份验证系统集成?
- 如何分区集群以更有效地使用资源?
- 如何管理多租户、多个专用和共享集群?
- 如何创建高可用集群?
- 如何跨集群/命名空间实施安全策略?
- 如何良好地进行监控,以确保有足够的可见性来检测和解决问题?
- 如何跟上Kubernetes快速发展的步伐?
这就是Rancher可以帮助您的地方。Rancher是一个100%开源的容器管理平台,用于在生产中运行Kubernetes。通过Rancher,你可以:
- 拥有易于使用的kubernetes配置和部署界面;
- 跨多个集群和云的基础架构管理;
- 自动部署最新的kubernetes版本;
- 工作负载、RBAC、政策和项目管理;
- 24x7企业级支持。
Rancher可以成为一个单一控制点,而您可以在多种、多个基础架构上运行多个Kubernetes集群:
上手Rancher和Kubernetes
现在让我们看看如何在Rancher的帮助下轻松使用前文描述的Kubernetes对象。首先,您需要一个Rancher实例。按照本指南,在几分钟之内即可启动一个Rancher实例并使用它创建一个Kubernetes集群:
https://rancher.com/docs/ranc...
启动集群后,您应该在Rancher中看到Kubernetes集群的资源:
要从第一个Kubernetes对象——节点开始,请单击顶部菜单上的Nodes。你应该可以组成了你的Kubernetes集群的Nodes的整体情况:
在那里,您还可以看到已从Kubernetes集群部署到每个节点的pod的数量。这些pod由Kubernetes和Rancher内部系统使用。通常情况下你不需要处理那些。
下面让我们继续Pod的例子。要做到这一点,转到Kubernetes集群的Default项目,然后进入Workloads选项卡。下面让我们部署一个工作负载。点击Deploy并将Name和Docker image设置为nginx,剩下的一切都使用默认值,然后点击Launch。
创建后,Workloads选项卡会显示nginx工作负载。
如果单击nginx工作负载,您将会看到Rancher实际创建了一个Deployment,就像Kubernetes推荐的那样用来管理ReplicaSet,您还将看到该ReplicaSet创建的Pod:
现在你有一个Deployment,它将确保我们所需的状态在集群中正确显示。现在,点击Scale附近+号,将此Workload扩容到3。一旦你这样做,你应该能立即看到另外2个Pods被创建出来,另外还多了2个ReplicaSet来缩放事件。使用Pod右侧菜单,尝试删除其中一个pod,并注意ReplicaSet是如何重新创建它以匹配所需状态的。
现在,您的应用程序已启动并运行,并且已经扩展到3个实例。下一个问题是,您如何访问它?在这里,我们将尝试使用下一个Kubernetes对象——服务。为了暴露我们的nginx工作负载,我们需要先编辑它,从Workload右侧菜单中选择Edit。您将看到Deploy Workload页面,且已填好了您的nginx工作负载的详细信息:
请注意,现在您有3个pod在Scalable Deployment旁边,但是当您启动时,默认值为1。这是因为你的扩展工作刚完成不久。
现在单击Add Port,并按如下所示填充值:
将Publish the container port值设置为80;
Protocol仍为TCP;
将As a值设置为Layer-4 Load Balancer;
将On listening port值设置为80。
然后自信地点击Upgrade吧!这将在您的云提供商中创建一个外部负载均衡器,并将流量引至您的Kubernetes集群内的nginx Pods中。要对此进行测试,请再次访问nginx工作负载概述页面,现在您应该看到Endpoints旁的80/tcp链接:
如果点击80/tcp,它会导向您刚刚创建的负载均衡器的外部IP,并且向您展示一个默认的nginx页面,确认一切都按预期正常工作。
至此,你已经搞定了上半篇文章中介绍的大多数Kubernetes对象。你可以在Rancher中好好玩玩卷和命名空间,相信您一定能很快掌握如何通过Rancher更简单快捷地使用它们。至于StatefulSet、DaemonSet和Job,它们和Deployments非常类似,你同样可以在Workloads选项卡中通过选择Workload type来创建它们。
结 语
让我们回顾一下你在上面的动手练习中所做的一切。你已经创建了我们描述的大多数Kubernetes对象:
1、最开始,你在Rancher中创建了kubernetes集群;
2、然后你浏览了集群的Nodes;
3、你创造了一个Workload;
4、你已经看到了一个Workload实际上创建了3个独立的Kubernetes对象:一个Deployment管理着 ReplicaSet,同时按需保持着所需数量的Pods正常运行;
5、在那之后你扩展了你的Deployment数量,并观察它是如何改变了ReplicaSet并相应地扩展Pods的数量的;
6、最后你创建了一个Load Balancer类型的Service类型,用于平衡Pods之间的客户端请求。
所有这些都可以通过Rancher轻松完成,您只需进行一些点击的操作,无需在本地安装任何软件来复制身份验证配置或在终端中运行命令行。您只需一个浏览器,玩转Kubernetes唾手可得。