本文已超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。
Gardener 项目更新
去年,我们在Kubernetes 社区会议和Kubernetes 博客上的一篇文章中介绍了 Gardener。在 SAP,我们运行 Gardener 已经超过两年了,并且成功地在所有主要超大规模厂商以及通过收购加入企业的众多基础设施和私有云中管理着数千个各种版本的符合性集群。
我们经常被问到为什么少量动态可扩展集群不足以满足需求。我们在开始 Kubernetes 之旅时也有类似的想法。但是我们意识到,将 Kubernetes 的架构和原则应用于生产场景,我们的内部和外部客户很快就需要对关注点和所有权进行合理的划分,这在大多数情况下导致了多个集群的使用。因此,可扩展且受管理的 Kubernetes 即服务解决方案通常也是采用的基础。特别是当一个大型组织在不同的提供商和不同的地区运行多个产品时,集群的数量将迅速增加到数百甚至数千个。
今天,我们想更新一下过去一年我们在可扩展性和可定制性方面所做的工作,以及我们计划在下一个里程碑中进行的工作。
简短回顾:什么是 Gardener?
Gardener 的主要原则是利用 Kubernetes 原语进行所有操作,通常被称为 inception 或 kubeception。社区的反馈是,最初我们的架构图看起来“令人难以置信”,但在对材料进行了一些研究后,我们所做的一切都是“Kubernetes 方式”。人们可以重用所有关于 API、控制循环等的知识。
基本的想法是,使用所谓的 种子 集群来托管最终用户集群(植物学上称为 芽 )的控制平面。
Gardener 以同质方式提供独立于底层基础设施提供商的 vanilla Kubernetes 集群作为服务,利用上游提供的 k8s.gcr.io/*
镜像作为开放分发*(更新:k8s.gcr.io
已被弃用,取而代之的是 registry.k8s.io
)。* 该项目完全基于 Kubernetes 扩展概念构建,因此添加了一个自定义 API 服务器、一个控制器管理器和一个调度程序来创建和管理 Kubernetes 集群的生命周期。它使用自定义资源扩展了 Kubernetes API,最突出的是 Gardener 集群规范(Shoot
资源),该规范可以以声明式方式“订购”一个 Kubernetes 集群(用于第 1 天,但也协调第 2 天的所有管理活动)。
通过利用 Kubernetes 作为基础架构,我们能够设计出一个组合的水平和垂直 Pod 自动缩放器 (HVPA),当配置自定义启发式方法时,它可以自动向上/向下或向外/向内扩展所有控制平面组件。这使得可以快速横向扩展,甚至超出通常一些固定数量的主节点的容量。与其他许多 Kubernetes 集群配置工具相比,此架构特性是主要区别之一。但在我们的生产中,Gardener 不仅通过对控制平面进行合并打包来有效降低总拥有成本。它还简化了“第 2 天操作”(如集群更新或稳健性质量)的实现。同样,主要是通过依赖所有成熟的 Kubernetes 特性和功能。
Gardener 新引入的扩展概念现在使提供商只需维护其特定的扩展,而无需在核心源代码树中进行开发。
可扩展性
由于过去几年的发展,Kubernetes 代码库中包含了大量特定于提供商的代码,这些代码现在正从其核心源代码树中外部化。Project Gardener 也发生了同样的情况:随着时间的推移,积累了许多关于云提供商、操作系统、网络插件等的细节。通常,这会导致在可维护性、可测试性或新版本方面的工作量显着增加。我们的社区成员 Packet 为他们的基础设施贡献了Gardener 支持,并遭受了上述缺点。
因此,类似于 Kubernetes 社区决定将他们的云控制器管理器移出树外,或将卷插件移至 CSI 等,Gardener 社区提议并实现了类似的扩展概念。Gardener 核心源代码树现在没有任何提供商的细节,允许供应商仅专注于其基础设施细节,并使核心贡献者再次变得更加敏捷。
通常,设置集群需要一系列相互依赖的步骤,从生成证书和准备基础设施开始,继续到配置控制平面和工作节点,最后到部署系统组件。我们想在这里强调的是,所有这些步骤都是必要的(参见Kubernetes the Hard Way),并且所有 Kubernetes 集群创建工具都以一种或另一种方式(在一定程度上是自动化的)实现相同的步骤。
Gardener 的可扩展性概念的总体思路是使 此流程 更通用,并为每个步骤刻画出自定义资源,这些资源可以作为理想的扩展点。

图 1 带有扩展点的集群协调流程。
借助 Gardener 的流程框架,我们隐式地为所有基础设施和集群的所有可能状态提供了一个可重现的状态机。
Gardener 的可扩展性方法定义了自定义资源,这些资源可作为以下类别的理想扩展点
- DNS 提供商(例如,Route53、CloudDNS 等),
- Blob 存储提供商(例如,S3、GCS、ABS 等),
- 基础设施提供商(例如,AWS、GCP、Azure 等),
- 操作系统(例如,CoreOS Container Linux、Ubuntu、FlatCar Linux 等),
- 网络插件(例如,Calico、Flannel、Cilium 等),
- 非必要扩展(例如,Let's Encrypt 证书服务)。
扩展点
除了利用自定义资源定义外,我们还有效地在种子集群中使用变异/验证 webhook。扩展控制器本身在这些集群中运行,并对它们负责的 CRD 和工作负载资源(如 Deployment
、StatefulSet
等)做出反应。与集群 API 的方法类似,这些 CRD 也可能包含特定于提供商的信息。
步骤 2 到 10 [参见图 1] 涉及特定于基础设施的元数据,这些元数据指的是特定于基础设施的实现,例如,对于 DNS 记录,可能有 aws-route53
、google-clouddns
,或者对于隔离的网络,甚至有 openstack-designate
等等。我们将在接下来的段落中检查步骤 4 和 6,作为一般概念的示例(基于 AWS 的实现)。如果您有兴趣,可以在我们的可扩展性文档中阅读完整记录的 API 合约。
示例:Infrastructure
CRD
AWS 上的 Kubernetes 集群需要一定的基础设施准备才能使用。这包括,例如,创建 VPC、子网等。Infrastructure
CRD 的目的是触发此准备工作。
apiVersion: extensions.gardener.cloud/v1alpha1
kind: Infrastructure
metadata:
name: infrastructure
namespace: shoot--foobar--aws
spec:
type: aws
region: eu-west-1
secretRef:
name: cloudprovider
namespace: shoot--foobar—aws
sshPublicKey: c3NoLXJzYSBBQUFBQ...
providerConfig:
apiVersion: aws.provider.extensions.gardener.cloud/v1alpha1
kind: InfrastructureConfig
networks:
vpc:
cidr: 10.250.0.0/16
zones:
- name: eu-west-1a
internal: 10.250.112.0/22
public: 10.250.96.0/22
workers: 10.250.0.0/19
基于 Shoot
资源,Gardener 创建此 Infrastructure
资源,作为其协调流程的一部分。AWS 特定的 providerConfig
是最终用户在 Shoot
资源中的配置的一部分,不由 Gardener 评估,而只是传递给种子集群中的扩展控制器。
在其当前实现中,AWS 扩展在 eu-west-1a
区域中创建一个新的 VPC 和三个子网。此外,它还会创建一个 NAT 和互联网网关、弹性 IP、路由表、安全组、IAM 角色、实例配置文件和一个 EC2 密钥对。
完成其任务后,它将报告状态和一些特定于提供商的输出。
apiVersion: extensions.gardener.cloud/v1alpha1
kind: Infrastructure
metadata:
name: infrastructure
namespace: shoot--foobar--aws
spec: ...
status:
lastOperation:
type: Reconcile
state: Succeeded
providerStatus:
apiVersion: aws.provider.extensions.gardener.cloud/v1alpha1
kind: InfrastructureStatus
ec2:
keyName: shoot--foobar--aws-ssh-publickey
iam:
instanceProfiles:
- name: shoot--foobar--aws-nodes
purpose: nodes
roles:
- arn: "arn:aws:iam::<accountID>:role/shoot..."
purpose: nodes
vpc:
id: vpc-0815
securityGroups:
- id: sg-0246
purpose: nodes
subnets:
- id: subnet-1234
purpose: nodes
zone: eu-west-1b
- id: subnet-5678
purpose: public
zone: eu-west-1b
providerStatus
中的信息可以在后续步骤中使用,例如,配置 cloud-controller-manager 或检测 machine-controller-manager。
示例:部署集群控制平面
Gardener 的主要功能之一是它在不同基础设施上管理的集群的同质性。因此,它仍然负责将提供商无关的控制平面组件部署到种子集群中(例如 etcd、kube-apiserver)。提供商特定的控制平面组件(如 cloud-controller-manager 或 CSI 控制器)的部署由专用的 ControlPlane
CRD 触发。但是,在本段中,我们希望关注标准组件的自定义。
让我们关注 kube-apiserver 和 kube-controller-manager Deployment
。我们的 Gardener AWS 扩展尚未使用 CSI,而是依赖于树内 EBS 卷插件。因此,它需要启用 PersistentVolumeLabel
准入插件,并向 kube-apiserver 提供云提供商配置。类似地,将指示 kube-controller-manager 使用其树内卷插件。
kube-apiserver Deployment
包含 kube-apiserver
容器,并由 Gardener 这样部署
containers:
- command:
- /hyperkube
- apiserver
- --enable-admission-plugins=Priority,...,NamespaceLifecycle
- --allow-privileged=true
- --anonymous-auth=false
...
使用 MutatingWebhookConfiguration
,AWS 扩展注入上述标志并按如下方式修改规范
containers:
- command:
- /hyperkube
- apiserver
- --enable-admission-plugins=Priority,...,NamespaceLifecycle,PersistentVolumeLabel
- --allow-privileged=true
- --anonymous-auth=false
...
- --cloud-provider=aws
- --cloud-config=/etc/kubernetes/cloudprovider/cloudprovider.conf
- --endpoint-reconciler-type=none
...
volumeMounts:
- mountPath: /etc/kubernetes/cloudprovider
name: cloud-provider-config
volumes:
- configMap:
defaultMode: 420
name: cloud-provider-config
name: cloud-provider-config
kube-controller-manager Deployment
以类似的方式处理。
种子集群中的 Webhook 可用于修改与 Gardener 部署的 shoot 集群控制平面或任何其他扩展相关的任何内容。如果扩展控制器需要自定义 Gardener 部署的系统组件,则在 shoot 集群中存在类似 webhook 的概念。
注册扩展控制器
Gardener API 使用两个特殊资源来注册和安装扩展。注册本身通过 ControllerRegistration
资源声明。最简单的选择是定义 Helm 图表以及一些用于渲染图表的值,但是,任何其他部署机制也通过自定义代码支持。
Gardener 确定特定种子集群中是否需要扩展控制器,并创建一个 ControllerInstallation
,用于触发部署。
到目前为止,每个注册的扩展控制器都部署到每个种子集群,这通常不是必需的。将来,Gardener 将变得更具选择性,仅部署特定种子集群上所需的扩展。
我们的动态注册方法允许在运行的系统中添加或删除扩展,而无需重建或重新启动任何组件。

图 2 带有扩展控制器的 Gardener 架构。
现状
我们最近引入了新的 core.gardener.cloud
API 组,该组包含完全向前和向后兼容的 Shoot
资源,并允许提供商使用 Gardener,而无需修改其核心源代码树中的任何内容。
我们已经调整了所有控制器以使用这个新的 API 组,并已弃用旧的 API。最终,几个月后我们将删除它,因此建议最终用户尽快开始迁移到新的 API。
除此之外,我们已经使所有相关的扩展都能够为 shoot 健康状态做出贡献,并实现了相应的合同。基本思想是 CRD 可能具有 .status.conditions
,这些条件由 Gardener 拾取并与其标准健康检查合并到 Shoot
状态字段中。
此外,我们希望实现一些易于使用的库函数,以便于 CRD 的默认和验证 webhook,从而验证最终用户控制的 providerConfig
字段。
最后,我们将把 gardener/gardener-extensions
存储库拆分为单独的存储库,并仅将其保留用于可用于编写扩展控制器的通用库函数。
下一步
Kubernetes 已经外化了许多基础设施管理挑战。初始设计通过将生命周期操作委托给单独的管理平面(种子集群)来解决其中的大多数问题。但是,如果 garden 集群或种子集群发生故障怎么办?我们如何扩展到需要并行协调的数万个受管集群?我们将进一步投资以加强 Gardener 的可扩展性和灾难恢复功能。让我们简要地详细介绍三个功能
Gardenlet
从 Gardener 项目一开始,我们就开始实现 operator 模式:我们有一个自定义的控制器管理器,它作用于我们自己的自定义资源。现在,当您开始考虑 Gardener 架构时,您会认识到与 Kubernetes 架构有一些有趣的相似之处:可以将 Shoot 集群与 Pod 进行比较,并且可以将种子集群视为工作节点。在这一观察的指导下,我们引入了 gardener-scheduler。它的主要任务是找到合适的种子集群来托管新订购集群的控制平面,类似于 kube-scheduler 如何为新创建的 Pod 找到合适的节点。通过为区域(或提供商)提供多个种子集群并分配工作负载,我们还减少了潜在故障的爆炸半径。

图 3 Kubernetes 和 Gardener 架构之间的相似性。
但是,Kubernetes 和 Gardener 架构之间仍然存在显着差异:Kubernetes 在每个节点上运行一个主要的“代理”kubelet,它主要负责管理其特定节点上的 Pod 和容器。Gardener 使用其控制器管理器,该管理器负责所有种子集群上的所有 shoot 集群,并且它从 garden 集群集中执行其协调循环。
虽然这对于当今数千个集群的规模来说效果很好,但我们的目标是按照 Kubernetes 原则实现真正的可扩展性(超出单个控制器管理器的容量):我们现在正在努力将逻辑(或 Gardener 运算符)分配到种子集群中,并将引入一个相应的组件,适当命名为 gardenlet。它将是 Gardener 在每个种子集群上的主要“代理”,并且仅负责位于其特定种子集群中的 shoot 集群。
gardener-controller-manager 将仍然保留其对 Gardener API 的其他资源的控制循环,但是,它将不再与种子/shoot 集群通信。
反转控制流甚至允许将种子/shoot 集群放置在防火墙后面,而无需直接访问(通过 VPN 隧道)。

图 4 带有 Gardenlet 的详细架构。
种子集群之间的控制平面迁移
当种子集群发生故障时,用户的静态工作负载将继续运行。但是,由于在发生故障的种子中运行的 shoot 集群的 API 服务器不再可访问,因此不再可能管理集群。
我们已经实现了将某些种子灾难影响的失败控制平面重新定位到另一个种子,并且现在正在努力完全自动化此独特功能。事实上,这种方法不仅可行,而且我们在生产中多次执行了故障转移过程。
自动化故障转移功能将使我们能够实现更全面的灾难恢复和可扩展性质量,例如,自动配置和重新平衡种子集群或针对所有不可预见情况的自动迁移。再次考虑 Kubernetes 在 Pod 驱逐和节点排空方面的相似之处。
Gardener Ring
Gardener Ring 是我们用于配置和管理 Kubernetes 集群的新颖方法,而无需依赖外部配置工具进行初始集群。通过以递归方式使用 Kubernetes,我们可以通过避免强制性工具集来大幅降低管理复杂性,同时使用自我稳定的循环系统创建新的质量。
Ring 方法在概念上不同于自托管和基于静态 Pod 的部署。这个想法是创建一个由三个(或更多)shoot 集群组成的环,每个集群都托管其后继者的控制平面。
一个集群的中断不会影响 Ring 的稳定性和可用性,并且由于控制平面已外部化,因此失败的集群可以由 Gardener 的自我修复功能自动恢复。只要有至少 n/2+1
个可用集群的法定人数,Ring 将始终自行稳定。在不同的云提供商(或至少在不同的区域/数据中心)上运行这些集群会减少法定人数损失的可能性。

图 5 Kubernetes 集群的自我稳定环。
Gardener 的分布式实例如何共享相同数据的方式是通过部署与同一个 etcd 集群通信的单独的 kube-apiserver 实例。这些 kube-apiserver 形成一个无节点的 Kubernetes 集群,该集群可以用作 Gardener 及其相关应用程序的“数据容器”。
我们正在运行由 Ring 内部保护的测试环境,它使我们免于手动干预。通过自动化控制平面迁移,我们可以轻松地引导 Ring 并解决“初始集群问题”,并提高整体稳健性。
开始使用!
如果您有兴趣编写扩展程序,您可能需要查看以下资源
- GEP-1:可扩展性提案文档
- GEP-4:新的
core.gardener.cloud/v1alpha1
API - 适用于 AWS 的示例扩展控制器实现
- Gardener 扩展 Golang 库
- 扩展合约文档
- Gardener API 参考
当然,我们也非常欢迎您对我们的项目做出任何其他贡献!我们一直在寻找新的社区成员。
如果您想尝试 Gardener,请查看我们的快速安装指南。此安装程序将设置一个完整的 Gardener 环境,只需几分钟即可用于测试和评估。
欢迎贡献!
Gardener 项目以开源形式开发并托管在 GitHub 上:https://github.com/gardener
如果您看到 Gardener 项目的潜力,请通过 GitHub 加入我们。
我们每周五中欧时间上午 10-11 点举行公开社区会议,并在 Kubernetes 工作区中设有公开的 #gardener Slack 频道。此外,我们正在计划于2020 年第一季度举办 Gardener 黑客马拉松,并期待在那里见到您!