返回文章列表

Kubernetes 排程器與安裝

本文探討 Kubernetes 排程器的核心機制,包含預測、優先順序與高階演算法,並解析節點親和性、汙點和容忍度等控制排程的重要概念。同時,提供使用 kubeadm 安裝和設定 Kubernetes 叢集的完整,涵蓋 kubelet、控制平面、

容器技術 系統管理

Kubernetes 排程器負責將 Pod 分配到最佳節點,其決策過程根據預測和優先順序等因素,並透過演算法實作最佳化。預測作為硬性約束,確保 Pod 的基本需求得到滿足,而優先順序則用於在滿足預測的基礎上,選擇更優的節點。理解這些概念有助於管理員和開發者更好地控制 Pod 的佈署位置和資源分配。此外,文章也詳細介紹瞭如何使用 kubeadm 安裝和設定 Kubernetes 叢集,包含控制平面、kubelet 和網路設定等關鍵步驟,並提供客製化設定的選項,讓使用者可以根據自身需求調整叢集組態。

Kubernetes 排程器深度解析

Kubernetes 的排程器(Scheduler)是叢集運作的核心元件之一,負責將 Pod 分配到適當的節點上執行。本篇文章將探討 Kubernetes 排程器的工作原理、關鍵概念以及實際運作中的挑戰。

排程流程

當排程器發現一個尚未被分配到節點的 Pod 時,它需要決定將該 Pod 排程到哪個節點上。這個決策過程涉及多個因素,包括使用者提供的資訊和排程器自身的計算結果。總的來說,排程器試圖最佳化多個不同的標準,以找到最適合特定 Pod 的節點。

預測(Predicates)

在進行排程決策時,排程器使用兩個通用的概念:預測和優先順序。預測是指一個 Pod 是否適合在某個節點上執行。預測是硬性約束,如果違反,將導致 Pod 無法正常運作。例如,Pod 請求的記憶體量如果在節點上不可用,則該約束被違反。另一個預測的例子是使用者指定的節點選擇器標籤查詢。

優先順序(Priorities)

優先順序函式用於評估將 Pod 排程到特定節點上的相對價值。與預測不同,優先順序函式不判斷 Pod 是否能在節點上成功執行,而是評估在該節點上執行的相對價值。例如,一個優先順序函式可能會給已經提取了所需映像的節點更高的權重,因為這樣可以加快容器的啟動速度。

高階演算法

對於每個需要排程的 Pod,排程演算法都會執行。以下是該演算法的高階概述:

schedule(pod): string
nodes := getAllHealthyNodes()
viableNodes := []
for node in nodes:
    for predicate in predicates:
        if predicate(node, pod):
            viableNodes.append(node)
scoredNodes := PriorityQueue<score, Node[]>
priorities := GetPriorityFunctions()
for node in viableNodes:
    score = CalculateCombinedPriority(node, pod, priorities)
    scoredNodes[score].push(node)
bestScore := scoredNodes.top().score
selectedNodes := []
while scoredNodes.top().score == bestScore:
    selectedNodes.append(scoredNodes.pop())
node := selectAtRandom(selectedNodes)
return node.Name

內容解密:

  1. getAllHealthyNodes():取得所有健康的節點列表。
  2. predicates:一系列的預測函式,用於過濾出可行的節點。
  3. CalculateCombinedPriority(node, pod, priorities):計算每個可行節點的綜合優先順序分數。
  4. PriorityQueue:一個優先順序佇列,用於儲存根據分數排序的節點。
  5. selectAtRandom(selectedNodes):從具有相同最高分數的節點中隨機選擇一個節點。

衝突與挑戰

由於 Pod 排程和實際執行之間存在延遲,排程決策可能會因為叢集狀態的變化而變得無效。這種情況可能導致選擇一個稍微次優的節點,或者在極端情況下,由於硬性約束的違反而導致 Pod 無法執行。

硬性約束衝突

當叢集狀態的變化違反了排程器的硬性約束時,可能會導致 Pod 無法在指定的節點上執行。例如,如果一個節點在排程決策後但在 Pod 執行前可用資源發生變化,則可能導致 Pod 無法啟動。在這種情況下,Pod 將被標記為失敗,如果它是由 ReplicaSet 建立的,則會建立一個新的 Pod 並排程到其他合適的節點上。

排程控制:使用標籤(Labels)、親和性(Affinity)、汙點(Taints)和容忍(Tolerations)

在 Kubernetes 中,Pod 的排程是一個非常重要的過程。預設情況下,Kubernetes 會根據其內建的排程演算法來決定將 Pod 排程到哪個節點上執行。但是,在某些情況下,我們需要更細粒度地控制排程的過程。Kubernetes 提供了多種工具來幫助我們實作這一點,包括標籤、親和性、汙點和容忍等。

節點選擇器(Node Selectors)

