Kubernetes应用程序设计指南

发布时间:2024-02-16 19:00

Kubernetes应用程序设计指南

引言

设计和运行考虑到可伸缩性、可移植性和健壮性的应用程序可能具有挑战性,尤其是在系统复杂性增加的情况下。应用程序或系统的体系结构规定了它必须如何运行、它希望从其环境中得到什么,以及它与相关组件的耦合程度。在设计阶段遵循特定的模式并遵循特定的操作实践可以帮助应对应用程序在高度分布式环境中运行时面临的一些最常见的问题。

Docker和Kubernetes等技术帮助团队打包软件,然后在分布式计算机平台上分发、部署和扩展。了解如何最好地利用这些工具的功能可以帮助你以更高的灵活性、控制力和响应性来管理应用程序。

在本指南中,我们将讨论你可能想要采用的一些原则和模式,以帮助你扩展和管理Kubernetes上的工作负载。虽然Kubernetes可以运行许多类型的工作负载,但你的选择可能会影响操作的简易性和系统的可能性。

Kubernetes应用程序设计指南_第1张图片

针对应用程序可伸缩性进行设计

在开发软件时,许多需求会影响你选择采用的模式和体系结构。对于Kubernetes,最重要的因素之一是能够水平扩展,增加并行运行的应用程序的相同副本的数量,以分布负载和提高可用性。这是垂直扩展的替代方案,垂直扩展通常指增加单个应用程序堆栈的容量。

特别是,微服务是一种软件设计模式,可以很好地用于集群上的可伸缩部署。开发人员创建小型、可组合的应用程序,这些应用程序通过定义明确的API在网络上通信,而不是通过内部调用的单体复合程序。通过将单一应用程序重构为离散的单一用途组件,可以独立扩展每个功能。通常存在于应用程序级别的大部分复杂性和开销被转移平台上,在那里可以由Kubernetes等平台进行管理。

除了特定的软件模式之外,设计云原生应用程序时还考虑了一些额外的考虑因素。云本地应用程序通常遵循微服务架构模式,具有内置的弹性、可观察性和管理功能,以最大限度地利用云平台。

例如,使用运行状况报告指标构建云本地应用程序,以便在实例变得不健康时使平台能够管理应用程序生命周期。它们产生强大的监控数据,以提醒操作员注意问题,并使他们能够做出决定。定期重启和故障、后端程序出错以及高负载,应用程序不会无响应或是丢失数据。

遵循12要素应用原则

十二要素应用程序原则是一种流行的方法,可以帮助你专注于创建云原生Web应用程序时最重要的特征。这些原则最初是为了帮助开发人员和运营团队理解为在云上运行而设计的Web服务所共有的核心品质,现在非常适用于将在Kubernetes这样的集群环境中运行的软件。虽然单体应用程序可以从遵循这些建议中受益,但围绕这些原则设计的微服务架构效果更好。

以下是12个因素的简要总结:

  1. **代码库:**在代码版本管理系统(如 Git 或 Mercurial)中管理所有代码。代码库全面规定了部署的内容。
  2. **依赖项:**依赖项应该完全由代码库明确地管理,无论是供应商软件(与代码一起存储)还是在包管理器指定固定的版本。
  3. **配置:**将配置参数从应用程序中分离出来,并在部署环境中定义它们,而不是将它们放置到应用程序本身中。
  4. **后台服务:**本地和远程服务都被抽象为网络可访问资源,并在配置中设置连接详细信息。
  5. **构建、发布、运行:**你的应用程序的构建阶段应该与你的应用程序发布和运行过程完全分开。构建阶段从源代码创建部署制品,发布阶段结合制品和配置,运行阶段执行发布。
  6. **进程:**应用程序被实现为不应依赖本地存储状态的进程。应该将状态落到后台服务,如第四个因素中所述。
  7. **端口绑定:**应用程序应本机绑定到端口并侦听连接。路由和请求转发应该在外部处理。
  8. **并发性:**应用程序应该依赖于通过流程模型进行扩展。同时运行应用程序的多个副本,可能跨多个服务器,允许在不调整应用程序代码的情况下进行扩展。
  9. **可处置性:**进程应该能够快速启动并优雅地停止而不会产生严重的副作用。
  10. **开发/生产:**您的测试、试运行和生产环境应紧密匹配并保持同步。环境之间的差异可能造成不兼容和未经测试的配置。
  11. **日志:**应用程序应该将日志流式传输到标准输出,以便外部服务可以决定如何最好地处理它们。
  12. **管理流程:**一次性管理流程应针对特定版本运行,并与主流程代码一起提供。

