本文超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。
我们如何在 Kubernetes 中运行 Kubernetes,又名 Kubeception
Giant Swarm 的容器基础架构最初的目标是为开发人员提供一种简单的方式来部署容器化的微服务。我们的第一代广泛使用 fleet 作为我们基础架构组件以及调度用户容器的基础层。
为了给我们的用户提供一种更强大的方式来管理他们的容器,我们在 2016 年初将 Kubernetes 引入到我们的堆栈中。然而,由于我们需要一种快速灵活地启动和管理不同用户的 Kubernetes 集群并使其具有弹性的方法,我们保留了底层的 fleet 层。
由于我们坚持在容器中运行所有底层基础架构组件,fleet 使我们能够灵活地使用 systemd 单元文件以声明方式定义我们的基础架构组件。我们自主开发的部署工具使我们能够在无需命令式配置管理工具的情况下部署和管理基础架构。
然而,fleet 只是一个分布式初始化系统,而不是一个完整的调度和编排系统。除了我们在工具方面的大量工作外,它还需要在对等通信、协调循环和稳定性方面进行重大改进,而我们必须致力于这些方面。此外,Kubernetes 使用量的增加将确保更快地发现和修复问题。
由于我们在用户端引入 Kubernetes 方面取得了良好的经验,并且随着 rktnetes 和 stackanetes 等最新发展,我们觉得是时候将我们的基础层也迁移到 Kubernetes 了。
为什么在 Kubernetes 中使用 Kubernetes
现在,你可能会问,为什么有人想要在 Kubernetes 集群内部运行多个 Kubernetes 集群?我们疯了吗?答案是高级多租户用例以及其可操作性和自动化。
Kubernetes 自带了不断增长的多租户用例功能集。然而,我们的目标是为用户提供完全托管的 Kubernetes,而不会对其使用任何 vanilla Kubernetes 环境(包括对节点的特权访问)的功能造成任何限制。此外,在更大的企业场景中,单个 Kubernetes 集群及其内置的隔离机制通常不足以满足合规性和安全要求。更高级的(防火墙)分区或分层安全概念很难通过单一安装来实现。 使用命名空间隔离,特权访问和防火墙区域都很难在不绕过安全措施的情况下实现。
现在你可以去建立多个完全独立(和联合)的 Kubernetes 安装。然而,自动化这些集群的部署和管理将需要额外的工具和复杂的监控设置。此外,我们希望能够按需启动和关闭集群、扩展它们、更新它们、跟踪哪些集群可用,并能够灵活地将它们分配给组织和团队。 事实上,这种设置可以与联邦控制平面相结合,通过一个 API 端点将部署联合到集群。
如果有一个 API 和前端来处理这些事情,那岂不是很棒?
进入 Giantnetes
基于上述要求,我们着手构建我们所谓的 Giantnetes——或者如果你喜欢电影,Kubeception。在最基本的抽象层面上,它是一个外部 Kubernetes 集群(实际的 Giantnetes),用于运行和管理多个完全隔离的用户 Kubernetes 集群。
物理机是通过使用我们的 CoreOS Container Linux 引导工具 Mayu 引导的。Giantnetes 组件本身是自托管的,即 kubelet 负责自动引导驻留在 manifests 文件夹中的组件。你可以称之为 Kubeception 的第一层。
一旦 Giantnetes 集群运行,我们就使用它来调度用户 Kubernetes 集群以及我们用于管理和保护它们的工具。
我们选择 Calico 作为 Giantnetes 网络插件,以确保在 Giantnetes 上运行的所有应用程序的安全、隔离和正确的性能。
然后,为了创建内部 Kubernetes 集群,我们启动了一些 Pod,这些 Pod 配置网络桥接器、创建证书和令牌,并为未来的集群启动虚拟机。为此,我们使用 KVM 和 qemu 等轻量级技术来配置 CoreOS Container Linux 虚拟机,这些虚拟机将成为内部 Kubernetes 集群的节点。你可以称之为 Kubeception 的第二层。
目前这意味着我们正在使用 Docker 容器启动 Pod,而 Docker 容器反过来又使用 KVM 和 qemu 启动虚拟机。但是,我们正在研究使用 rkt qemu-kvm 来实现这一点,这将导致我们的 Giantnetes 使用 rktnetes 设置。
内部 Kubernetes 集群的网络解决方案有两个层次。它结合了 flannel 的服务器/客户端架构模型和 Calico BGP。 flannel 客户端用于在每个虚拟化内部 Kubernetes 集群的虚拟机之间创建网络桥接器,而 Calico 在虚拟机内部运行以连接不同的 Kubernetes 节点并为内部 Kubernetes 创建单个网络。通过使用 Calico,我们在每个 Kubernetes 集群内部模仿 Giantnetes 网络解决方案,并提供通过 Kubernetes 网络策略 API 保护和隔离工作负载的原语。
关于安全性,我们的目标是尽可能地分离权限并使事情可审计。目前这意味着我们使用证书来保护对集群的访问,并加密构成集群的所有组件之间的通信(即虚拟机到虚拟机、Kubernetes 组件之间、etcd 主服务器到 Calico 工作器等)。为此,我们为每个集群创建一个 PKI 后端,然后按需在 Vault 中为每个服务颁发证书。每个组件都使用不同的证书,因此,如果任何组件或节点遭到入侵,可以避免暴露整个集群。我们还会定期轮换证书。
为了确保从外部访问每个内部 Kubernetes 集群的 API 和服务,我们在 Giantnetes 中运行一个多级 HAproxy 入口控制器设置,该设置将 Kubernetes 虚拟机连接到硬件负载均衡器。
使用 kubectl 查看 Giantnetes
让我们看一下 Giantnetes 的最小示例部署。
在上面的示例中,您看到一个用户 Kubernetes 集群 customera
在 Giantnetes 之上的 VM 容器中运行。我们目前将作业用于网络和证书设置。
窥视用户集群内部,您会看到 DNS pod 和一个正在运行的 helloworld。
这些用户集群中的每一个都可以独立调度和使用。它们可以按需启动和关闭。
结论
总而言之,我们可以展示 Kubernetes 如何能够轻松地不仅自托管,还能灵活地调度多个内部 Kubernetes 集群,同时确保更高的隔离性和安全性。此设置中的一个亮点是安装的可组合性和自动化性以及 Kubernetes 组件之间的稳健协调。这使我们能够轻松地按需创建、销毁和重新调度集群,而不会影响用户或损害基础架构的安全性。通过在集群创建时更改一些参数,它还允许我们启动具有不同大小和配置甚至版本的集群。
此设置仍处于早期阶段,我们的路线图计划在许多领域进行改进,例如透明升级、集群的动态重新配置和扩展、性能改进以及(更多)安全性。此外,我们期待通过利用 Kubernetes 操作工具和即将推出的功能(如 Init 容器、计划作业、Pod 和节点亲和性和反亲和性等)的不断发展来改进我们的设置。
最重要的是,我们正在努力使内部 Kubernetes 集群成为第三方资源,然后可以通过自定义控制器进行管理。结果将与 CoreOS 的 Operator 概念 非常相似。为了确保整个社区能够从该项目中受益,我们将在不久的将来开源它。