節點選擇器是一種簡單的方式,用於確保 Pod 被排程到具有特定標籤的節點上。首先,每個 Kubernetes 物件都有一個與之相關聯的標籤集合。標籤提供了 Kubernetes 物件的識別後設資料,而標籤選擇器則常用於動態識別各種操作的 API 物件集。

舉例來說,假設我們有一個工作負載,需要排程到具有高效能儲存(如 NVMe SSD)的機器上。由於這種儲存通常很昂貴,因此不是每台機器都具備。這時,我們可以為具有 NVMe SSD 的機器新增一個額外的標籤,如下所示:

kind: Node
metadata:
  labels:
    nvme-ssd: true
...

然後,在 Pod 的定義中,我們可以設定 nodeSelector 欄位來比對節點上的標籤:

kind: Pod
spec:
  nodeSelector:
    nvme-ssd: true
...

內容解密:

  • kind: Nodekind: Pod 定義了 Kubernetes 物件的型別。
  • metadata.labels 用於為節點新增標籤。
  • spec.nodeSelector 用於指定 Pod 應該被排程到哪些節點上。

Kubernetes 有一個預設的謂詞(predicate),要求每個節點都必須比對 nodeSelector 標籤查詢(如果存在)。因此,具有 nvme-ssd 標籤的 Pod 總是會被排程到具有相應硬體的節點上。

節點親和性(Node Affinity)

節點選擇器提供了一種簡單的方式來保證 Pod 落在特定的節點上,但它們缺乏靈活性。它們無法表示更複雜的邏輯表示式,也無法表示反親和性。

從 Kubernetes 1.2 開始,透過在 Pod spec 中加入 affinity 結構,新增了親和性的概念。親和性是一種更複雜的結構,但如果你想表達更複雜的排程策略,它會更加靈活。

例如,假設我們有一個 Pod,需要排程到具有標籤 foo 且其值為 AB 的節點上。這可以透過以下親和性策略來實作:

kind: Pod
...
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          # foo == A 或 B
          - key: foo
            operator: In
            values:
            - A
            - B
...

內容解密:

  • affinity.nodeAffinity 定義了節點親和性。
  • requiredDuringSchedulingIgnoredDuringExecution 表示在排程時必須滿足的條件,但在 Pod 執行期間則會被忽略。
  • nodeSelectorTermsmatchExpressions 用於指定比對條件。
  • operator: In 表示標籤的值必須在指定的值列表中。

此外,還可以使用 preferredDuringSchedulingIgnoredDuringExecution 來表達對節點的偏好,而不是要求。這允許我們根據偏好來排程 Pod。

kind: Pod
...
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          # foo == A 或 B
          - key: foo
            operator: In
            values:
            - A
            - B
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        preference:
          matchExpressions:
          - key: foo
            operator: In
            values:
            - A

內容解密:

  • preferredDuringSchedulingIgnoredDuringExecution 用於指定排程偏好。
  • weight 用於指定偏好的權重。

總之,Kubernetes 提供了多種工具來控制 Pod 的排程,包括節點選擇器、親和性和汙點等。這些工具使我們能夠更靈活地控制 Pod 的排程,以滿足不同的需求和場景。

Kubernetes 排程與安裝

Kubernetes 是一個強大的容器協調平台,其核心功能之一是將使用者的容器執行請求排程到適當的機器上。對於叢集管理員來說,排程器的運作以及教導使用者如何有效地使用它,是建立一個可靠且高效能叢集的關鍵。

節點親和性與容忍度

節點親和性允許使用者指定 Pod 排程到特定節點的偏好或需求。Pod 親和性則允許使用者表達 Pod 之間的親和性或反親和性需求。然而,這些功能需要使用者在建立容器時進行設定。

節點汙點(Taints)與容忍度(Tolerations)

節點汙點是一種機制,允許管理員將某些節點標記為「汙點」,使得這些節點預設不會被排程器選中,除非 Pod 明確地容忍這些汙點。

apiVersion: v1
kind: Pod
metadata:
  name: example-pod
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: foo
            operator: In
            values:
            - A
            - B

內容解密:

  • nodeAffinity 用於指定節點親和性規則。
  • requiredDuringSchedulingIgnoredDuringExecution 表示在排程期間必須滿足的條件,如果節點不符合條件,則 Pod 不會被排程到該節點。
  • matchExpressions 用於定義標籤選擇器,這裡指定了 foo 標籤的值必須是 AB

Kubernetes 安裝

安裝 Kubernetes 是使用其功能的第一步。有許多工具可以幫助您快速建立一個 Kubernetes 叢集,例如 minikube 或各大公有雲供應商的管理服務。

kubeadm

kubeadm 是一個由 Kubernetes 社群支援的安裝工具,它提供了安裝 Kubernetes 所需的所有功能。使用 kubeadm,您可以在幾分鐘內完成 Kubernetes 的安裝。

