本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
我们如何用 Kubernetes 运行 Kubernetes,又名 Kubeception
Giant Swarm 的容器基础设施最初的目标是为开发人员提供一种简便的方式来部署容器化微服务。我们的第一代产品广泛使用 fleet 作为基础设施组件的基础层,并用于调度用户容器。
为了让用户更强大地管理其容器,我们在2016年初将 Kubernetes 引入了我们的堆栈。然而,由于我们需要一种快速、灵活地启动和管理不同用户的 Kubernetes 集群并保持弹性的方式,我们保留了底层 fleet 层。
由于我们坚持在容器中运行所有底层基础设施组件,fleet 为我们提供了使用 systemd 单元文件声明性地定义基础设施组件的灵活性。我们自主开发的部署工具使我们能够部署和管理基础设施,而无需命令式配置管理工具。
然而,fleet 只是一个分布式 init,而不是一个完整的调度和编排系统。除了在工具方面做了大量工作外,它还需要在同行之间的通信、其协调循环和稳定性方面进行显著改进,这是我们必须努力的。此外,Kubernetes 使用率的提高将确保问题更快地被发现和修复。
由于我们在用户端引入 Kubernetes 方面积累了良好的经验,并且最近有了 rktnetes 和 stackanetes 等发展,我们觉得是时候也将我们的基础层迁移到 Kubernetes 了。
为什么要在 Kubernetes 中运行 Kubernetes
现在,您可能会问,为什么有人想在 Kubernetes 集群中运行多个 Kubernetes 集群?我们疯了吗?答案是高级多租户用例以及其可操作性和自动化。
Kubernetes 自身为多租户用例提供了不断增长的功能集。然而,我们的目标是为用户提供一个完全托管的 Kubernetes,而对其使用任何原生 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,它们配置网络桥接,创建证书和令牌,并为未来的集群启动虚拟机。为此,我们使用 KVM 和 qemu 等轻量级技术来提供 CoreOS Container Linux 虚拟机,这些虚拟机将成为内部 Kubernetes 集群的节点。您可以称之为 Kubeception 的第二层。
目前,这意味着我们正在启动带有 Docker 容器的 Pod,这些容器又会启动带有 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 容器中运行。我们目前使用 Jobs 进行网络和证书设置。
查看用户集群内部,您会看到 DNS Pod 和一个 helloworld 正在运行。
这些用户集群中的每一个都可以独立调度和使用。它们可以按需启动和关闭。
结论
总而言之,我们展示了 Kubernetes 如何不仅能够轻松地自托管,还能灵活地调度多个内部 Kubernetes 集群,同时确保更高的隔离性和安全性。此设置的一个亮点是安装的可组合性和自动化以及 Kubernetes 组件之间强大的协调。这使我们能够按需轻松创建、销毁和重新调度集群,而不会影响用户或损害基础设施的安全性。它还允许我们通过在集群创建时更改一些参数来启动具有不同大小和配置甚至版本的集群。
此设置仍处于早期阶段,我们的路线图计划在许多领域进行改进,例如透明升级、集群的动态重新配置和扩展、性能改进以及(更多)安全性。此外,我们期待通过利用不断发展的 Kubernetes 操作工具和即将推出的功能(例如 Init 容器、计划任务、Pod 和节点亲和性以及反亲和性等)来改进我们的设置。
最重要的是,我们正在努力使内部 Kubernetes 集群成为第三方资源,然后可以通过自定义控制器进行管理。结果将非常类似于 CoreOS 的 Operator 概念。为了确保广大社区能够从这个项目中受益,我们将在不久的将来将其开源。