规划并运转一个兼顾可扩展性、可移植性和健壮性的运用是一件很有应战的事情,尤其是当体系杂乱度在不断增长时。运用或体系 本身的架构极大的影响着其运转办法、对环境的依靠性,以及与相关组件的耦合强弱。当运用在一个高度散布式的环境中运转时, 假如能在规划阶段遵从特定形式,在运维阶段恪守特定实践,就能够协助咱们更好的应对那些最常呈现的问题。 尽管软件规划形式和开发办法论能够协助咱们出产出满足恰当扩展性目标的运用,根底设施与运转环境也在影响着已布置体系的运 维操作。像 Docker、Kubernetes 这些技能能够协助团队打包、分发、布置以及在散布式环境中扩展运用。学习怎么最好的驾御这 些东西,能够协助你在办理运用时拥有更好的机动性、操控性和呼应能力。 在这份攻略里,咱们将探讨一些你或许想采用的准则和形式,它们能够协助你在 Kubernetes 上更好的扩展和办理你的作业集 (workloads)。尽管在 Kubernetes 上能够运转各式各样的作业集,可是你的不同挑选会影响运维难度和布置时的可选项。你怎么 架构和构建运用、怎么将效劳用容器打包、怎么装备生命周期办理以及在 kubernetes 上怎么操作,每一个点都会影响你的体会。 为可扩展性做运用规划 当开发软件时,你所选用的形式与架构会被许多需求所影响。关于 Kubernetes 来说,它最重要的特征之一就是要求运用拥有水平 扩展能力 - 经过调整运用副本数来分管负载以及提高可用性。这与笔直扩展不同,笔直扩展测验运用同样的参数将运用布置到性能 更强或更弱的效劳器上。 比方,微效劳架构是一种合适在集群中运转多个可扩展运用的软件规划形式。开发者们创立一些可组合的简略运用,它们经过杰出 界说的 REST 接口进行网络通讯,而不是像更杂乱的单体式运用那样经进程序内部机制通讯。将单体式运用拆分为多个独立的单一 功用组件后,咱们能够独立的扩展每个功用组件。许多之前一般存在于运用层的组合与杂乱度被搬运到了运维范畴,而它们刚好可 以被像 Kubernetes 这样的渠道搞定。 比特定的软件形式更进一步,云原生(cloud native)运用在规划之初就有一些额定的考量。云原生运用是遵从了微效劳架构形式 的程序,拥有内置的可康复性、可观测性和可办理性,专门用于适应云集群渠道供给的环境。 举例来说,云原生运用在被创造出时都带有健康度目标数据,当某个实例变得不健康时,渠道能够依据目标数据来办理实例的生命 周期。这些目标发生(也能够被导出)稳定的遥控数据来给运维人员告警,让他们能够依据这些数据做决策。运用被规划成能够应 付常规的重启、失败、后端可用性改变以及高负载等各种情况,而不会损坏数据或许变得无法呼应。 遵从 “12 规律运用”运用理论 在创立预备跑在云上的 web 运用时,有一个盛行的办法论能够帮你关注到那些最重要的特征:“12 规律运用理论”( Twelve- Factor App)。它最初被编写出来,是为了协助开发者和运维团队了解一切被规划成在云环境运转的 web 效劳的共有核心特征,而 关于那些将在 Kubernetes 这种集群环境中运转的运用,这个理论也十分适用。尽管单体式运用能够从这些主张中获益,围绕这些 准则规划的微效劳架构运用也会作业的十分好。 “12 规律”的一份简略摘要: 基准代码(Codebase): 将你的一切代码都放在版别操控体系中(比方 Git 或许 Mercurial)。被布置的内容彻底由基准代码决 定。 依靠(Dependencies):运用依靠应该由基准代码全部显式办理起来,无论是用 vendor(指依靠代码和运用代码保存在一同),还 是经过可由包办理软件解析装置的依靠装备文件的办法。 装备(Config):把运用装备参数与运用本身分开来,装备应该在布置环境中界说,而不是被嵌入到运用本身。 后端效劳(Backing Services):本地或长途的依靠效劳都应该被笼统为可经过网络拜访的资源,衔接细节应该在装备中界说。 构建、发布、运转(Build, release, run):运用的构建阶段应该彻底与发布、运维阶段区别开来。构建阶段从运用源码创立出一 个可履行包,发布阶段担任把可履行包和装备组合起来,然后在运转阶段履行这个发布版别。 进程(Processes):运用应该由不依靠任何本地状况存储的进程完结。状况应该被存储在第 4 个规律描绘的后端效劳中。 端口绑定(Port binding):运用应该原生绑定端口和监听衔接。一切的路由和恳求转发作业应该由外部处理。 并发(Concurrency):运用应该依靠于进程模型扩展。只需同时运转多份运用(或许散布在不同效劳器上),就能完结不调整运用 代码扩展的意图。 易处理(Disposability):进程应该能够被快速发动、高雅中止,而不发生任何严峻的副作用。 开发环境与线上环境等价(Dev/prod parity):你的测验、预发布以及线上环境应该尽或许共同而且坚持同步。环境间的差异有可 能会导致兼容性问题和未经测验的装备突然呈现。 日志(Logs):运用应该将日志输出到规范输出(stdout),然后由外部效劳来决定最佳的处理办法。 办理进程(Admin processes):一次性办理进程应该和主进程代码一同发布,依据某个特定的发布版别运转。 依照“12 规律”所供给的攻略,你能够运用彻底适用于 Kubernetes 运转环境的模型来创立和运转运用。“12 规律”鼓舞开发者 们专心于他们运用的首要职责,考虑运维条件以及组件间的接口规划,并运用输入、输出和规范进程办理功用,终究以可被预见的 办法将运用在 Kubernetes 中跑起来。 容器化运用组件 Kubernetes 运用容器在集群节点上运转阻隔的打包运用程序。要在 Kubernetes 上运转,你的运用有必要被封装在一个或许多个容器 镜像中,并运用 Docker 这样的容器运转时履行。尽管容器化你的组件是 Kubernetes 的要求之一,但其实这个进程也协助强化了 刚刚谈到的“12规律运用”里的许多准则,然后让咱们能够简略的扩展和办理运用。 举例来说,容器供给了运用环境与外部宿主机环境之间的阻隔,供给了一个依据网络、面向效劳的运用间通讯办法,而且一般都是 从环境变量读取装备、将日志写到规范输出与规范错误输出中。容器本身鼓舞依据进程的并发策略,而且能够经过坚持独立扩展性 和绑缚运转时环境来协助坚持开发/线上环境共同性(#10 Dev/prod parity)。这些特性让你能够顺畅打包运用,然后顺畅的在 Kubernetes 上运转起来。 容器优化准则 由于容器技能的灵活性,咱们有许多不同种封装运用的办法。可是在 Kubernetes 环境中,其间一些办法比其他办法作业的更好。 镜像构建(image building),是指你界说运用将怎么在容器里被设置与运转的进程,绝大多数关于“怎么容器化运用”的最佳实 践都与镜像构建进程有关。一般来说,坚持镜像尺度小以及可组合会带来许多优点。在镜像晋级时,经过坚持构建步骤可办理以及 复用现有镜像层,被优化过尺度的的镜像能够减少在集群中发动一个新容器所需求的时刻与资源。 当构建容器镜像时,尽最大努力将构建步骤与终究在出产环境运转的镜像区别开来是一个好的开端。构建软件一般需求额定的工 具、花费更多时刻,而且会出产出在不同容器里体现不同、或是在终究运转时环境里根本不需求的内容。将构建进程与运转时环境 清晰分开的办法之一是运用 Docker 的“多阶段构建(multi-stage builds)” 特性。多阶段构建装备答应你为构建阶段和运转阶 段设置不同的根底镜像。也就是说,你能够运用一个装置了一切构建东西的镜像来构建软件,然后将结果可履行软件包复制到一个 精简过的、之后每次都会用到的镜像中。 有了这类功用后,依据最小化的父镜像来构建出产环境镜像一般会是个好主意。假如你想彻底防止由 ubuntu:16.04(该镜像包含了 一个完好的 Ubuntu 16.04 环境)这类 “Linux 发行版” 风格父镜像带来的臃肿,你能够测验用 scratch - Docker 的最简根底 镜像 - 来构建你的镜像。不过 scratch 根底镜像缺了一些核心东西,所以部分软件或许会由于环境问题而无法运转。别的一个方 案是运用 Alpine Linux 的 alpine 镜像,该镜像供给了一个轻量可是拥有完好特性的 Linux 发行版。它作为一个稳定的最小根底 环境获得了广泛的运用。 关于像 Python 或 Ruby 这种解说型编程言语来说,上面的例子会稍有改变。由于它们不存在“编译”阶段,而且在出产环境运转 代码时一定需求有解说器。不过由于咱们依然寻求精简的镜像,所以 Docker Hub 上仍是有许多依据 Alpine Linux 构建的各言语 优化版镜像。关于解说型言语来说,运用更小镜像带来的优点和编译型言语差不多:在开端正式作业前,Kubernetes 能够在新节点 上快速拉取到一切有必要的容器镜像。 在 Pod 和“容器”之间做挑选 尽管你的运用有必要被“容器”化后才能在 Kubernetes 上跑起来,但 pods(译注:由于 pod、service、ingress 这类资源名称不 合适翻译为中文,此处及后面均运用英文原文) 才是 Kubernetes 能直接办理的最小笼统单位。pod 是由一个或更多严密相关的容 器组合在一同的 Kubernetes 目标。同一个 pod 里的一切容器共享同一生命周期且作为一个独立单位被办理。比方,这些容器总是 被调度到同一个节点上、一同被发动或中止,同时共享 IP 和文件体系这类资源。 一开端,找到将运用拆分为 pods 和容器的最佳办法会比较困难。所以,了解 Kubernetes 是怎么处理这些目标,以及每个笼统层 为你的体系带来了什么变得十分重要。下面这些事项能够协助你在运用这些笼统概念封装运用时,找到一些自然的鸿沟点。 寻觅自然开发鸿沟是为你的容器决定有效范围的手段之一。假如你的体系采用了微效劳架构,一切容器都经过杰出规划、被频频构 建,各自担任不同的独立功用,而且能够被经常用到不同场景中。这个程度的笼统能够让你的团队经过容器镜像来发布改变,然后 将这个新功用发布到一切运用了这个镜像的环境中去。运用能够经过组合许多容器来构建,这些容器里的每一个都完结了特定的功 能,可是又不能独立成事。 与上面相反,当考虑的是体系中的哪些部分能够从独立办理中获益最多时,咱们常常会用 pods。Kubernetes 运用 pods 作为它面 向用户的最小笼统,因而它们是 Kubernetes API 和东西能够直接交互与操控的最原生单位。你能够发动、中止或许重启 pods,或 者运用依据 pods 建立的更高级别笼统来引进副本集和生命周期办理这些特性。Kubernetes 不答应你独自办理一个 Pod 里的不同 容器,所以假如某些容器能够从独立办理中获得优点,那么你就不应该把它们分到到一个组里。 由于 Kubernetes 的许多特性和笼统概念都直接和 pods 打交道,所以把那些应该被一同扩缩容的东西绑缚到一个 pod 里、应该被 分开扩缩容的分到不同 pod 中是很有道理的。举例来说,将前端 web 效劳器和运用效劳放到不同 pods 里让你能够依据需求独自 对每一层进行扩缩容。不过,有时候把 web 效劳器和数据库适配层放在同一个 pod 里也说得过去,假如那个适配器为 web 效劳器 供给了它正常运转所需的基本功用的话。 经过和支撑性容器绑缚到一同来增强 Pod 功用 了解了上面这点后,究竟什么类型的容器应该被绑缚到同一个 pod 里呢?一般来说,pod 里的主容器担任供给 pod 的核心功用, 可是咱们能够界说附加容器来修正或许扩展那个主容器,或许协助它适配到某个特定的布置环境中。 比方,在一个 web 效劳器 pod 中,或许会存在一个 Nginx 容器来监听恳求和托管静态内容,而这些静态内容则是由别的一个容器 来监听项目变动并更新的。尽管把这两个组件打包到同一个容器里的主意听上去不错,可是把它们作为独立的容器来完结是有许多 优点的。nginx 容器和内容拉取容器都能够独立的在不同情形中运用。它们能够由不同的团队保护并别离开发,到达将行为通用化 来与不同的容器协同作业的意图。 Brendan Burns 和 David Oppenheimer 在他们关于“依据容器的散布式体系规划形式”的论文中界说了三种打包支撑性容器的首要 形式。它们代表了一些最常见的将容器打包到 pod 里的用例: Sidecar(边车形式):在这个形式中,次要容器扩展和增强了主容器的核心功用。这个形式触及在一个独立容器里履行非规范或工 具功用。举例来说,某个转发日志或许监听装备值改动的容器能够扩展某个 pod 的功用,而不会改动它的首要关注点。 Ambassador(大使形式):Ambassador 形式运用一个援助性容器来为主容器完结长途资源的笼统。主容器直接衔接到 Ambassador 容器,而 Ambassador 容器反过来衔接到或许很杂乱的外部资源池 - 比方说一个散布式 Redis 集群 - 并完结资源笼统。主容器可 以完结衔接外部效劳,而不必知道或许关心它们实际的布置环境。 Adaptor(适配器形式):Adaptor 形式被用来翻译主容器的数据、协议或是所运用的接口,来与外部用户的希望规范对齐。 Adaptor 容器也能够统一化中心效劳的拜访入口,即便它们效劳的用户本来只支撑互不兼容的接口规范。 运用 Configmaps 和 Secrets 来保存装备 尽管运用装备能够被一同打包进容器镜像里,可是让你的组件在运转时坚持可被装备能更好支撑多环境布置以及供给更多办理灵活 性。为了办理运转时的装备参数,Kubernetes 供给了两个目标:ConfigMaps 与 Secrets。 ConfigMaps 是一种用于保存可在运转时暴露给 pods 和其他目标的数据的机制。保存在 ConfigMaps 里的数据能够经过环境变量使 用,或是作为文件挂载到 pod 中。经过将运用规划成从这些位置读取装备后,你能够在运用运转时运用 ConfigMaps 注入装备,并 以此来修正组件行为而不必重新构建整个容器镜像。 Secrets 是一品种似的 Kubernetes 目标类型,它首要被用来安全的保存敏感数据,并依据需求挑选性的的答应 pods 或是其他组 件拜访。Secrets 是一种便利的往运用传递敏感内容的办法,它不必像一般装备相同将这些内容用纯文本存储在能够被轻易拜访到 的当地。从功用性上讲,它们的作业办法和 ConfigMaps 简直彻底共同,所以运用能够用彻底相同的办法从二者中获取数据。 ConfigMaps 和 Secrets 能够帮你防止将装备内容直接放在 Kubernetes 目标界说中。你能够只映射装备的键名而不是值,这样可 以答应你经过修正 CongfigMap 或 Secret 来动态更新装备。这使你能够修正线上 pod 和其他 kubernetes 目标的运转时行为,而 不必修正这些资源本身的界说。 完结“安排妥当检测(Readiness)”与“存活检测(Liveness)”探针 Kubernetes 包含了十分多用来办理组件生命周期的开箱即用功用,它们能够保证你的运用始终坚持健康和可用状况。不过,为了利 用好这些特性,Kubernetes 有必要要理解它应该怎么监控和解说你的运用健康情况。为此,Kubernetes 答应你界说“安排妥当检测探针 (Readiness Probe)”与“存活检测探针(Liveness Probe)”。 “存活检测探针”答应 Kubernetes 来断定某个容器里的运用是否处于存活与运转状况。Kubernetes 能够在容器内周期性的履行一 些指令来检查基本的运用行为,或许能够往特定地址发送 HTTP / TCP 网络恳求来判断进程是否可用、呼应是否符合预期。假如某 个“存活探测指针”失败了,Kubernetes 将会重启容器来测验康复整个 pod 的功用。 “安排妥当检测探针”是一个类似的东西,它首要用来判断某个 Pod 是否现已预备好承受恳求流量了。在容器运用彻底安排妥当,能够承受 客户端恳求前,它们或许需求履行一些初始化进程,或许当接到新装备时需求重新加载进程。当一个“安排妥当检测探针”失败后, Kubernetes 会暂停往这个 Pod 发送恳求,而不是重启它。这使得 Pod 能够完结本身的初始化或许保护使命,而不会影响到整个组 的整体健康状况。 经过结合运用“存活检测探针”与“安排妥当检测探针”,你能够操控 Kubernetes 自动重启 pods 或是将它们从后端效劳组里剔除。 经过装备根底设施来使用好这些特性,你能够让 Kubernetes 来办理运用的可用性和健康状况,而无需履行额定的运维作业。 运用 Deployments 来办理扩展性与可用性 在早些时候讨论 Pod 规划根底时,咱们说到其他 Kubernetes 目标会建立在 Pod 的根底上来供给更高级的功用。而 deployment 这个复合目标,或许是被界说和操作的最多次的 Kubernetes 目标。 Deployments 是一种复合目标,它经过建立在其他 Kubernetes 根底目标之上来供给额定功用。它们为一类名为 replicasets 的中 间目标添加了生命周期办理功用,比方能够施行“翻滚晋级(Rolling updates)”、回滚到旧版别、以及在不同状况间转化的能 力。这些 replicasets 答应你界说 pod 模板并依据它快速拉起和办理多份依据这个模板的副本。这能够协助你便利的扩展根底设 施、办理可用性要求,并在毛病发生时自动重启 Pods。 这些额定特性为相对简略的 pod 笼统供给了一个办理框架和自我修复能力。尽管你界说的作业集终究仍是由 pods 单元来承载,但 是它们却不是你一般应该最多装备和办理的单位。相反,当 pods 由 deployments 这种更高级目标装备时,应该把它们当做能够稳 定运转运用的根底构建块来考虑。 创立 Services 与 Ingress 规矩来办理到运用层的拜访 Deployment 答应你装备和办理可交换的 Pod 集合,以扩展运用以及满足用户需求。可是,怎么将恳求流量路由到这些 pods 则是 破例一码事了。鉴于 pods 会在翻滚晋级的进程中被换出、重启,或许由于机器毛病发生搬运,之前被分配给这个运转组的网络地 址也会发生改变。Kubernetes services 经过保护动态 pods 资源池以及办理各根底设施层的拜访权限,来协助你办理这部分杂乱 性。 在 Kuberntes 里,services 是操控流量怎么被路由到多批 pods 的机制。无论是为外部客户转发流量,仍是办理多个内部组件之 间的衔接,services 答应你来操控流量该怎么活动。然后,Kubernetes 将更新和保护将衔接转发到相关 pods 的一切必需信息, 即使环境或网络条件发生改变也相同。 从内部拜访 Services 为了有效的运用 services,你首要应该断定每组 pods 效劳的目标用户是谁。假如你的 service 只会被布置在同一个 Kubernetes 集群的其他运用所运用,那么 ClusterIP 类型答应你运用一个仅在集群内部可路由的固定 IP 地址来拜访一组 pods。一切布置在 集群上的目标都能够经过直接往这个 service IP 地址发送恳求来与这组 pod 副本通讯。这是最简略的 service 类型,很合适在 内部运用层运用。 Kubernetes 供给了可选的 DNS 插件来为 services 供给姓名解析效劳。这答应 pods 和其他目标能够运用域名来代替 IP 地址进 行通讯。这套机制不会显著改动 service 的用法,但依据域名的标识符能够使衔接组件和界说效劳间交互变得更简略,而不需求提 前知道 service IP 地址。 将 Services 向公网开放 假如你的运用需求被公网拜访,奇迹狐网站那么 “负载均衡器(load balancer)”类型的 service 一般会是你的最佳挑选。它会运用运用所 在的特定云供给商 API 来装备一个负载均衡器,由这个负载均衡器经过一个公网 IP 来效劳一切到 service pods 的流量。这种方 式供给了一个到集群内部网络的可控网络通道,然后将外部流量引进到你的 service pods 中。 由于“负载均衡器”类型会为每一个 service 都创立一个负载均衡器,因而用这种办法来暴露 Kubernetes 效劳或许会有些昂贵。 为了协助缓解这个问题,咱们能够运用 Kubernetes ingress 目标来描绘怎么依据预定规矩集来将不同类型的恳求路由到不同 services。例如,发往 “example.com” 的恳求或许会被指向到 service A,而往 “sammytheshark.com” 的恳求或许会被路由 到 service B。Ingress 目标供给了一种描绘怎么依据预界说形式将混合恳求流别离路由到它们的目标 services 的办法。 Ingress 规矩有必要由一个 ingress controller 来解析,它一般是某种负载均衡器(比方 Nginx),以 pod 的办法布置在集群中, 它完结了 ingress 规矩并依据规矩将流量分发到 Kubernetes serices 上。目前,ingress 资源目标界说依然处于 beta 阶段,但 是市面上现已有好几个能作业的具体完结了,它们能够协助集群一切者最小化需求运转的外部负载均衡器数量。
Kubernetes 之上的架构应用 运用声明式语法来办理 Kubernetes 状况 Kubernetes 在界说和办理布置到集群的资源方面供给了很大灵活性。运用 kubectl 这样的东西,你能够指令式的界说一次性资源 并将其快速布置到集群中。尽管在学习 Kubernetes 阶段,这个办法关于快速布置资源或许很有用,但这种办法也存在许多缺陷, 不合适长周期的出产环境办理。 指令式办理办法的最大问题之一就是它不保存你往集群布置过的改变记录。这使得毛病时康复和跟踪体系内运维改变操作变得十分 困难,乃至不或许。 走运的是,Kubernetes 供给了别的一种声明式的语法,它答应你运用文本文件来完好界说资源,并随后运用 kubectl 指令运用这 些装备或更改。将这些装备文件保存在版别操控体系里,是监控改变以及与你的公司内其他部分的审理进程集成的一种简略办法。 依据文件的办理办法也让将已有形式适配专卖网站到新资源时变得简略,只需求复制然后修正现有资源界说即可。将 Kubernetes 目标界说 保存在版别化目录里答应你保护集群在每个时刻节点的希望集群状况快照。当你需求进行毛病康复、搬迁,或是追踪体系里某些意 料之外的改变时,这些内容的价值是不可估量的。 总结 办理运转运用的根底设施,并学习怎么最好的使用这些现代化编排体系供给的特性,这些事情或许会令人望而生畏。可是,只有当 你的开发与运维进程与这些东西的构建概念共同时,Kubernetes 体系、容器技能供给的优势才能更好的体现出来。遵从 Kubernetes 最擅长的那些形式来架构你的体系,以及了解特定功用怎么能缓解由高度杂乱的布置带来的应战,能够协助改进你运转 渠道时的体会。