K8s in Action 阅读笔记——【1】Introducing Kubernetes
多年前,大多数软件应用程序都是庞大的单体应用,运行在单个进程或少量进程分布在几台服务器上。这些传统系统今天仍然广泛存在。它们具有缓慢的发布周期,更新相对不频繁。在每个发布周期结束时,开发人员将整个系统打包交给运营团队,然后进行部署和监控。在硬件故障的情况下,运营团队手动将其迁移到其余健康的服务器上。
如今,这些庞大的单体传统应用正在逐渐被拆分成更小的、独立运行的组件,称为微服务。由于微服务彼此分离,因此它们可以分别进行开发、部署、更新和扩展。这使你可以快速更改组件,并根据需要进行频繁更新,以跟上当今快速变化的业务需求。
但是,随着可部署组件数量的增加和数据中心规模的扩大,配置、管理和保持整个系统运行平稳变得越来越困难。要弄清楚在哪里放置每个组件以实现高资源利用率,从而降低硬件成本,这变得更加困难。手动完成所有这些工作是一项艰巨的任务。我们需要自动化,包括将这些组件自动调度到我们的服务器上、自动配置、监管和处理故障。这就是Kubernetes的用武之地。
Kubernetes使开发人员能够自己部署应用程序,而且可以随时进行部署,无需运营(ops)团队的任何帮助。但是Kubernetes不仅有利于开发人员,它还通过在硬件故障时自动监控和重新调度这些应用程序来帮助运营团队。系统管理员(sysadmins)的重点从监督单个应用程序转移到大部分监督和管理Kubernetes和其他基础设施,而Kubernetes本身则负责管理应用程序。
Kubernetes是希腊语,意思是驾驶员或舵手(掌舵人),简称k8s。
读音:
[kubə’netis]
Kubernetes抽象出硬件基础设施,并将整个数据中心呈现为单个巨大的计算资源。它允许你在不需要了解底层实际服务器的情况下部署和运行软件组件。在通过Kubernetes部署多组件应用程序时,它会为每个组件选择一个服务器,部署它,并使其能够轻松地找到和与你的应用程序的所有其他组件通信。
这使得Kubernetes非常适用于大多数本地数据中心,但它真正发挥作用的地方是在使用最大的数据中心,例如云提供商建立和运营的数据中心。Kubernetes允许它们为开发人员提供一个简单的平台,以部署和运行任何类型的应用程序,同时不需要云提供商自己的系统管理员了解运行在他们硬件上的数以万计的应用程序。
1.1 Understanding the need for a system like Kubernetes
在深入了解Kubernetes之前,让我们快速了解一下近年来应用程序的开发和部署方式发生了怎样的变化。这种变化既是将庞大的单体应用拆分成更小的微服务的结果,也是运行这些应用程序的基础设施发生变化的结果。理解这些变化将有助于你更好地看到使用Kubernetes和Docker等容器技术的好处
1.1.1 Moving from monolithic apps to microservices
monolithic:庞大而单一的
单体应用程序(monolithic apps
)由紧密耦合在一起的组件组成,必须作为一个实体进行开发、部署和管理,因为它们都运行在单个操作系统进程中。对应用程序的某个部分进行更改需要重新部署整个应用程序,随着时间的推移,部分之间缺少硬边界会导致复杂性增加,并因这些部分之间相互依赖关系不受限制的增长而导致整个系统质量的下降。
运行单体应用程序通常需要少量强大的服务器,可以提供足够的资源来运行应用程序。为了处理系统上的负载增加,你可以通过垂直扩展(``vertically scale)服务器(也称为
scaling up)**添加更多的CPU、内存和其他服务器组件来扩展整个系统,或者通过设置附加服务器并运行应用程序的多个副本(或
replicas`)来水平扩展**整个系统(称为向外扩展)。
虽然向上扩展通常不需要对应用程序进行任何更改,但它在硬件方面的成本相对较高,实际上总有上限。另一方面,向外扩展在硬件方面相对便宜,但可能需要应用程序代码的重大更改,并且并不总是可能的。应用程序的某些部分极其难以或几乎不可能进行水平扩展(例如关系型数据库)。如果单体应用程序的任何部分不可扩展,则整个应用程序将变得不可扩展,除非你可以以某种方式拆分单体应用程序。
SPLITTING APPS INTO MICROSERVICES
这些问题和其他问题迫使我们开始将复杂的单体应用程序拆分为更小的独立可部署组件,称为微服务。每个微服务作为独立进程运行(参见图1.1),并通过简单、明确定义的接口(API)与其他微服务通信。
微服务通过同步协议(例如HTTP)进行通信,通常公开RESTful(REpresentational State Transfer)API,或通过异步协议(例如AMQP)进行通信。这些协议简单易懂,大多数开发人员都能理解,而且不与任何特定的编程语言绑定。每个微服务都可以用最适合实现该特定微服务的语言编写。
由于每个微服务都是一个独立的进程,具有相对静态的外部API,因此可以单独开发和部署每个微服务。对其中一个微服务的更改不需要更改或重新部署任何其他服务,只要API不会改变或以向后兼容的方式改变即可。
SCALING MICROSERVICES
与单体系统需要整体扩展系统不同,微服务的扩展是基于每个服务的基础进行的,这意味着你可以选择仅扩展需要更多资源的服务,同时保留其他服务的原始规模。图1.2显示了一个例子。某些组件被复制并作为部署在不同服务器上的多个进程运行,而其他组件则作为单个应用程序进程运行。当单体应用程序由于其中一个部分不可扩展而无法进行水平扩展时,将应用程序拆分为微服务允许你在允许水平扩展的部分水平扩展,并将不支持水平扩展的部分垂直扩展。
DEPLOYING MICROSERVICES
微服务也有缺点。当系统仅由少量可部署组件组成时,管理这些组件很容易。决定每个组件在哪里部署是微不足道的,因为选择不是那么多。但是,当这些组件的数量增加时,与部署相关的决策变得越来越困难,因为不仅部署组合的数量增加,而且组件之间的相互依赖关系也以更大的因素增加。
微服务作为一个团队共同执行工作,因此它们需要找到彼此并进行通信。在部署它们时,需要有人或某种工具来正确配置它们,以便使它们作为一个单一系统协同工作。随着微服务数量的增加,这变得繁琐且容易出错,特别是当你考虑到当服务器故障时,运维/系统管理员团队需要做什么
微服务还带来了其他问题,例如由于它们跨越多个进程和计算机,因此很难调试和跟踪执行调用。幸运的是,现在可以使用分布式跟踪系统(例如Zipkin)来解决这些问题。
UNDERSTANDING THE DIVERGENCE OF ENVIRONMENT REQUIREMENTS
微服务架构中的组件是独立部署并以此方式开发的。每个组件有独立的团队开发,没有阻碍这些团队在需要时使用不同的库并替换它们。因此,应用程序组件之间的依赖关系的分歧是不可避免的,例如图1.3所示的应用程序需要不同版本的相同库。这可能会导致在部署和管理生产服务器上的应用时出现问题。
在生产服务器上部署动态链接的应用程序,这些应用程序需要不同版本的共享库和/或需要其他环境特定的要求,对于部署和管理它们的运维团队来说很快就会成为一场噩梦。需要在同一主机上部署的组件数量越多,就越难管理所有它们的依赖关系以满足它们的所有要求。
1.1.2 Providing a consistent environment to applications
开发人员和运维团队必须处理应用程序在不同环境下运行所带来的问题,无论部署多少个独立组件。这些环境差异可以涵盖硬件、操作系统和可用库等方面。生产环境通常由运维团队管理,而开发人员则自行管理其开发环境。这两个团队的系统管理知识不同,因此两个系统之间可能存在较大的差异。
此外,生产系统可能运行多个开发人员或团队的应用程序,这可能不适用于开发人员的计算机。为了减少生产环境中出现的问题数量,最好的解决方案是应用程序在开发和生产期间运行在完全相同的环境中,而且这个环境最好不要随时间而改变。此外,最好能够在同一服务器上添加应用程序,而不会影响现有应用程序。
1.1.3 Moving to continuous delivery: DevOps and NoOps
近年来,整个应用程序开发过程以及在生产环境中应用程序的管理方式发生了转变。在过去,开发团队的工作是创建应用程序并将其交给运维团队,然后由运维团队部署、维护和保持其运行。但现在,组织机构意识到最好由开发应用程序的同一团队也参与部署并在其整个生命周期中进行维护。这意味着开发人员、QA(质量保证团队)和运维团队现在需要在整个过程中进行协作。这种做法被称为DevOps。
UNDERSTANDING THE BENEFITS
让开发人员更多的参与应用程序在生产环境中的运行,可以使他们更好地了解用户需求和问题,以及运维团队在维护应用程序时面临的问题。现在,应用程序开发人员更倾向于更早地向用户提供应用程序,并利用他们的反馈来引导应用程序的进一步开发。
为了更频繁地发布应用程序的新版本,需要简化部署流程。理想情况下,你希望开发人员自己部署应用程序,而无需等待运维人员。但是,部署应用程序通常需要了解基础架构和数据中心硬件的组织。开发人员并不总是了解这些细节,而且大多数情况下甚至不想了解。
LETTING DEVELOPERS AND SYSADMINS DO WHAT THEY DO BEST
开发人员和系统管理员有不同的职责和关注点。开发人员喜欢创建新功能和改善用户体验,而系统管理员负责保持生产环境运行和维护硬件基础设施。为了让开发人员能够快速部署应用程序并让系统管理员专注于维护基础设施,Kubernetes提供了一种解决方案。
Kubernetes可以将硬件基础设施抽象化,并将其作为一个平台公开,使开发人员可以轻松地部署和运行应用程序,而系统管理员可以专注于保持基础设施运行,无需了解实际运行的应用程序的细节。这种解决方案被称为NoOps。
1.2 Introducing container technologies
Kubernetes使用Linux容器技术来隔离运行的应用程序,因此在深入研究Kubernetes之前,你需要熟悉容器的基础知识,以了解Kubernetes自身的功能以及它将一些功能外置到像Docker或rkt(发音为“rock-it”)这样的容器技术中。
1.2.1 Understanding what containers are
如果应用程序由许多小组件组成,为每个组件提供独立的虚拟机会浪费硬件资源并增加管理成本。因此,需要寻找一种更高效的方式来管理它们的环境,以减少对硬件和人力资源的浪费。
ISOLATING COMPONENTS WITH LINUX CONTAINER TECHNOLOGIES
开发人员不再使用虚拟机来隔离每个微服务(或一般的软件进程)的环境,而是转向使用Linux容器技术。它们允许你在同一主机上运行多个服务,同时为每个服务提供不同的环境,并像虚拟机一样将它们彼此隔离,但开销要小得多。
在容器中运行的进程与其他进程一样,在主机的操作系统中运行(不像虚拟机,其中进程在单独的操作系统中运行)。但是,容器中的进程仍然与其他进程隔离。对于进程本身来说,它看起来像是在机器和其操作系统中唯一运行的进程。
COMPARING VIRTUAL MACHINES TO CONTAINERS
与虚拟机相比,容器更加轻量级,这使得你可以在同一硬件上运行更多的软件组件,主要是因为每个虚拟机需要运行自己的系统进程,这需要额外的计算资源,除了组件自身的进程。另一方面,容器只是在主机操作系统中运行的单个隔离进程,仅消耗应用程序消耗的资源,并且不需要额外进程的开销。
由于虚拟机的开销,你常常将多个应用程序分组到每个虚拟机中,因为没有足够的资源来为每个应用程序分配一个完整的虚拟机。使用容器时,你可以(并且应该)为每个应用程序使用一个容器,如图1.4所示。最终结果是,你可以在同一裸机上安装更多的应用程序。
当你在主机上运行三个虚拟机时,你有三个完全独立的操作系统在共享同一台裸机上运行。在这些虚拟机下面是主机的操作系统和虚拟机监控程序,它将物理硬件资源划分为较小的虚拟资源集,可以被每个虚拟机内部的操作系统使用。在这些虚拟机内运行的应用程序向虚拟机中的客户操作系统内核执行系统调用,然后内核通过虚拟机监控程序在主机的物理CPU上执行x86指令。
存在两种类型的虚拟机监控程序。类型1的虚拟机监控程序不使用主机操作系统,而类型2的虚拟机监控程序则使用主机操作系统
另一方面,容器都在主机操作系统中运行相同的内核上执行系统调用。这个单一内核是唯一在主机CPU上执行x86指令的内核。CPU不需要像虚拟机一样进行任何虚拟化(参见图1.5)。
虚拟机的主要优点是提供完全的隔离性,因为每个虚拟机都运行自己的Linux内核,而容器都调用相同的内核,这可能会带来安全风险。如果你的硬件资源有限,当你只有少量进程需要独立隔离时,虚拟机可能是唯一的选择。为了在同一台机器上运行更多的被隔离进程,容器是更好的选择,因为它们具有低开销。请记住,每个虚拟机运行自己的系统服务,而容器不需要,因为它们都在同一个操作系统中运行。这也意味着,在容器中运行进程时不需要启动任何东西,而在虚拟机中需要。在容器中运行的进程会立即启动。
INTRODUCING THE MECHANISMS THAT MAKE CONTAINER ISOLATION POSSIBLE
容器如何在运行在同一操作系统上时隔离进程?有两个机制使这成为可能。第一个机制是Linux命名空间,它确保每个进程看到自己的系统的个人视图(文件、进程、网络接口、主机名等)。第二个机制是Linux控制组(cgroups),它限制进程可以消耗的资源量(CPU、内存、网络带宽等)。
ISOLATING PROCESSES WITH LINUX NAMESPACES
默认情况下,每个Linux系统最初只有一个命名空间。所有系统资源,例如文件系统、进程ID、用户ID、网络接口等都属于单个命名空间。但是你可以创建额外的命名空间并在它们之间组织资源。运行进程时,将其运行在其中一个命名空间中。该进程只能看到在相同命名空间中的资源。存在多种类型的命名空间,因此一个进程不属于一个命名空间,而是属于每个类型的一个命名空间。以下是存在的一些命名空间类型:
- 挂载点(mnt)
- 进程ID(pid)
- 网络(net)
- 进程间通信(ipc)
- UTS
- 用户ID(user)
每个命名空间类型用于隔离一组特定的资源。例如,UTS命名空间确定运行在该命名空间内的进程所看到的主机名和域名。通过为一对进程分配两个不同的UTS命名空间,你可以使它们看到不同的本地主机名。换句话说,对于这两个进程,它们会看起来像是在两台不同的机器上运行(至少就主机名而言)。
同样地,进程所属的网络命名空间决定了运行在该进程内部的应用程序所看到的网络接口。每个网络接口都属于一个命名空间,但可以从一个命名空间移动到另一个命名空间。每个容器使用自己的网络命名空间,因此每个容器看到自己的一组网络接口。
LIMITING RESOURCES AVAILABLE TO A PROCESS
容器隔离的另一半涉及限制容器可以消耗的系统资源数量。这是通过cgroups实现的,cgroups是Linux内核的一个功能,可以限制进程(或一组进程)的资源使用。进程不能使用超过配置的CPU、内存、网络带宽等的数量。这样,进程就不能独占为其他进程保留的资源,这类似于每个进程在单独的机器上运行时的情况。
1.2.2 Introducing the Docker container platform
虽然容器技术已经存在很长时间了,但随着Docker容器平台的崛起,它们变得更加广为人知。Docker是第一个可以在不同机器之间轻松移植容器的容器系统。它简化了打包应用程序以及所有库和其他依赖项(甚至整个操作系统文件系统)的过程,将它们打包成一个简单、可移植的包,可以用来将应用程序交付到运行Docker的任何其他机器上。
当你运行使用Docker打包的应用程序时,它会看到你与之捆绑的精确文件系统内容。无论它是在你的开发机器还是生产机器上运行,它都会看到相同的文件,即使生产服务器运行完全不同的Linux操作系统。应用程序不会看到它正在运行的服务器上的任何内容,因此,如果与你的开发计算机相比,该服务器安装了完全不同的库集合,也没有关系。
例如,如果你将整个Red Hat Enterprise Linux(RHEL)操作系统的文件与应用程序捆绑在一起,那么应用程序将认为它正在RHEL内运行,无论你在运行它的开发计算机上运行的是Fedora还是在运行Debian或其他Linux发行版的服务器上运行。只有内核可能会有所不同。这类似于通过在VM中安装操作系统、在其中安装应用程序,然后分发整个VM镜像并运行它来创建VM镜像。Docker实现了相同的效果,但是它不是使用VM来实现应用程序隔离,而是使用前面提到的Linux容器技术来提供(几乎)与VM相同的隔离水平。它使用容器镜像而不是大型的单块VM镜像,这些容器镜像通常更小。
Docker容器镜像和VM镜像之间的一个重大区别是,容器镜像是由层组成的,这些层可以在多个镜像之间共享和重用。这意味着,如果在运行另一个包含相同层的容器镜像时已经下载了其他层,则只需要下载镜像的某些层。
UNDERSTANDING DOCKER CONCEPTS
Docker是一个平台,用于将应用程序与其环境打包在一起,并将其部署到任何运行Docker的计算机上。这使得应用程序和环境可以在不同的计算机上轻松移植和执行。
在Docker中,这种情况涉及了三个主要概念:
- 镜像(Images):Docker镜像是将应用程序和其环境打包在一起的组件。它包含应用程序可用的文件系统以及其他元数据,例如在运行镜像时应该执行的可执行文件的路径。
- 仓库(Registries):Docker仓库是存储Docker镜像并在不同计算机之间轻松共享这些镜像的库。在构建镜像时,你可以在构建镜像的计算机上运行它,或者你可以将镜像上传到仓库,然后在另一台计算机上拉取并运行它。某些仓库是公共的,允许任何人从中拉取镜像,而其他仓库是私有的,只允许某些人或计算机访问。
- 容器(Containers):Docker容器是从Docker镜像创建的正常的Linux容器。正在运行的容器是在运行Docker的主机上运行的进程,但它与主机和运行在主机上的所有其他进程完全隔离。该进程还受到资源限制,这意味着它只能访问和使用为其分配的资源(CPU、RAM等)的数量。
BUILDING, DISTRIBUTING, AND RUNNING A DOCKER IMAGE
图1.6展示了所有三个概念及其之间的关系。开发人员首先构建一个镜像,然后将其推送到仓库中。镜像因此可供任何可以访问仓库的人使用。他们可以将镜像拉到任何运行Docker的其他计算机上并运行镜像。Docker基于镜像创建一个隔离的容器,并运行镜像中指定的二进制可执行文件。
COMPARING VIRTUAL MACHINES AND DOCKER CONTAINERS
图1.7再次显示了六个应用程序在虚拟机和Docker容器中运行的情况。
注意到,当应用程序A和B在虚拟机中运行时,它们访问相同的二进制文件和库;而当它们作为两个独立的容器运行时也是如此。在虚拟机中,这很明显,因为两个应用程序看到的是相同的文件系统(即虚拟机的文件系统)。但我们说每个容器都有自己隔离的文件系统。那么应用程序A和B如何共享相同的文件呢?
UNDERSTANDING IMAGE LAYERS
如前所述,Docker镜像由多个层组成。不同的镜像可以包含完全相同的层,因为每个Docker镜像都是在另一个镜像之上构建的,而两个不同的镜像都可以使用相同的父镜像作为其基础。这加速了镜像在网络上的分发,因为已经作为第一个镜像的一部分传输的层在传输其他镜像时不需要再次传输。
但是,层不仅使分发更加高效,还有助于减少镜像的存储占用。每个层只存储一次。因此,基于相同基础层创建的两个镜像生成的两个容器可以读取相同的文件,但如果其中一个容器覆盖这些文件,另一个容器不会看到这些更改。因此,即使它们共享文件,它们仍然隔离。这是因为容器镜像层是只读的。当运行容器时,在镜像的层之上创建一个新的可写层。当容器中的进程写入底层层中的文件时,会在最上层创建整个文件的副本,并将进程写入该副本。
UNDERSTANDING THE PORTABILITY LIMITATIONS OF CONTAINER IMAGES
从理论上讲,任何运行Docker的Linux机器都可以运行容器镜像,但存在一个小细节——所有在主机上运行的容器都使用主机的Linux内核。如果容器化的应用程序需要特定的内核版本,则可能无法在每台机器上工作。如果一台机器运行不同版本的Linux内核或没有相同的内核模块可用,则该应用程序无法在该机器上运行。
虚拟机没有这样的限制,因为每个虚拟机都运行自己的内核。并且不仅仅是内核的问题,应该明确的是,为特定硬件架构构建的容器化应用程序只能在具有相同架构的其他机器上运行。你不能将为x86架构构建的应用程序容器化,然后期望它在基于ARM架构的机器上运行。对于这种情况,仍然需要使用虚拟机。
1.2.3 Introducing rkt—an alternative to Docker
Docker是第一个使容器成为主流的容器平台。Docker本身并不提供进程隔离。容器的实际隔离是在Linux内核级别使用Linux Namespaces和cgroups等内核特性完成的。Docker只是使使用这些特性变得容易。
在Docker的成功之后,Open Container Initiative(OCI)应运而生,旨在创建围绕容器格式和运行时的开放行业标准。Docker是该倡议的一部分,rkt(发音为“rock-it”)是另一个Linux容器引擎。
与Docker一样,rkt是一个运行容器的平台。它非常注重安全性、可组合性和符合开放标准。它使用OCI容器镜像格式,甚至可以运行常规的Docker容器镜像。
本书重点介绍如何使用Docker作为Kubernetes的容器运行时,因为最初Kubernetes仅支持Docker。最近,Kubernetes还开始支持rkt等其他容器运行时。
提到rkt的原因是为了不要错误地认为Kubernetes是专门为基于Docker的容器设计的容器编排系统。
1.3 Introducing Kubernetes
随着系统中可部署的应用程序组件数量增加,管理它们变得越来越困难。谷歌是少数几家运行数十万台服务器并必须管理如此大规模部署的公司之一,因此他们开发了解决方案,使成千上万的软件组件的开发和部署可管理和具有成本效益。这促使谷歌开发了Kubernetes,这是一种用于管理容器化应用程序的开源平台,可以自动化部署、扩展和管理应用程序。
1.3.1 Understanding its origins
多年来,谷歌开发了一种名为Borg的内部系统(后来又开发了一种名为Omega的新系统),帮助应用程序开发人员和系统管理员管理这些数千个应用程序和服务。除了简化开发和管理之外,它还帮助他们实现更高的基础设施利用率,这在组织规模如此之大时非常重要。当你运行数十万台机器时,即使是微小的利用率改进都意味着数百万美元的节省,因此开发这样的系统的动机是明确的。在保密了Borg和Omega长达十年之后,谷歌在2014年推出了Kubernetes,这是一种基于Borg、Omega和其他内部谷歌系统经验的开源系统。
1.3.2 Looking at Kubernetes from the top of a mountain
Kubernetes是一种软件系统,可以轻松地在其上部署和管理容器化应用程序。它依赖于Linux容器的特性,可以运行异构应用程序,而无需了解这些应用程序的任何内部细节,并且无需在每个主机上手动部署这些应用程序。由于这些应用程序在容器中运行,它们不会影响运行在同一服务器上的其他应用程序,这在在同一硬件上为完全不同的组织运行应用程序时至关重要。这对于云服务提供商来说非常重要,因为他们力求在保持托管应用程序的完全隔离的同时,实现最佳可能的硬件利用率。
Kubernetes使你能够将软件应用程序在数千个计算机节点上运行,就像这些节点都是一个单独的巨大计算机。它抽象了底层基础架构,并通过这样做简化了开发、部署和管理,适用于开发和运营团队。通过Kubernetes部署应用程序始终相同,无论你的集群只包含几个节点还是数千个节点,集群的大小都没有任何区别。额外的集群节点只是表示可供部署应用程序使用的额外资源数量。
UNDERSTANDING THE CORE OF WHAT K UBERNETES DOES
图1.8展示了Kubernetes系统的最简单的视图。该系统由一个主节点和任意数量的工作节点组成。当开发人员向主节点提交应用程序列表时,Kubernetes将它们部署到工作节点的集群中。组件落在哪个节点上并不重要,无论是对开发人员还是系统管理员来说都应该如此。
开发人员可以指定某些应用程序必须一起运行,Kubernetes会将它们部署在同一个工作节点上。其他应用程序将分布在集群中,但无论它们部署在哪里,它们可以以相同的方式相互通信。
HELPING DEVELOPERS FOCUS ON THE CORE APP FEATURES
可以将Kubernetes视为集群的操作系统。它使应用程序开发人员无需将某些基础设施相关服务实现到其应用程序中,而是依赖于Kubernetes提供这些服务。这包括服务发现、扩展、负载均衡、自我修复,甚至是领导者选举等内容。因此,应用程序开发人员可以专注于实现应用程序的实际功能,而不浪费时间 figuring out如何与基础设施集成。
HELPING OPS TEAMS ACHIEVE BETTER RESOURCE UTILIZATION
Kubernetes将在集群中的某个地方运行容器化应用程序,向其组件提供有关如何找到彼此的信息,并保持其所有组件的运行。由于应用程序不关心它在哪个节点上运行,因此Kubernetes可以随时重新定位应用程序,并通过混合和匹配应用程序来实现比手动调度更好的资源利用率。
1.3.3 Understanding the architecture of a Kubernetes cluster
在硬件层面上,Kubernetes集群由许多节点组成,可以分为两种类型:
- 主节点(master node),它托管Kubernetes控制平面,控制和管理整个Kubernetes系统。
- 工作节点(worker node),它们运行你部署的实际应用程序。
THE CONTROL PLANE
控制平面是控制集群并使其正常运行的部分。它由多个组件组成,可以在单个主节点上运行,也可以分布在多个节点上并进行复制,以确保高可用性。这些组件包括:
- kube-apiserver:提供Kubernetes API的接口,是所有Kubernetes控制面组件的前端。
- etcd:一个高度可靠的键值存储,用于保存Kubernetes集群的所有状态信息。
- kube-scheduler:负责监视新创建的Pod,并选择一个工作节点来运行它们。
- kube-controller-manager:管理集群中的控制器,包括节点控制器、副本控制器、端点控制器和服务帐户和令牌控制器。
- cloud-controller-manager:用于管理集群与云平台的交互,例如云资源的自动伸缩、负载均衡和存储。
THE NODES
工作节点是运行容器化应用程序的机器。运行、监视和为应用程序提供服务的任务由以下组件完成:
- Docker、rkt或其他容器运行时,用于运行你的容器。
- Kubelet,它与API服务器通信并管理其节点上的容器。
- Kubernetes服务代理(kube-proxy),它在应用程序组件之间负载平衡网络流量。
1.3.4 Running an application in Kubernetes
要在Kubernetes中运行应用程序,首先需要将其打包成一个或多个容器映像,将这些映像推送到仓库中,然后向Kubernetes API服务器发布应用程序的描述。
描述包括信息,例如包含应用程序组件的容器映像或映像,这些组件之间的关系以及哪些组件需要共同运行(在同一节点上)以及哪些不需要。对于每个组件,你还可以指定要运行的副本数。此外,描述还将包括哪些组件为内部或外部客户端提供服务,并且应通过单个IP地址公开并使其他组件能够发现。
UNDERSTANDING HOW THE DESCRIPTION RESULTS IN A RUNNING CONTAINER
当API服务器处理你的应用程序描述时,调度程序会根据每个组所需的计算资源和每个节点上未分配的资源,将指定的容器组调度到可用的工作节点上。然后,这些节点上的Kubelet会指示容器运行时(例如Docker)拉取所需的容器映像并运行容器。
请参考图1.10,以更好地了解如何在Kubernetes中部署应用程序。应用程序描述符列出了四个容器,分为三组(这些组称为Pod;我们将在第三章中解释它们)。前两个Pod每个只包含一个容器,而最后一个Pod包含两个容器。这意味着这两个容器需要共同运行,不能相互隔离。在每个Pod旁边,你还可以看到表示需要并行运行每个Pod的副本数的数字。在将描述符提交给Kubernetes后,它将调度每个Pod的指定副本数到可用的工作节点。然后,节点上的Kubelet会告诉Docker从仓库拉取容器映像并运行容器。
KEEPING THE CONTAINERS RUNNING
一旦应用程序正在运行,Kubernetes会持续确保部署的状态始终与你提供的描述相匹配。例如,如果你指定始终希望运行五个Web服务器实例,则Kubernetes将始终保持恰好五个实例运行。如果其中一个实例停止正常工作,例如其进程崩溃或停止响应,Kubernetes将自动重新启动它。
同样,如果整个工作节点死亡或变得不可访问,Kubernetes将为在该节点上运行的所有容器选择新节点,并在新选的节点上运行它们。
SCALING THE NUMBER OF COPIES
在应用程序运行时,你可以决定增加或减少副本的数量,Kubernetes将相应地启动额外的副本或停止多余的副本。你甚至可以将决定副本的最佳数量的工作留给Kubernetes。它可以根据实时指标(例如CPU负载、内存消耗、每秒查询次数或你的应用程序公开的任何其他指标)自动调整副本数量。
HITTING A MOVING TARGET
为了让客户端轻松找到提供特定服务的容器,你可以告诉Kubernetes哪些容器提供相同的服务,Kubernetes将在单个静态IP地址下公开所有这些容器,并将该地址公开给在集群中运行的所有应用程序。这是通过环境变量完成的,但客户端也可以通过传统的DNS查找服务IP。kube-proxy将确保连接到服务的连接在提供服务的所有容器之间进行负载平衡。服务的IP地址保持不变,因此客户端始终可以连接到其容器,即使它们在集群中移动。
1.3.5 Understanding the benefits of using Kubernetes
在任何部署了Kubernetes的节点上,Kubernetes都可以立即运行应用程序,而无需系统管理员的帮助。
SIMPLIFYING APPLICATION DEPLOYMENT
Kubernetes将所有工作节点公开为单个部署平台,这使得应用程序开发人员可以轻松地部署应用程序,无需了解底层服务器的细节。所有节点都是计算资源池,开发人员只需要确保应用程序可以获得足够的系统资源即可。在某些情况下,开发人员需要关心应用程序运行的硬件,例如节点是异构的情况下,需要在具有特定功能的节点上运行某些应用程序。此时,使用Kubernetes可以方便地告诉Kubernetes仅在具有特定功能的节点之间选择运行应用程序,而不是手动选择特定节点。
ACHIEVING BETTER UTILIZATION OF HARDWARE
通过设置Kubernetes并使用容器来运行应用程序,你可以将应用程序与基础架构分离。Kubernetes会根据应用程序的资源要求选择最适合的节点来运行应用程序。同时,应用程序可以在集群中自由移动,以便更好地利用节点的硬件资源。这是因为计算机比人类更擅长在复杂的应用程序和节点组合中寻找最优的方案。
HEALTH CHECKING AND SELF-HEALING
具有随时可以在集群中移动应用程序的系统在服务器故障时非常有用。随着集群规模的增加,你将更频繁地处理计算机组件故障。
Kubernetes会监视应用程序组件及其运行的节点,并在节点故障时自动重新调度它们到其他节点上。这使得运维团队无需手动迁移应用程序组件,而是可以立即专注于修复节点本身并将其返回到可用硬件资源池中,而不必关注应用程序的重新定位。
如果你的基础架构有足够的备用资源,即使没有故障节点,系统也可以正常运行。这意味着运维团队不必立即对故障做出反应,例如在凌晨3点。他们可以安心睡觉,并在正常工作时间处理故障节点。
AUTOMATIC SCALING
使用Kubernetes来管理应用程序,可以避免运维团队不断监视各个应用程序的负载以应对突然的负载峰值。Kubernetes可以监视每个应用程序使用的资源,并不断调整每个应用程序运行实例的数量。如果Kubernetes运行在云基础设施上,它可以通过云提供商的API请求添加其他节点,根据已部署应用程序的需求自动调整整个集群的大小。这使得管理和部署应用程序变得更加容易和高效。
SIMPLIFYING APPLICATION DEVELOPMENT
Kubernetes对开发人员有很多好处。首先,应用程序在开发和生产环境中运行在相同的环境中,这有助于更早地发现漏洞,减少修复工作量。其次,Kubernetes可以代替应用程序实现一些功能,例如发现服务和/或对等点。这使得开发人员可以专注于应用程序的开发而不必花费时间和精力去实现这些功能。最后,Kubernetes可以自动检测新版本是否存在问题,并立即停止其发布,从而使开发人员更加自信,加速应用程序的持续交付,从而使整个组织受益。
1.4 Summary
- 单体应用程序更容易部署,但随着时间的推移,维护难度会增加,有时无法扩展。
- 基于微服务的应用程序架构可以更轻松地开发每个组件,但更难以部署和配置为一个单一的系统。
- Linux容器提供了几乎与虚拟机相同的好处,但更轻量级,并允许更好的硬件利用率。
- Docker改进了现有的Linux容器技术,使容器化应用程序及其操作系统环境更容易和更快速地进行配置。
- Kubernetes将整个数据中心作为一个单一的计算资源暴露出来,用于运行应用程序。
- 开发人员可以通过Kubernetes独立部署应用程序,无需系统管理员的帮助。
- 系统管理员可以通过让Kubernetes自动处理故障节点来更好地休息。