本文发布已超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。
支持 Azure VMSS、集群自动缩放器和用户分配的标识
引言
在 Kubernetes v1.12 中,Azure 虚拟机规模集 (VMSS) 和集群自动缩放器已达到正式发布 (GA) 状态,并且用户分配的身份作为预览功能提供。
Azure VMSS 允许您创建和管理相同的、负载均衡的 VM,这些 VM 会根据需求或设定的计划自动增加或减少。这使您可以轻松管理和扩展多个 VM,以提供高可用性和应用程序弹性,非常适合容器工作负载等大规模应用程序 [1]。
集群自动缩放器允许您根据负载条件自动调整 Kubernetes 集群的大小。
v1.12 带来的另一个令人兴奋的功能是能够在 Kubernetes 集群中使用用户分配的身份 [12]。
在本文中,我们将简要概述 Azure 上的 VMSS、集群自动缩放器和用户分配的身份功能。
VMSS
Azure 的虚拟机规模集 (VMSS) 功能为用户提供了从单个中心配置自动创建 VM 的能力,通过 L4 和 L7 负载均衡提供负载均衡,提供使用可用区实现高可用性的途径,并提供大规模 VM 实例等。
VMSS 由一组相同的虚拟机组成,可以在组级别进行管理和配置。有关此功能在 Azure 本身的更多详细信息,请访问以下链接 [1]。
使用 Kubernetes v1.12,客户可以使用 VMSS 实例创建 k8s 集群并利用 VMSS 功能。
Azure 上的集群组件
通常,Azure 中的独立 Kubernetes 集群由以下部分组成
- 计算 - VM 本身及其属性。
- 网络 - 这包括 IP 和负载均衡器。
- 存储 - 与 VM 关联的磁盘。
计算
云 k8s 集群中的计算由 VM 组成。这些 VM 由 acs-engine 或 AKS(在托管服务的情况下)等预配工具创建。最终,它们会运行各种系统守护程序,例如 kubelet、kube-api 服务器等,作为进程(在某些版本中)或作为 docker 容器。
网络
在 Azure Kubernetes 集群中,各种网络组件被组合在一起,以提供用户所需的功能。通常,它们包括网络接口、网络安全组、公共 IP 资源、VNET(虚拟网络)、负载均衡器等。
存储
Kubernetes 集群构建在 Azure 中创建的磁盘之上。在典型配置中,我们有用于保存常规 OS 映像的托管磁盘,以及用于 etcd 的单独磁盘。
云提供商组件
Kubernetes 云提供商接口提供与云的交互,以管理特定于云的资源,例如公共 IP 和路由。这些组件的良好概述在 [2] 中给出。在 Azure Kubernetes 集群的情况下,Kubernetes 交互通过 Azure 云提供商层并联系在云中运行的各种服务。
K8s 的云提供商实现可以大致分为以下我们需要实现的组件接口
- 负载均衡器
- 实例
- 区域
- 路由
除了上述接口之外,来自云提供商的存储服务通过卷插件层链接。
Azure 云提供商实现和 VMSS
在 Azure 云提供商中,对于我们实现的每种类型的集群,我们都会指定一个 VMType 选项。在 VMSS 的情况下,VM 类型为“vmss”。预配软件(acs-engine,未来为 AKS 等)会在 /etc/kubernetes/azure.json 文件中设置这些值。根据此类型,会实例化各种实现 [3]
负载均衡器接口提供对底层云提供商负载均衡器服务的访问。Kubernetes 需要有关负载均衡器的信息以及对负载均衡器的控制操作,以便处理托管在 Kubernetes 集群上的服务。对于 VMSS 支持,更改可确保 VMSS 实例成为负载均衡器池的一部分。
实例接口帮助云控制器从云提供商层获取有关节点的各种详细信息。例如,控制器通过云提供商层注册的实例接口获取节点的详细信息,例如 IP 地址、实例 ID 等。在 VMSS 支持的情况下,我们与 VMSS 服务通信以收集有关实例的信息。
区域接口帮助云控制器获取每个节点的区域信息。调度程序可以使用此类信息将 Pod 分散到不同的可用区。它还支持拓扑感知动态预配功能,例如 AzureDisk。每个 VMSS 实例都将使用其当前区域和区域进行标记。
路由接口帮助云控制器为 Pod 网络设置高级路由。例如,将为每个节点设置一个前缀为节点 podCIDR 且下一跳为节点内部 IP 的路由。在 VMSS 支持的情况下,下一跳是 VMSS 虚拟机的内部 IP 地址。
Azure 卷插件接口已针对 VMSS 进行了修改,以使其正常工作。例如,附加/分离到 AzureDisk 的操作已修改为在 VMSS 实例级别执行这些操作。
在 Azure 上设置 VMSS 集群
以下链接 [4] 提供了一个使用 acs-engine 创建 Kubernetes 集群的示例。
acs-engine deploy --subscription-id <subscription id> \
--dns-prefix <dns> --location <location> \
--api-model examples/kubernetes.json
API 模型文件提供了 acs-engine 用于创建集群的各种配置。此处的 API 模型 [5] 提供了一个很好的起始配置来设置 VMSS 集群。
创建 VMSS 集群后,您可以运行以下一些步骤来了解有关集群设置的更多信息。以下是使用上述命令创建的集群的 kubectl get nodes 的输出
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-agentpool1-92998111-vmss000000 Ready agent 1h v1.12.0-rc.2
k8s-agentpool1-92998111-vmss000001 Ready agent 1h v1.12.0-rc.2
k8s-master-92998111-0 Ready master 1h v1.12.0-rc.2
此集群由两个工作节点和一个主节点组成。现在,我们如何检查哪个节点在 Azure 中是哪个节点?在 VMSS 列表中,我们可以看到单个 VMSS
$ az vmss list -o table -g k8sblogkk1
Name ResourceGroup Location Zones Capacity Overprovision UpgradePolicy
---------------------------- --------------- ---------- ------- ---------- --------------- ---------------
k8s-agentpool1-92998111-vmss k8sblogkk1 westus2 2 False Manual
我们看到作为代理(在 kubectl get nodes 命令中)的节点是此 vmss 的一部分。我们可以使用以下命令列出属于 VM 规模集的实例
$ az vmss list-instances -g k8sblogkk1 -n k8s-agentpool1-92998111-vmss -o table
InstanceId LatestModelApplied Location Name ProvisioningState ResourceGroup VmId
------------ -------------------- ---------- ------------------------------ ------------------- --------------- ------------------------------------
0 True westus2 k8s-agentpool1-92998111-vmss_0 Succeeded K8SBLOGKK1 21c57d6c-9c8f-4a62-970f-63ed0fcba53f
1 True westus2 k8s-agentpool1-92998111-vmss_1 Succeeded K8SBLOGKK1 840743b9-0076-4a2e-920e-5ba9da296665
节点名称与 VM 规模集中的名称不匹配,但是如果我们运行以下命令列出 providerID,我们可以找到与实例名称相似的匹配节点
$ kubectl describe nodes k8s-agentpool1-92998111-vmss000000| grep ProviderID
ProviderID: azure:///subscriptions/<subscription id>/resourceGroups/k8sblogkk1/providers/Microsoft.Compute/virtualMachineScaleSets/k8s-agentpool1-92998111-vmss/virtualMachines/0
当前状态和未来
当前支持以下功能
- VMSS 主节点和工作节点
- 工作节点上的 VMSS 和主节点组合上的可用性集。
- 每个 VM 磁盘连接
- Azure 磁盘和 Azure 文件支持
- 可用区(Alpha)
未来将支持以下功能
- 具有 VMSS 支持的 AKS
- 每个 VM 实例的公共 IP
集群自动缩放器
Kubernetes 集群由节点组成。这些节点可以是虚拟机、裸机服务器,甚至可以是虚拟节点(虚拟 kubelet)。为了避免迷失在 Kubernetes 生态系统的排列和组合中 ;-),让我们考虑一下我们正在讨论的集群由托管在云中(例如:Azure、Google 或 AWS)的虚拟机组成。这实际上意味着您可以访问运行 Kubernetes 代理的虚拟机以及运行 API 服务器等 k8s 服务的主节点。有关 k8s 架构的详细版本,请参见此处 [11]。
集群上所需的节点数取决于集群上的工作负载。当负载上升时,需要增加节点,当负载下降时,需要减少节点并清理不再使用的资源。解决此问题的一种方法是手动扩展作为 Kubernetes 集群一部分的节点,并在需求减少时手动缩减。但是,这不应该自动完成吗?这个问题的答案是集群自动缩放器 (CA)。
集群自动缩放器本身作为 Kubernetes 集群内的 Pod 运行。下图说明了关于 k8s 集群的设置的高级视图
由于集群自动缩放器是 k8s 集群中的 Pod,因此它可以使用集群内配置和 Kubernetes go 客户端 [10] 来联系 API 服务器。
内部
API 服务器是管理 k8s 集群状态的中心服务,它利用后备存储(etcd 数据库),在管理节点上运行或在云中运行(在 AKS 等托管服务的情况下)。对于 Kubernetes 集群中的任何组件来说,要确定集群的状态,例如集群中注册的节点,与 API 服务器联系是唯一的方法。
为了简化讨论,我们将 CA 的功能划分为以下三个部分:
CA 的主要部分是一个控制循环,它在每个扫描间隔内持续运行。此循环负责更新自动伸缩器指标和健康探测。在进入此循环之前,自动伸缩器会执行各种操作,例如在执行 Kubernetes 领导者选举后声明领导者状态。主循环会初始化静态自动伸缩器组件。此组件根据传递给 CA 的参数初始化底层云提供商。
CA 执行的用于管理集群状态的各种操作会传递给云提供商组件。例如,增加目标大小、减少目标大小等操作,会导致云提供商组件在内部与云服务进行通信,并执行诸如添加节点或删除节点的操作。这些操作在集群中的一组节点上执行。静态自动伸缩器还会通过查询 API 服务器来监视系统状态 - 例如,使用列出 Pod 和列出节点等操作来获取此类信息。
进行扩展的决定是基于未调度的 Pod 以及各种检查和平衡。可以缩减的空闲节点会从集群中删除,并从云本身删除。集群自动伸缩器在扩展和缩减之前会应用检查和平衡 - 例如,最近添加的节点会被特殊考虑。在删除过程中,节点会被排空,以确保正在运行的 Pod 不会发生中断。
在 Azure 上设置 CA
集群自动伸缩器作为 acs-engine 的附加组件提供。以下链接 [15] 提供了一个示例配置文件,用于使用 acs-engine 部署自动伸缩器。以下链接 [8] 提供了手动逐步执行相同操作的详细信息。
在 acs-engine 案例中,我们使用常规命令行进行部署
acs-engine deploy --subscription-id <subscription id> \
--dns-prefix <dns> --location <location> \
--api-model examples/kubernetes.json
以下是 [15] 的配置文件中的主要区别,确保 CA 作为附加组件部署
"addons": [
{
"name": "cluster-autoscaler",
"enabled": true,
"config": {
"minNodes": "1",
"maxNodes": "5"
}
}
]
上面的 json 中的配置部分可用于为集群自动伸缩器 Pod 提供配置,例如:如上所示的最小和最大节点数。
设置完成后,我们可以看到 cluster-autoscaler Pod 部署在 system 命名空间中
$kubectl get pods -n kube-system | grep autoscaler
cluster-autoscaler-7bdc74d54c-qvbjs 1/1 Running 1 6m
以下是来自示例集群的 CA configmap 和事件的输出
$kubectl -n kube-system describe configmap cluster-autoscaler-status
Name: cluster-autoscaler-status
Namespace: kube-system
Labels: <none>
Annotations: cluster-autoscaler.kubernetes.io/last-updated=2018-10-02 01:21:17.850010508 +0000 UTC
Data
====
status:
----
Cluster-autoscaler status at 2018-10-02 01:21:17.850010508 +0000 UTC:
Cluster-wide:
Health: Healthy (ready=3 unready=0 notStarted=0 longNotStarted=0 registered=3 longUnregistered=0)
LastProbeTime: 2018-10-02 01:21:17.772229859 +0000 UTC m=+3161.412682204
LastTransitionTime: 2018-10-02 00:28:49.944222739 +0000 UTC m=+13.584675084
ScaleUp: NoActivity (ready=3 registered=3)
LastProbeTime: 2018-10-02 01:21:17.772229859 +0000 UTC m=+3161.412682204
LastTransitionTime: 2018-10-02 00:28:49.944222739 +0000 UTC m=+13.584675084
ScaleDown: NoCandidates (candidates=0)
LastProbeTime: 2018-10-02 01:21:17.772229859 +0000 UTC m=+3161.412682204
LastTransitionTime: 2018-10-02 00:39:50.493307405 +0000 UTC m=+674.133759650
NodeGroups:
Name: k8s-agentpool1-92998111-vmss
Health: Healthy (ready=2 unready=0 notStarted=0 longNotStarted=0 registered=2 longUnregistered=0 cloudProviderTarget=2 (minSize=1, maxSize=5))
LastProbeTime: 2018-10-02 01:21:17.772229859 +0000 UTC m=+3161.412682204
LastTransitionTime: 2018-10-02 00:28:49.944222739 +0000 UTC m=+13.584675084
ScaleUp: NoActivity (ready=2 cloudProviderTarget=2)
LastProbeTime: 2018-10-02 01:21:17.772229859 +0000 UTC m=+3161.412682204
LastTransitionTime: 2018-10-02 00:28:49.944222739 +0000 UTC m=+13.584675084
ScaleDown: NoCandidates (candidates=0)
LastProbeTime: 2018-10-02 01:21:17.772229859 +0000 UTC m=+3161.412682204
LastTransitionTime: 2018-10-02 00:39:50.493307405 +0000 UTC m=+674.133759650
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScaleDownEmpty 42m cluster-autoscaler Scale-down: removing empty node k8s-agentpool1-92998111-vmss000002
如事件所示,集群自动伸缩器缩减并删除了一个节点,因为此集群上没有负载。本例中的其余 configmap 指示自动伸缩器目前没有采取进一步的操作。
当前状态和未来
集群自动伸缩器目前支持四种 VM 类型:标准 (VMAS)、VMSS、ACS 和 AKS。未来,集群自动伸缩器将集成到 AKS 产品中,以便用户可以通过一键启用它。
用户分配的身份
为了使 Kubernetes 集群组件安全地与云服务进行通信,它需要使用云提供商进行身份验证。在 Azure Kubernetes 集群中,到目前为止,这是通过两种方式完成的 - 服务主体或托管身份。在服务主体的情况下,凭据存储在集群中,用户需要承担密码轮换和其他挑战以适应此模型。托管服务身份消除了用户的负担,并直接管理服务实例 [12]。
有两种可能的托管身份 - 一种是系统分配的,另一种是用户分配的。在系统分配的身份的情况下,Kubernetes 集群中的每个虚拟机在创建过程中都会分配一个托管身份。此身份由需要访问 Azure 资源的各种 Kubernetes 组件使用。这些操作的示例包括获取/更新负载均衡器配置,获取/更新虚拟机信息等。使用系统分配的托管身份,用户无法控制分配给底层虚拟机的身份。系统会自动分配它,这降低了用户的灵活性。
在 v1.12 中,我们为 Kubernetes 带来了用户分配的托管身份支持。通过此支持,用户无需管理任何密码,但同时可以灵活地管理集群使用的身份。例如,如果用户需要允许集群访问特定的存储帐户或 Azure 密钥保管库,则可以预先创建用户分配的身份并提供密钥保管库访问权限。
内部
为了了解其内部原理,我们将重点关注使用 acs-engine 创建的集群。这可以通过其他方式配置,但基本交互模式相同。
acs-engine 使用所需的配置设置集群。/etc/kubernetes/azure.json 文件为集群组件(例如:kube-apiserver)提供了一种收集有关如何访问云资源配置的方法。在用户托管身份集群中,有一个值填充为键 UserAssignedIdentityID
。此值填充为由 acs-engine 创建或由用户提供的用户分配身份的客户端 ID,但情况可能如此。用于在 Azure 上为 Kubernetes 进行身份验证的代码可以在这里找到 [14]。此代码使用 Azure adal 包来获取身份验证以访问云中的各种资源。在用户分配的身份的情况下,会调用以下 API 调用来获取新令牌
adal.NewServicePrincipalTokenFromMSIWithUserAssignedID(msiEndpoint,
env.ServiceManagementEndpoint,
config.UserAssignedIdentityID)
这会调用实例元数据服务或虚拟机扩展 [12] 来收集令牌,然后使用该令牌访问各种资源。
设置具有用户分配身份的集群
由于 v1.12 中对用户分配身份的上游支持,现在 acs-engine 中也支持使用用户分配的身份创建集群。此处的 json 配置文件 [13] 可用于创建具有用户分配身份的集群。用于创建 vmss 集群的相同步骤可用于创建分配了用户分配身份的集群。
acs-engine deploy --subscription-id <subscription id> \
--dns-prefix <dns> --location <location> \
--api-model examples/kubernetes-msi-userassigned/kube-vmss.json
此处的主要配置值如下:
"useManagedIdentity": true
"userAssignedID": "acsenginetestid"
第一个 useManagedIdentity
指示 acs-engine 我们将使用托管身份扩展。这将设置托管身份工作所需的必要包和扩展。下一个 userAssignedID
提供有关要与集群一起使用的用户身份的信息。
当前状态和未来
目前,我们支持使用 acs-engine 的部署来创建具有集群的用户分配身份。未来,这将成为 AKS 的一部分。
参与其中
有关特定于 Azure 的讨论,请查看 Azure SIG 页面 [6] 并加入 #sig-azure slack 频道以获取更多信息。
对于 CA,请查看此处的 Autoscaler 项目 [7] 并加入 #sig-autoscaling Slack 以进行更多讨论。
有关 Azure 上 acs-engine(非托管版本)的文档,请在此处找到:[9]。有关 Azure Kubernetes 服务 (AKS) 的托管服务的更多详细信息,请访问此处 [5]。
参考
https://learn.microsoft.com/zh-cn/azure/virtual-machine-scale-sets/overview
/docs/concepts/architecture/cloud-controller/
https://github.com/Azure/acs-engine/blob/master/docs/kubernetes/deploy.md
https://github.com/kubernetes/community/tree/master/sig-azure
/docs/concepts/architecture/
https://learn.microsoft.com/zh-cn/azure/active-directory/managed-identities-azure-resources/overview
https://github.com/Azure/acs-engine/tree/master/examples/kubernetes-msi-userassigned
14)https://github.com/kubernetes/kubernetes/blob/release-1.17/staging/src/k8s.io/legacy-cloud-providers/azure/auth/azure_auth.go