kubeadm 的優點:
  • 簡單易用,適合開發者和生產環境。
  • 與 Kubernetes 版本同步發布,保證相容性。
  • 被許多其他安裝工具用作底層安裝引擎。

kubeadm 的系統需求

  • kubeadm 是靜態連結的二進位檔案,因此對分享函式庫沒有依賴。
  • 需要一個容器執行環境和 Kubernetes 的 kubelet 元件。
  • 需要一些標準的 Linux 工具。

選擇容器執行環境

選擇一個符合 Container Runtime Interface (CRI) 的容器執行環境。目前,Docker、rkt 和 CRI-O 是流行的 CRI 相容執行環境。

內容解密:
  • CRI 定義了 kubelet 與主機上的容器執行環境之間的介面標準。
  • 選擇容器執行環境時,應參考 Kubernetes 的發行說明,以確保相容性和效能。

Kubernetes 安裝與設定

Kubernetes 的安裝涉及多個元件的設定,包括 kubelet、控制平面(control plane)元件,以及 etcd 資料儲存。kubeadm 是 Kubernetes 官方提供的工具,用於簡化叢集的安裝和設定過程。

Kubelet 的安裝與設定

kubelet 是 Kubernetes 的節點代理,負責向 API 伺服器報告節點狀態並管理 Pod 的生命週期。安裝 kubelet 需要下載並安裝與 Kubernetes 版本相符的套件。大多數 Linux 發行版使用 systemd 管理服務,因此 kubelet 的設定通常涉及建立或修改 systemd 的單元檔案。

預設設定範例

[Unit]
Description=kubelet: The Kubernetes Node Agent
Documentation=http://kubernetes.io/docs/

[Service]
ExecStart=/usr/bin/kubelet
Restart=always
StartLimitInterval=0
RestartSec=10

[Install]
WantedBy=multi-user.target

自訂 kubelet 設定

可以透過在 /etc/systemd/system/kubelet.service.d/ 目錄下新增設定檔來自訂 kubelet 的行為。例如,若要設定 --cloud-provider 引數,可以建立一個名為 09-extra-args.conf 的檔案:

[Service]
Environment="KUBELET_EXTRA_ARGS=--cloud-provider=aws"

修改後,需要重新載入 systemd 設定並重啟 kubelet 服務:

$ sudo systemctl daemon-reload
$ sudo systemctl restart kubelet

控制平面的安裝

控制平面包括 API 伺服器、控制器管理器和排程器,這些元件共同負責管理叢集的狀態和工作負載。kubeadm 可以自動安裝這些元件。

使用 kubeadm 初始化控制平面

$ kubeadm init

初始化完成後,kubeadm 會輸出相關的設定資訊,包括如何設定 kubectl、如何佈署 Pod 網路,以及如何讓其他節點加入叢集。

設定 kubectl

$ mkdir -p $HOME/.kube
$ sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
$ sudo chown $(id -u):$(id -g) $HOME/.kube/config

佈署 Pod 網路

需要根據所選的網路方案執行對應的佈署命令,例如:

$ kubectl apply -f [podnetwork].yaml

kubeadm 設定與客製化

kubeadm 提供了多種方式進行客製化設定,包括命令列引數和 kubeadm API。

使用 kubeadm API 設定控制平面

apiVersion: kubeadm.k8s.io/v1alpha1
kind: MasterConfiguration
api:
  advertiseAddress: <address|string>
  bindPort: <int>
etcd:
  endpoints:
  - <endpoint1|string>
  - <endpoint2|string>
  caFile: <path|string>
  certFile: <path|string>
  keyFile: <path|string>
networking:
  dnsDomain: <string>
  serviceSubnet: <cidr>
  podSubnet: <cidr>
kubernetesVersion: <string>
cloudProvider: <string>
authorizationModes:
- <authorizationMode1|string>
- <authorizationMode2|string>
token: <string>
tokenTTL: <time duration>

詳細解說

此 YAML 設定檔用於定義 Kubernetes 控制平面的各項引數。

  1. apiVersion 和 kind:指定了該組態檔案的版本和型別。
  2. api:定義了 API 伺服器的相關設定,如 advertiseAddressbindPort
  3. etcd:指定了 etcd 資料儲存的相關設定,包括端點、憑證檔案路徑等。
  4. networking:定義了叢集的網路設定,如 DNS 網域、服務子網路和 Pod 子網路。
  5. kubernetesVersion:指定了 Kubernetes 的版本。
  6. cloudProvider:指定了雲端服務提供者。
  7. authorizationModes:定義了授權模式。
  8. token 和 tokenTTL:用於節點加入叢集的驗證 token 及其有效期限。

透過這種方式,可以對 Kubernetes 叢集進行細緻的客製化設定,以滿足不同的佈署需求。