本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

支援 Azure VMSS、Cluster-Autoscaler 和使用者分配的身份

引言

隨著 Kubernetes v1.12 的釋出,Azure 虛擬機器規模集(VMSS)和叢集自動擴縮器已達到通用可用性(GA),使用者分配的身份作為預覽功能提供。

Azure VMSS 允許您建立和管理相同、負載均衡的虛擬機器,這些虛擬機器根據需求或預定計劃自動增加或減少。這使您可以輕鬆管理和擴縮多個虛擬機器,以提供高可用性和應用程式彈性,非常適合容器工作負載等大規模應用程式 [1]

叢集自動擴縮器允許您根據負載條件自動調整 Kubernetes 叢集的大小。

v1.12 帶來的另一個令人興奮的功能是能夠將使用者分配的身份與 Kubernetes 叢集一起使用 [12]

在本文中,我們將簡要概述 Azure 上的 VMSS、叢集自動擴縮器和使用者分配的身份功能。

VMSS

Azure 的虛擬機器規模集(VMSS)功能允許使用者從單箇中心配置自動建立虛擬機器,透過 L4 和 L7 負載均衡提供負載均衡,提供使用可用性區域實現高可用性的途徑,提供大規模虛擬機器例項等。

VMSS 由一組相同的虛擬機器組成,可以在組級別進行管理和配置。有關 Azure 中此功能的更多詳細資訊,請參見以下連結 [1]

透過 Kubernetes v1.12,客戶可以利用 VMSS 例項建立 k8s 叢集並使用 VMSS 功能。

Azure 上的叢集元件

通常,Azure 中的獨立 Kubernetes 叢集由以下部分組成

  • 計算 - 虛擬機器本身及其屬性。
  • 網路 - 包括 IP 和負載均衡器。
  • 儲存 - 與虛擬機器關聯的磁碟。

計算

雲 k8s 叢集中的計算由虛擬機器組成。這些虛擬機器由 acs-engine 或 AKS(對於託管服務)等預配工具建立。最終,它們作為程序(在某些版本中)或作為 docker 容器執行各種系統守護程式,例如 kubelet、kube-api server 等。

網路

在 Azure Kubernetes 叢集中,各種網路元件協同工作,為使用者提供所需功能。它們通常包括網路介面、網路安全組、公共 IP 資源、VNET(虛擬網路)、負載均衡器等。

儲存

Kubernetes 叢集建立在 Azure 中建立的磁碟之上。在典型配置中,我們使用託管磁碟來儲存常規 OS 映象,並使用單獨的磁碟用於 etcd。

雲提供商元件

Kubernetes 雲提供商介面提供與雲的互動,用於管理雲特定資源,例如公共 IP 和路由。這些元件的良好概述可在 [2] 中找到。對於 Azure Kubernetes 叢集,Kubernetes 互動透過 Azure 雲提供商層進行,並聯系雲中執行的各種服務。

K8s 的雲提供商實現可大致分為以下需要實現的元件介面

  1. 負載均衡器
  2. 例項
  3. 區域
  4. 路由

除了上述介面外,雲提供商的儲存服務透過卷外掛層連線。

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 用於建立叢集的各種配置。此處 [5] 的 API 模型提供了設定 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 的一部分。我們可以使用以下命令列出作為虛擬機器規模集一部分的例項

$ 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

節點名稱與虛擬機器規模集中的名稱不匹配,但是如果我們執行以下命令列出 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

現狀與未來

目前支援以下功能

  1. VMSS 主節點和工作節點
  2. VMSS 在工作節點上,可用性集在主節點上組合。
  3. 每個虛擬機器磁碟連線
  4. Azure 磁碟和 Azure 檔案支援
  5. 可用區(Alpha)

將來將支援以下功能

  1. AKS 支援 VMSS
  2. 每個 VM 例項公共 IP

叢集自動擴縮器