管理版本控制系统(如Git或Mercurial)中的所有代码。依赖项:依赖项应该完全显式地由代码库管理,要么是提供的(与代码一起存储的),要么是以包管理器可以安装的格式固定的版本。配置:将配置参数从应用程序中分离出来,并在部署环境中定义它们,而不是将它们烘焙到应用程序本身中。后台服务:本地和远程服务都抽象为网络可访问的资源,并在配置中设置连接细节。构建、发布、运行:应用程序的构建阶段应该与应用程序的发布和操作过程完全分开。构建阶段从源代码创建部署构件,发布阶段组合构件和配置,运行阶段执行发布。过程:应用程序被实现为不应该依赖于本地存储状态的过程。应将状态卸载到支持服务,如第四个因素所述。端口绑定:应用程序应本地绑定到端口并侦听连接。路由和请求转发应该在外部处理。

并发性:应用程序应该依赖于通过流程模型进行扩展。同时运行应用程序的多个副本(可能跨多个服务器)允许在不调整应用程序代码的情况下进行扩展。可处置性:进程应该能够快速启动和优雅地停止,而不会产生严重的副作用。开发/生产奇偶校验:你的测试、试运行和生产环境应该紧密匹配,并保持同步。环境之间的差异是不兼容和未测试配置出现的机会。日志:应用程序应该将日志流到标准输出,以便外部服务可以决定如何最好地处理它们。管理进程:应该针对特定版本运行一次性管理进程,并与主进程代码一起提供。通过遵循十二要素提供的指导原则,你可以创建和运行非常适合Kubernetes的应用程序。十二个因素鼓励开发人员将重点放在应用程序的主要用途上,考虑组件之间的操作条件和接口,并使用输入、输出和标准流程管理功能在Kubernetes中可预测地运行。

通过遵循十二要素提供的指导原则,你可以创建和运行非常适合Kubernetes的应用程序。十二个因素鼓励开发人员将重点放在应用程序的主要用途上,考虑组件之间的接口,并使用输入、输出和标准流程管理功能在Kubernetes中可控地运行。

将应用程序组件容器化

Kubernetes使用容器在其集群节点上运行隔离的打包应用程序。要在Kubernetes上运行,你的应用程序必须封装在一个或多个容器镜像中,并使用Docker等容器运行时执行。尽管组件的容器化是Kubernetes的一项要求,但它也有助于强化上面讨论的十二要素应用程序方法中的许多原则,从而实现更好的伸缩性和管理。

例如,容器在应用程序环境和外部主机系统之间提供隔离。它们支持应用程序间通信的联网方式,通常通过环境变量进行配置,并公开写入stdoutstderr的日志。容器本身鼓励基于进程的并发性,并通过独立可伸缩的运行时环境来帮助维护开发/生产环境。这些特性使得打包你的应用程序成为可能,以便它们能够在Kubernetes上流畅地运行。

优化容器的指导方针

容器技术的灵活性允许封装应用程序的多种不同方式。但是,在 Kubernetes 环境中,某些方法比其他方法效果更好。

大多数关于应用程序容器的最佳实践都与映像构建有关,你可以在其中定义如何在容器中设置和运行你的软件。一般而言,保持镜像小而简单可以带来许多好处。优化大小的镜像可以通过在镜像更新之间重用现有层来减少在集群上启动新容器所需的时间和资源,这是Docker和其他容器框架设计为自动完成的。

创建容器映像的第一步是尽最大努力将构建步骤与将在生产中运行的最终映像分开。编译软件通常需要额外的工具,花费额外的时间,并产生可能在不同容器之间不一致或对最终运行时环境不必要的构件(例如,跨平台依赖)。将构建过程与运行时环境完全分开的一种方法是使用Docker多阶段构建。多阶段构建配置允许你指定一个基本映像以在构建过程中使用,并定义另一个以在运行时使用。这使得可以使用安装了所有构建工具的映像来构建软件,并将生成的构件复制到一个精简的映像中,以后每次都会使用该映像。

有了这种可用的功能,在最小的父映像上构建生产映像通常是一个好主意。如果你希望完全避免ubuntu:20.04(包含完整的Ubuntu 20.04服务器环境)之类的发行版风格父层的臃肿,你可以使用Docker最小的基础镜像scratch作为父镜像来构建你的镜像。然而,scratch基本层并不提供对许多核心工具,并且经常会打破关于Linux环境的一些基线。作为另一种选择,Alpine Linux alpine镜像已经变得流行起来,因为它是一个坚实的、最小的基础环境,提供了一个很小但功能齐全的Linux发行版。

