这篇文章已发布超过一年。旧文章可能包含过时的内容。请检查页面中的信息自发布以来是否已失效。
DIY:使用 Kubernetes 创建你自己的云(第三部分)
到了最有趣的部分,本文深入探讨了在 Kubernetes 中运行 Kubernetes 的主题。重点介绍了 Kamaji 和 Cluster API 等技术,以及它们与 KubeVirt 的集成。
先前的讨论涵盖了在裸金属上准备 Kubernetes 以及如何将 Kubernetes 变成虚拟机管理系统。本文通过解释如何利用上述所有技术,构建一个功能齐全的托管式 Kubernetes,并通过点击即可运行虚拟 Kubernetes 集群,从而结束本系列。
首先,让我们深入了解 Cluster API。
Cluster API
Cluster API 是 Kubernetes 的一个扩展,它允许在另一个 Kubernetes 集群中将 Kubernetes 集群作为自定义资源进行管理。
Cluster API 的主要目标是提供一个统一的接口,用于描述 Kubernetes 集群的基本实体并管理它们的生命周期。这使得创建、更新和删除集群的过程自动化,简化了扩缩容和基础设施管理。
在 Cluster API 的语境中,有两个术语:管理集群和租户集群。
- 管理集群是用于部署和管理其他集群的 Kubernetes 集群。此集群包含所有必需的 Cluster API 组件,并负责描述、创建和更新租户集群。它通常仅用于此目的。
- 租户集群是用户集群或使用 Cluster API 部署的集群。它们通过在管理集群中描述相关资源来创建。然后,终端用户可以使用它们部署应用程序和服务。
重要的是要理解,在物理上,租户集群不一定必须与管理集群运行在相同的基础设施上;更多时候,它们运行在别处。
一张图表显示了使用 Cluster API 的管理 Kubernetes 集群和租户 Kubernetes 集群之间的交互
为了运行,Cluster API 利用了“提供者”(providers)的概念,这些提供者是独立的控制器,负责正在创建的集群的特定组件。Cluster API 中有几种类型的提供者。主要的提供者有:
- 基础设施提供者,负责提供计算基础设施,例如虚拟机或物理服务器。
- 控制平面提供者,提供 Kubernetes 控制平面,即 kube-apiserver、kube-scheduler 和 kube-controller-manager 组件。
- 引导提供者,用于为正在创建的虚拟机和服务器生成 cloud-init 配置。
要开始使用,您需要安装 Cluster API 本身以及每种类型的一个提供者。您可以在项目的文档中找到受支持提供者的完整列表。
对于安装,您可以使用 clusterctl
工具,或者使用更具声明性的方法,即Cluster API Operator。
选择提供者
基础设施提供者
要使用 KubeVirt 运行 Kubernetes 集群,必须安装KubeVirt 基础设施提供者。它允许在 Cluster API 运行的同一管理集群中部署用于工作节点的虚拟机。
控制平面提供者
Kamaji 项目为在管理集群中以容器形式运行租户集群的 Kubernetes 控制平面提供了现成的解决方案。这种方法有几个显著优势:
- 成本效益:在容器中运行控制平面避免了为每个集群使用单独的控制平面节点,从而显著降低了基础设施成本。
- 稳定性:通过消除复杂的多层部署方案来简化架构。无需按顺序启动虚拟机然后在其中安装 etcd 和 Kubernetes 组件,而是有一个简单的控制平面,它作为常规应用程序部署并在 Kubernetes 中运行,并由一个 Operator 管理。
- 安全性:集群的控制平面对终端用户隐藏,降低了其组件被攻破的可能性,同时也消除了用户访问集群证书存储的权限。这种对用户不可见的控制平面组织方式常被云提供商采用。
引导提供者
将Kubeadm 作为引导提供者 - 这是在 Cluster API 中准备集群的标准方法。该提供者是 Cluster API 本身的一部分。它只需要一个安装了 kubelet 和 kubeadm 的预备系统镜像,并允许生成 cloud-init 和 ignition 格式的配置。
值得注意的是,Talos Linux 也支持通过 Cluster API 进行供应,并为此提供了提供者。虽然之前的文章讨论了使用 Talos Linux 在裸金属节点上设置管理集群,但在供应租户集群方面,Kamaji+Kubeadm 方法有更多优势。它方便了在容器中部署 Kubernetes 控制平面,从而消除了为控制平面实例使用单独虚拟机体的需求。这简化了管理并降低了成本。
工作原理
Cluster API 中的主要对象是 Cluster 资源,它作为所有其他资源的父级。通常,此资源会引用另外两个资源:描述控制平面的资源和描述基础设施的资源,每个资源都由单独的提供者管理。
与 Cluster 不同,这两个资源不是标准化的,它们的种类取决于您使用的特定提供者:
一张图表显示了 Cluster API 中 Cluster 资源及其关联资源的关系
在 Cluster API 中,还有一个名为 MachineDeployment 的资源,它描述了一组节点,无论是物理服务器还是虚拟机。此资源的功能类似于标准的 Kubernetes 资源,例如 Deployment、ReplicaSet 和 Pod,提供了一种机制来声明性地描述一组节点并进行自动扩缩容。
换句话说,MachineDeployment 资源允许您声明性地描述集群的节点,根据指定的参数和请求的副本数量自动创建、删除和更新它们。
一张图表显示了 Cluster API 中 MachineDeployment 资源及其子资源的关系
为了创建机器,MachineDeployment 会引用一个用于生成机器本身的模板以及一个用于生成其 cloud-init 配置的模板:
一张图表显示了 Cluster API 中 MachineDeployment 资源及其关联资源的关系
要使用 Cluster API 部署新的 Kubernetes 集群,您需要准备以下一组资源:
- 一个通用的 Cluster 资源
- 一个 KamajiControlPlane 资源,负责由 Kamaji 运行的控制平面
- 一个 KubevirtCluster 资源,描述 KubeVirt 中的集群配置
- 一个 KubevirtMachineTemplate 资源,负责虚拟机模板
- 一个 KubeadmConfigTemplate 资源,负责生成 token 和 cloud-init
- 至少一个 MachineDeployment 来创建一些工作节点
完善集群
在大多数情况下,这些就足够了,但根据所使用的提供者不同,您可能还需要其他资源。您可以在Kamaji 项目文档中找到为每种类型的提供者创建的资源示例。
在此阶段,您已经拥有了一个就绪的租户 Kubernetes 集群,但到目前为止,它除了 API 工作进程和一些 Kubernetes 集群安装中标准包含的核心插件:kube-proxy 和 CoreDNS 之外,没有其他内容。要实现完全集成,您还需要安装更多组件:
要安装其他组件,您可以使用单独的Cluster API Helm 插件提供者,或者使用之前的文章中讨论过的 FluxCD。
在 FluxCD 中创建资源时,可以通过引用 Cluster API 生成的 kubeconfig 来指定目标集群。然后,安装将直接在该集群中执行。因此,FluxCD 成为一个通用的工具,用于管理管理集群和用户租户集群中的资源。
一张图表显示了 FluxCD 的交互示意图,它可以将组件安装到管理 Kubernetes 集群和租户 Kubernetes 集群中
这里讨论的是哪些组件?一般来说,这组组件包括以下内容:
CNI 插件
为了确保租户 Kubernetes 集群中的 Pod 之间能够通信,需要部署一个 CNI 插件。该插件创建一个虚拟网络,使 Pod 能够相互交互,并且传统上作为 Daemonset 部署在集群的工作节点上。您可以选择并安装任何您认为合适的 CNI 插件。
一张图表显示了在嵌套 Kubernetes 集群示意图中安装在租户 Kubernetes 集群内部的 CNI 插件
Cloud Controller Manager
Cloud Controller Manager (CCM) 的主要任务是将 Kubernetes 与云基础设施提供商的环境集成(在您的案例中,它是用于供应所有租户 Kubernetes 工作节点的管理 Kubernetes 集群)。它执行的一些任务如下:
- 当创建 LoadBalancer 类型的 Service 时,CCM 会启动创建云负载均衡器的过程,该负载均衡器将流量引导到您的 Kubernetes 集群。
- 如果从云基础设施中移除一个节点,CCM 会确保将其也从您的集群中移除,从而维护集群的当前状态。
- 使用 CCM 时,节点会带着特殊的污点 (taint)
node.cloudprovider.kubernetes.io/uninitialized
添加到集群中,如果需要,这允许处理额外的业务逻辑。成功初始化后,此污点会从节点上移除。
根据云提供商的不同,CCM 可以在租户集群内部或外部运行。
KubeVirt 云提供者被设计为安装在外部父级管理集群中。因此,在租户集群中创建 LoadBalancer 类型的 Service 会触发在父级集群中创建 LoadBalancer Service,这些 Service 将流量引导到租户集群。
一张图表显示了在嵌套 Kubernetes 集群示意图中安装在租户 Kubernetes 集群外部的 Cloud Controller Manager,以及它如何将父级 Kubernetes 集群中管理的 Service 映射到子级 Kubernetes 集群
CSI 驱动程序
容器存储接口 (CSI) 分为两个主要部分,用于在 Kubernetes 中与存储进行交互:
- csi-controller:此组件负责与云提供商的 API 进行交互,以创建、删除、挂载、卸载和调整卷的大小。
- csi-node:此组件在每个节点上运行,并根据 kubelet 的请求协助将卷挂载到 Pod 中。
在使用KubeVirt CSI 驱动程序时,出现了一个独特的机会。由于 KubeVirt 中的虚拟机运行在管理 Kubernetes 集群内部,而该集群提供了功能齐全的 Kubernetes API,这为在用户租户集群外部运行 csi-controller 打开了通道。这种方法在 KubeVirt 社区中很受欢迎,并提供了几个关键优势:
- 安全性:此方法将内部云 API 对终端用户隐藏,仅通过 Kubernetes 接口提供对资源的访问。因此,它降低了用户集群直接访问管理集群管理 API 的风险。
- 简单性和便利性:用户无需在其集群中管理额外的控制器,简化了架构并减轻了管理负担。
但是,CSI-node 必须运行在租户集群内部,因为它直接与每个节点上的 kubelet 交互。该组件负责将卷挂载和卸载到 Pod 中,需要与直接发生在集群节点上的进程紧密集成。
KubeVirt CSI 驱动程序充当卷编排的代理。当在租户集群内部创建一个 PVC 时,会在管理集群中创建一个 PVC,然后创建的 PV 连接到虚拟机。
一张图表显示了在嵌套 Kubernetes 集群示意图中,安装在租户 Kubernetes 集群内部和外部的 CSI 插件组件,以及它如何将父级 Kubernetes 集群中管理的持久卷映射到子级 Kubernetes 集群
Cluster Autoscaler
Cluster Autoscaler 是一个多功能的组件,可以与各种云 API 配合使用,它与 Cluster-API 的集成只是其中一项功能。为了正确配置,它需要访问两个集群:租户集群(用于跟踪 Pod 并确定是否需要添加新节点),以及管理 Kubernetes 集群(management kubernetes cluster)(在该集群中与 MachineDeployment 资源交互并调整副本数量)。
尽管 Cluster Autoscaler 通常在租户 Kubernetes 集群内部运行,但在这种情况下,出于之前描述的相同原因,建议将其安装在外部。这种方法更易于维护,也更安全,因为它阻止了租户集群的用户访问管理集群的管理 API。
一张图表显示了在嵌套 Kubernetes 集群示意图中安装在租户 Kubernetes 集群外部的 Cluster Autoscaler
Konnectivity
还有一个我想提及的额外组件 - Konnectivity。您以后很可能需要它来使您的租户 Kubernetes 集群中的 webhooks 和 API 聚合层正常工作。这个主题在我的之前一篇文章中详细讨论过。
与上面介绍的组件不同,Kamaji 允许您轻松启用 Konnectivity,并将其作为租户集群的核心组件之一进行管理,与 kube-proxy 和 CoreDNS 并列。
总结
现在您拥有一个功能齐全的 Kubernetes 集群,具备动态扩缩容、自动卷供应和负载均衡的能力。
接下来,您可能需要考虑从租户集群收集指标和日志,但这超出了本文的范围。
当然,部署 Kubernetes 集群所需的所有组件都可以打包成一个 Helm Chart,并作为统一的应用程序进行部署。这正是我们在开放 PaaS 平台 Cozystack 上通过点击按钮来组织托管 Kubernetes 集群部署的方式,您可以在这里免费尝试文章中描述的所有技术。