本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
走出云端,落地生根:如何让 Kubernetes 在任何地方都达到生产级别
这篇博客提供了一些在本地数据中心或边缘位置等环境中运行生产级 Kubernetes 集群的指南。
“生产级”意味着什么?
- 安装是安全的
- 部署通过可重复和记录的过程进行管理
- 性能可预测且一致
- 更新和配置更改可以安全应用
- 日志和监控到位,以检测和诊断故障和资源短缺
- 考虑到可用资源,包括金钱、物理空间、电力等限制,服务“高可用性足够好”
- 在发生故障时,恢复过程可用、有文档记录并经过测试
简而言之,生产级意味着预见事故并准备好以最小的痛苦和延迟进行恢复。
本文针对基于管理程序或裸机平台的本地 Kubernetes 部署,与主要的公共云的可扩展性相比,这些部署面临有限的后端资源。但是,如果预算限制了您选择使用的资源,其中一些建议也可能在公共云中发挥作用。
单节点裸机 Minikube 部署可能便宜且简单,但并非生产级。反之,您不太可能在零售店、分支机构或边缘位置获得 Google Borg 的体验,您也不太可能需要它。
这篇博客提供了一些关于实现生产级 Kubernetes 部署的指导,即使在资源受限的情况下也是如此。
Kubernetes 集群中的关键组件
在深入了解细节之前,了解 Kubernetes 的整体架构至关重要。
Kubernetes 集群是一个高度分布式的系统,基于控制平面和集群工作节点架构,如下图所示。
通常,API 服务器、控制器管理器和调度器组件共存于控制平面(也称为主节点)的多个实例中。主节点通常也包含 etcd,尽管在需要将 etcd 运行在独立主机上的高可用性场景和大型集群场景中有所不同。这些组件可以作为容器运行,并可选择由 Kubernetes 监督,即作为静态 Pod 运行。
为了实现高可用性,使用了这些组件的冗余实例。其重要性和所需的冗余程度各不相同。
从高可用性角度看 Kubernetes 组件
这些组件面临的风险包括硬件故障、软件错误、不良更新、人为错误、网络中断和系统过载导致的资源耗尽。冗余可以减轻其中许多危害的影响。此外,管理程序平台的资源调度和高可用性功能有助于超越仅使用 Linux 操作系统、Kubernetes 和容器运行时所能实现的功能。
API 服务器使用负载均衡器后面的多个实例来实现规模和可用性。负载均衡器是高可用性目的的关键组件。如果您没有负载均衡器,多个 DNS API Server “A” 记录可能是一种替代方案。
kube-scheduler 和 kube-controller-manager 采用领导者选举过程,而不是使用负载均衡器。由于 cloud-controller-manager 用于选定的托管基础设施类型,并且这些类型有实现差异,因此除了指出它们是控制平面组件之外,本文将不予讨论。
运行在 Kubernetes 工作节点上的 Pod 由 kubelet 代理管理。每个工作实例都运行 kubelet 代理和一个 CRI 兼容的容器运行时。Kubernetes 本身旨在监控和从工作节点故障中恢复。但对于关键工作负载,管理程序资源管理、工作负载隔离和可用性功能可用于增强可用性并使性能更可预测。
etcd
etcd 是所有 Kubernetes 对象的持久存储。etcd 集群的可用性和可恢复性应该是生产级 Kubernetes 部署中的首要考虑。
如果资源允许,一个五节点的 etcd 集群是最佳实践。为什么?因为您可以在一个节点进行维护,同时仍能容忍一个故障。即使只有一个管理程序主机可用,三节点集群也是生产级服务的最小建议。除了跨多个可用区非常大的安装之外,不建议使用超过七个节点。
托管 etcd 集群节点的最低建议配置是 2GB 内存和 8GB SSD 硬盘。通常,8GB 内存和 20GB 硬盘就足够了。磁盘性能会影响故障节点的恢复时间。有关更多信息,请参阅 https://coreos.com/etcd/docs/latest/op-guide/hardware.html。
在特殊情况下考虑多个 etcd 集群
对于非常大的 Kubernetes 集群,请考虑为 Kubernetes 事件使用独立的 etcd 集群,这样事件风暴就不会影响主要的 Kubernetes API 服务。如果您使用 flannel 网络,它会在 etcd 中保留配置,并且可能具有与 Kubernetes 不同的版本要求,这会使 etcd 备份复杂化——考虑为 flannel 使用专用的 etcd 集群。
单主机部署
可用性风险清单包括硬件、软件和人员。如果您仅限于一台主机,使用冗余存储、纠错内存和双电源可以减少硬件故障的暴露。在物理主机上运行虚拟机监控程序将允许操作冗余软件组件,并增加与部署、升级和资源消耗治理相关的操作优势,在压力下提供可预测和可重复的性能。例如,即使您只能负担运行主服务的单例,它们也需要在与应用程序工作负载竞争时受到过载和资源耗尽的保护。虚拟机监控程序比配置 Linux 调度器优先级、cgroups、Kubernetes 标志等更有效且更易于管理。
如果主机上的资源允许,您可以部署三个 etcd 虚拟机。每个 etcd 虚拟机都应该由不同的物理存储设备支持,或者它们应该使用具有冗余(镜像、RAID 等)的后端存储的独立分区。
如果您的单主机有资源,API 服务器、调度器和控制器管理器的双冗余实例将是下一个升级。
单主机部署选项,从最不适合生产到更好
双主机部署
对于双主机,etcd 的存储问题与单主机相同,您需要冗余。并且您最好运行 3 个 etcd 实例。尽管可能违反直觉,但最好将所有 etcd 节点集中在一台主机上。通过在两台主机上进行 2+1 分割并不能获得可靠性——因为持有多数 etcd 实例的节点丢失会导致停机,无论多数是 2 个还是 3 个。如果主机不相同,则将整个 etcd 集群放在最可靠的主机上。
建议运行冗余的 API 服务器、kube-scheduler 和 kube-controller-manager。这些组件应跨主机部署,以最大程度地降低容器运行时、操作系统和硬件故障带来的风险。
在物理主机上运行虚拟机管理程序层将允许操作具有资源消耗治理的冗余软件组件,并可以带来计划性维护操作优势。
双主机部署选项,从最不适合生产到更好
三(或更多)主机部署——迈向不妥协的生产级服务 建议将 etcd 分布在三台主机上。单个硬件故障将降低应用程序工作负载容量,但不应导致完全服务中断。
对于超大型集群,将需要更多的 etcd 实例。
运行虚拟机管理程序层提供操作优势和更好的工作负载隔离。这超出了本文的范围,但在三台或更多主机级别上,可能会提供高级功能(集群冗余共享存储、带动态负载均衡的资源治理、带实时迁移或故障转移的自动化健康监控)。
三(或更多)主机选项,从最不适合生产到更好
Kubernetes 配置设置
主节点和工作节点应受到保护,防止过载和资源耗尽。虚拟机管理程序功能可用于隔离关键组件和保留资源。还有 Kubernetes 配置设置,可以限制 API 调用速率和每个节点的 Pod 数量等。一些安装套件和商业发行版会处理这些问题,但如果您正在执行自定义 Kubernetes 部署,您可能会发现默认值不合适,特别是当您的资源较少或集群较大时。
控制平面的资源消耗将与 Pod 数量和 Pod 流失率相关。超大型和超小型集群将受益于非默认的 kube-apiserver 请求限流和内存设置。设置过高可能导致请求限制超出和内存不足错误。
在工作节点上,应根据每个节点合理支持的工作负载密度配置 节点可分配资源。可以创建命名空间将工作节点集群细分为多个虚拟集群,并设置资源 CPU 和内存配额。可以配置 kubelet 处理资源不足的情况。
安全
每个 Kubernetes 集群都有一个集群根证书颁发机构 (CA)。控制器管理器、API 服务器、调度器、kubelet 客户端、kube-proxy 和管理员证书需要生成并安装。如果您使用安装工具或发行版,这可能已为您处理。此处介绍了手动过程:https://github.com/kelseyhightower/kubernetes-the-hard-way/blob/master/docs/04-certificate-authority.md。您应该准备好在节点替换或扩展时重新安装证书。
由于 Kubernetes 完全由 API 驱动,因此控制和限制谁可以访问集群以及他们被允许执行哪些操作至关重要。此文档中介绍了加密和身份验证选项。
Kubernetes 应用程序工作负载基于容器镜像。您需要确保这些镜像的来源和内容是可信的。这几乎总是意味着您将托管一个本地容器镜像仓库。从公共互联网拉取镜像可能会带来可靠性和安全问题。您应该选择一个支持镜像签名、安全扫描、对镜像推送和拉取进行访问控制以及活动日志记录的仓库。
必须有支持主机固件、虚拟机管理程序、操作系统、Kubernetes 和其他依赖项更新的流程。应建立版本监控以支持审计。
建议
- 收紧控制平面组件的安全设置,超越默认值(例如,锁定工作节点)
- 利用 Pod 安全策略
- 考虑您的网络解决方案提供的 NetworkPolicy 集成,包括如何实现跟踪、监控和故障排除。
- 使用 RBAC 驱动授权决策和强制执行。
- 考虑物理安全,特别是在部署到可能无人看管的边缘或远程办公地点时。包括存储加密以限制被盗设备的暴露,并防止连接恶意设备(如 USB 密钥)。
- 保护 Kubernetes 明文云提供商凭证(访问密钥、令牌、密码等)
Kubernetes Secret 对象适用于保存少量敏感数据。这些数据保留在 etcd 中。它们可以很容易地用于保存 Kubernetes API 的凭证,但有时工作负载或集群本身的扩展需要更全面的解决方案。如果您需要比内置 Secret 对象提供的更多功能,HashiCorp Vault 项目是一个流行的解决方案。
灾难恢复和备份
通过使用多个主机和虚拟机来实现冗余有助于减少某些类型的停机,但诸如站点范围的自然灾害、错误的更新、被黑客攻击、软件错误或人为错误等情况仍可能导致停机。
生产部署的关键部分是预测未来可能发生的恢复。
值得注意的是,如果您需要在多个站点进行大规模复制部署,那么您在设计、记录和自动化恢复过程方面的一些投入也可能被重新利用。
灾难恢复计划的要素包括备份(以及可能的副本)、替换、计划流程、能够执行流程的人员以及定期培训。定期测试演练和混沌工程原则可用于审计您的准备情况。
您的可用性要求可能要求您保留操作系统、Kubernetes 组件和容器镜像的本地副本,以便即使在互联网中断期间也能进行恢复。“空隙”场景下部署替换主机和节点的能力还可以提供安全性和部署速度优势。
所有 Kubernetes 对象都存储在 etcd 上。定期备份 etcd 集群数据对于在灾难场景下恢复 Kubernetes 集群至关重要,例如丢失所有主节点。
etcd 集群的备份可以通过 etcd 的内置快照机制完成,并将生成的文件复制到不同故障域的存储中。快照文件包含所有 Kubernetes 状态和关键信息。为了确保敏感的 Kubernetes 数据安全,请加密快照文件。
使用基于磁盘卷的 etcd 快照恢复可能会出现问题;请参阅#40027。基于 API 的备份解决方案(例如,Ark)可以提供比 etcd 快照更精细的恢复,但速度也可能更慢。您可以同时使用快照和基于 API 的备份,但至少应执行一种形式的 etcd 备份。
请注意,某些 Kubernetes 扩展可能会在独立的 etcd 集群、持久卷或通过其他机制维护状态。如果此状态至关重要,则应制定备份和恢复计划。
一些关键状态保存在 etcd 之外。证书、容器镜像以及其他与配置和操作相关的状态可能由您的自动化安装/更新工具管理。即使这些项目可以重新生成,备份或复制也可能允许在故障后更快地恢复。考虑对这些项目进行备份并制定恢复计划
- 证书和密钥对
- CA
- API 服务器
- Apiserver-kubelet-client
- ServiceAccount 签名
- “前端代理”
- 前端代理客户端
- 关键 DNS 记录
- IP/子网分配和预留
- 外部负载均衡器
- kubeconfig 文件
- LDAP 或其他身份验证详细信息
- 云提供商特定的账户和配置数据
您的生产工作负载的注意事项
反亲和性规范可用于将集群服务拆分到后端主机,但目前这些设置仅在 Pod 调度时使用。这意味着 Kubernetes 可以重新启动您的集群应用程序的故障节点,但没有原生机制在故障恢复后重新平衡。这是一个值得单独撰写博客的话题,但补充逻辑可能有助于在主机或工作节点恢复或扩展后实现最佳工作负载放置。Pod 优先级和抢占功能可用于在因故障或突发工作负载导致的资源短缺时指定首选的优先级。
对于有状态服务,外部附加卷挂载是 Kubernetes 对非集群服务(例如,典型的 SQL 数据库)的标准建议。目前,Kubernetes 对这些外部卷的快照管理属于路线图功能请求类别,可能与容器存储接口 (CSI) 集成保持一致。因此,对此类服务执行备份将涉及应用程序特定的、容器内的活动,这超出了本文的范围。在等待 Kubernetes 更好地支持快照和备份工作流的同时,将数据库服务运行在虚拟机而不是容器中,并将其暴露给您的 Kubernetes 工作负载可能值得考虑。
集群分布式有状态服务(例如 Cassandra)可以受益于跨主机拆分,如果资源允许,可以使用本地持久卷。这将需要部署多个 Kubernetes 工作节点(可以是虚拟机管理程序主机上的虚拟机)以在单点故障下保持仲裁。
其他注意事项
日志和指标(如果收集并持久保留)对于诊断中断很有价值,但鉴于可用技术的种类繁多,本文将不予讨论。如果 Internet 连接可用,则可能需要将日志和指标外部保留在中心位置。
您的生产部署应使用自动化安装、配置和更新工具(例如,Ansible、BOSH、Chef、Juju、kubeadm、Puppet 等)。手动过程将存在重复性问题、劳动密集、容易出错且难以扩展。经过认证的发行版可能包含在更新中保留配置设置的功能,但如果您实现自己的安装和配置工具链,那么配置工件的保留、备份和恢复至关重要。考虑将部署组件和设置置于版本控制系统(如 Git)下。
中断恢复
记录恢复过程的操作手册应经过测试并离线保存——甚至可以打印出来。当一名值班人员在周五凌晨 2 点被叫醒时,可能不是一个很好的即兴发挥的时机。最好是根据预先计划、经过测试的清单执行——并由远程和现场人员共享访问。
结语
购买商业航空公司的机票既方便又安全。但是当您前往跑道较短的偏远地区时,那趟商业空客 A320 航班就不是一个选择。这并不意味着航空旅行被排除在外。它确实意味着需要做出一些妥协。
航空界的谚语是,在单引擎飞机上,引擎故障意味着坠机。对于双引擎飞机,至少您可以有更多的坠机地点选择。少量主机上的 Kubernetes 也是如此,如果您的业务案例证明其合理性,您可以扩大到更大的混合大小车辆机队(例如,联邦快递、亚马逊)。
那些设计生产级 Kubernetes 解决方案的人有很多选择和决策。一篇博客文章无法提供所有答案,也无法了解您的具体优先级。我们希望这能提供一份值得考虑的事项清单,以及一些有用的指导。有些选项被“搁置”(例如,使用自托管而不是静态 Pod 运行 Kubernetes 组件)。如果有人感兴趣,这些可能会在后续文章中介绍。此外,Kubernetes 的高增强率意味着,如果您的搜索引擎在 2019 年之后发现了这篇文章,某些内容可能已经过期。