对于像Python或Ruby这样的解释型语言,原则稍有变化,因为没有编译阶段,而且解释器必须可用于在生产环境中运行代码。然而,由于超薄镜像仍然是理想的,许多特定语言构建在Alpine Linux之上的优化镜像在Docker Hub上可用。对解释语言使用较小镜像的好处与对编译语言使用较小镜像的好处相似:Kubernetes将能够快速将所有必要的容器镜像拖到新节点上,以开始进行有意义的工作。

确定容器和 Pod 的范围

虽然你的应用程序必须被容器化才能在Kubernetes集群上运行,但Pod是Kubernetes可以直接管理的最小抽象单元。Pod是由一个或多个紧密耦合的容器组成的Kubernetes对象。Pod中的容器共享一个生命周期,并作为一个单元一起管理。例如,容器始终部署在同一节点(服务器)上,同时启动或停止,并共享文件系统和IP寻址等资源。

了解Kubernetes如何处理这些组件以及每个抽象层为你的系统提供了什么,这一点很重要。一些注意事项可以帮助您使用这些抽象中的每一个来确定应用程序的一些自然封装点。

确定容器的有效范围的一种方法是寻找自然开发边界。如果你的系统使用微服务体系结构运行,则通常会构建设计良好的容器来表示分散的功能单元,这些功能单元通常可以在各种上下文中使用。这种抽象级别允许你的团队发布对容器映像的更改,然后将此新功能部署到使用这些映像的任何环境中。应用程序可以通过组成单独的容器来构建,每个容器都可以完成给定的功能,但可能不会单独完成整个过程。

与上面的情况不同,Pod通常是通过考虑系统的哪些部分可能从独立管理中获益最多来构建的。由于Kubernetes使用Pod作为其最小的面向用户的抽象,因此这些是Kubernetes工具和API可以直接交互和控制的最原始单元。你可以启动、停止和重新启动Pod,或者使用构建在Pod上的更高级别的对象来引入复制和生命周期管理功能。Kubernetes不允许你独立管理Pod中的容器,因此你不应该将单独管理的容器组合在一起。

因为Kubernetes的许多特性和抽象直接涉及Pod,所以将应该在单个Pod中一起扩展的项捆绑在一起,并将应该独立扩展的项分开。例如,将Web服务器与应用程序服务器分离在不同的Pod中,可以根据需要独立扩展每一层。但是,如果数据库提供Web服务器正常工作所需的基本功能,则将Web服务器和数据库捆绑到同一个Pod中可能是正确的选择。

通过捆绑支持容器增强Pod功能

考虑到这一点,应该将哪些类型的容器捆绑在一个 pod 中?通常,主容器负责完成 pod 的核心功能,但可以定义附加容器来修改或扩展主容器或帮助其连接到独特的部署环境。

例如,在 Web 服务器 pod 中,Nginx 容器可能会侦听请求并提供内容,而关联的容器会在存储库更改时更新静态文件。将这两个组件打包在一个容器中可能很诱人,但是将它们实现为单独的容器有很大的好处。Web 服务器容器和存储库拉取程序都可以在不同的上下文中独立使用。它们可以由不同的团队维护,并且每个都可以被开发以概括他们的行为以与不同的配套容器一起工作。

Brendan Burns 和 David Oppenheimer 在他们关于基于容器的分布式系统的设计模式的论文中确定了捆绑支持容器的三种主要模式。这些代表了将容器打包到一个 pod 中的一些最常见的用例:

  • **Sidecar:**在这种模式中,辅助容器扩展并增强了主容器的核心功能。此模式涉及在单独的容器中执行非标准或实用功能。例如,转发日志或监视更新配置值的容器可以在不改变其主要关注点的情况下增强 pod 的功能。
  • **大使:**大使模式使用补充容器为主容器抽象远程资源。主容器直接连接到大使容器,大使容器又连接并抽象出潜在复杂的外部资源池,例如分布式 Redis 集群。主容器不必知道或关心连接到外部服务的实际部署环境。
  • **适配器:**适配器模式用于转换主容器的数据、协议或接口,以符合外部各方期望的标准。适配器容器支持对集中式服务的统一访问,即使它们所服务的应用程序可能仅原生支持不兼容的接口。

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号