Kubernetes 叢集由節點組成。這些節點可以是虛擬機器、裸機伺服器,甚至可以是虛擬節點(虛擬 kubelet)。為了避免在 Kubernetes 生態系統的排列組合中迷失方向 ;-), 讓我們考慮我們正在討論的叢集由託管在雲中(例如:Azure、Google 或 AWS)的虛擬機器組成。這實際意味著您可以訪問執行 Kubernetes 代理的虛擬機器和執行 API 伺服器等 k8s 服務的主節點。k8s 架構的詳細版本可在此處找到 [11]

叢集所需的節點數量取決於叢集上的工作負載。當負載增加時,需要增加節點;當負載減小時,需要減少節點並清理不再使用的資源。一種解決方法是手動擴縮 Kubernetes 叢集中的節點,並在需求減少時手動縮減。但這不應該自動完成嗎?這個問題的答案是叢集自動擴縮器 (CA)。

叢集自動擴縮器本身作為 Pod 在 Kubernetes 叢集中執行。下圖說明了與 k8s 叢集相關的設定的高階檢視

由於叢集自動擴縮器是 k8s 叢集中的一個 Pod,它可以使用叢集內部配置和 Kubernetes go 客戶端 [10] 來聯絡 API 伺服器。

內部機制

API 伺服器是利用後端儲存(etcd 資料庫)管理 k8s 叢集狀態的中心服務,它執行在管理節點上或雲中(對於 AKS 等託管服務)。對於 Kubernetes 叢集中的任何元件,要了解叢集的狀態,例如叢集中註冊的節點,聯絡 API 伺服器是可行的方法。

為了簡化我們的討論,我們將 CA 功能分為以下 3 個部分

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 中的 config 部分可用於向叢集自動擴縮器 Pod 提供配置,例如:如上所示的最小和最大節點數。

設定完成後,我們可以看到 cluster-autoscaler pod 已部署在系統名稱空間中

$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 的其餘部分表示自動擴縮器目前沒有采取進一步的行動。

現狀與未來

叢集自動擴縮器目前支援四種虛擬機器型別:標準(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,具體情況視情況而定。用於 Kubernetes 在 Azure 上進行身份驗證的程式碼可在此處找到 [14]。此程式碼使用 Azure adal 包進行身份驗證以訪問雲中的各種資源。在使用者分配身份的情況下,會進行以下 API 呼叫以獲取新令牌

adal.NewServicePrincipalTokenFromMSIWithUserAssignedID(msiEndpoint,
env.ServiceManagementEndpoint,
config.UserAssignedIdentityID)

此呼叫會訪問例項元資料服務或虛擬機器擴充套件 [12],以獲取用於訪問各種資源的令牌。

使用使用者分配的身份設定叢集

隨著 v1.12 中使用者分配身份的上游支援,現在 acs-engine 支援建立具有使用者分配身份的叢集。此處 [13] 提供的 json 配置檔案可用於建立具有使用者分配身份的叢集。建立 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 特定討論,請檢視 [6] 上的 Azure SIG 頁面,並加入 #sig-azure Slack 頻道瞭解更多資訊。

對於 CA,請檢視此處的自動擴縮器專案 [7],並加入 #sig-autoscaling Slack 頻道進行更多討論。

有關 Azure 上的 acs-engine(非託管版本)文件,請參見此處:[9]。有關 Azure Kubernetes 服務(AKS)託管服務的更多詳細資訊,請參見此處 [5]

參考資料

  1. https://learn.microsoft.com/azure/virtual-machine-scale-sets/overview

  2. /docs/concepts/architecture/cloud-controller/

  3. https://github.com/kubernetes/kubernetes/blob/release-1.17/staging/src/k8s.io/legacy-cloud-providers/azure/azure_vmss.go

  4. https://github.com/Azure/acs-engine/blob/master/docs/kubernetes/deploy.md

  5. https://learn.microsoft.com/azure/aks/

  6. https://github.com/kubernetes/community/tree/master/sig-azure

  7. https://github.com/kubernetes/autoscaler

  8. https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/azure/README.md

  9. https://github.com/Azure/acs-engine

  10. https://github.com/kubernetes/client-go

  11. /docs/concepts/architecture/

  12. https://learn.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview

  13. 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

  1. https://github.com/Azure/acs-engine/tree/master/examples/addons/cluster-autoscaler