Kubernetes 核心介紹 Api Server

Posted by Alan Zhan on Sunday, April 24, 2022

API Server

kube-apiserver 是 Kubernetes 最重要的核心組件之一,主要提供以下功能:

  • 提供集群管理的 REST API ,包括認證、授權、數據檢驗以及集群狀態變更等
    • 認證 Authentication
    • 授權 Authorization
    • 准入 Admission (Mutating & Valiating)
  • 提供其他模組之間的數據交互和通訊的樞紐,其他模組只能通過 API Server 查詢或者修改數據,只有 API Server 才能直接操作 etcd。

kube-apiserver 支持提供 https ( 預設 port 6443 ) 和 http API (默認監聽 127.0.0.1 的 8080 ),其中 http API 是非安全的 API,不做任何認證授權機制,不建議在 Production 環境開啟此功能。

Authentication

開啟 TLS 時,所有的請求都需要首先認證。 Kubernetes 支持多種認證機制,並支持同時開啟多個認證 plugin (只要有一個認證通過即可)。如果認證成功,則用戶的 username 會傳入授權模組做進一步驗證,對於認證失敗的請求則會返回 401。高階版本默認使用 TLS 作為驗證方式。

常見的 Authentication 方法

  • X.509
    • 使用 X509 客戶端證書,只需要 API Server 啟動時配置 —client-ca-file=SOMEFILE。在證書認證時,其 CN 域用作用戶名,而組織機構域則用做 group 名。
  • 靜態 Token 文件
    • 使用靜態 Token 文件認證,只需要 API Server 啟動時配置 —token-auth=file=SOMEFILE 。
    • 該文件為 csv 格式,美行至少包括三列 token,username,userid,”group1,group2,group3”
  • 引導 Token
    • 為了支持平滑的啟動引導新的集群,Kubernetes 包含了一種動態管理的持有指 token 類型,稱作啟動引導 token (Bootstrap Token)。
    • 這些 token 以 Secret 的方式保存在 kube-system namespace 中,可以被動態管理和創建。
    • 控制器管理器包含的 TokenCleaner 控制器能夠在啟動引導 token 過期時,將其刪除。
    • 在使用 kubeadm 佈署 Kubernetes 時,可以通過 kubeadm token list 命令查詢。
  • 靜態密碼文件
    • 需要 API Server 啟動時候配置 —basic-auth-file=SOMEFILE ,文件格式為 csv ,每行至少三列 password,user,uid,”group1,group2,group3”。
  • ServiceAccount
    • ServiceAccount 是 Kubernetes 自動生成的,並會自動掛載到容器的 /run/secrets/kubernetes.io/serviceaccount 目錄中。
  • OpenID
    • OAuth 2.0 的認證機制。
  • Webhook Token 身分認證
    • —authentication-token-webhook-config-file 指向一個配置文件,其中描述訪問遠程的 Webhook 服務。
    • —authentication-token-webhook-cache-ttl 用來設定身分認證決定的緩存時間。默認兩分鐘。
  • 匿名請求
    • 如果使用 AlwaysAllow 以外的認證模式,則匿名請求默認開啟,但可用 —anonymous-auth=false 禁止匿名請求。

Authorization

授權主要是用於對集群資源的訪問控制,通過檢查請求包含的相關屬性值,與相對應的相對應的訪問策略相比較,API 請求必須滿足某些策略才能被處理。

跟認證類似, Kubernetes 也支持多種授權機制,並支持同時開啟多個授權 plugin (只要有一個驗證通過即可)。

如果授權成功,則用戶的請求會發送到准入控制模組做進一步的請求驗證,對於授權失敗的請求,則返回 HTTP 403。

Kubernetes 授權僅處理以下的請求屬性

  • user, group, extra
  • API、請求方法 (例如 get, post, update) 和請求路徑 (如 /api)
  • 請求資源和子資源
  • namespace
  • API Group

目前 Kubernetes 支持以下授權 plugin

  • ABAC
  • RBAC
  • Webhook
  • Node

Admission Control

准入控制 (Admission Control) 在授權後對請求做進一步的驗證或添加默認參數。不同於授權和認證只關心請求的用戶和操作,准入控制還處理請求的內容,並且僅對創建、更新、刪除或連接 (如代理) 等有效,而對讀操作無效。

准入控制支持開啟多個 plugin ,他們依序調用,只有全部的 plugin 都通過請求,才可以放過進入系統。

Admission Control Plugin

  • AlwaysAdmit : 接受所有請求。
  • AlwaysPullImages : 總是拉取最新鏡像,在多租戶場景下非常有用。
  • DenyEscalatingExec : 禁止特權容器的 exec 和 attach 操作。
  • ImagePolicyWebhook : 通過 Webhook 決定 image 策略,同時需要配置 —admission-control-config-file。
  • ServiceAccount : 自動創建默認 ServiceAccount,並確保 Pod 引用的 ServiceAccount 已經存在。
  • SecurityContextDeny : 拒絕包含非法 SecurityContext 配置的容器。
  • ResourceQuota : 限制 Pod 的請求不會超過配額,需要在 namespace 中創建一個 ResourceQuota 對象。
  • LimitRanger : 為 Pod 設置默認資源請求和限制,需要在 napespace 中創建一個 LimitRanger 對象。
  • InitialResource : 根據鏡像的歷史使用紀錄,為容器設置默認資源請求和限制。
  • NamespaceLifecyle : 確保處於 termination 狀態的 namespace 不再接受新的對象創建請求,並拒絕請求不存在的 namespace 。
  • DefaultStorageClass : 為 PVC 設置默認的 StorageClass。
  • DefaultTolerationSeconds : 設置 Pod 的默認 forgiveness toleration 為五分鐘。
  • PodSecurityPolicy : 使用 Pod Security Policies 時,必須開啟。
  • NodeRestriction : 限制 kubelet 僅可訪問 node 、 endpoint 、 pod 、 service 以及 secret 、configmap 、 PV 和 PVC 等相關資源。

除了默認的准入控制 plugin 以外,Kubernetes 預留了准入控制 plugin 的擴展點,用戶自定義准入控制 plugin ,實現自定義准入功能。

  • MutatingWebhookConfiguration : 變形 plugin ,支持對準入對向的修改。
  • ValidatingWebhookConfiguration : 較驗 plugin ,只能對準入對向合法性進行較驗,不能修改。

API Server 訪問控制流程

kube-apiserver work flow

限流控制

為了防止突發流量影響到 kube-apiserver 的可用性, kubernetes 支持多種限流方式:

  • MaxInFlightLimit
  • Client 限流
  • EventRateLinit
  • APF: (API Priority And Fariness)

MaxInFlightLimit

可以通過參數的方式,為 kube-apiserver 設置最大併發數量

  • max-request-inflight: 在給定的時間內最大請求數。
  • max-mutating-request-inflight : 在給定時間內的最大 mutating 請求數,調整 apiserver 的流控 qos 。

Client 限流

只支持 Client 的限流, Cluster 無法控制用戶的行為,譬如 client-go 的 QPS 為 5 。

EventRateLimit

只限制 event 請求,集成在 kube-apiserver 內部的 webhook 當中,可配置某個用戶、 namespace 、 server 等相關 event 操作限制。

  • Pros
    • 實現簡單,允許一定數量的併發。
    • 支持 server / namespace / user 等級別的限流。
  • Cons
    • 僅支持 event ,通過 webhook 實現只能攔截修改類的請求。
    • 所有 namespace 的限流相同,沒有優先級的概念。

API Priority And Fariness

kube-apiserer 默認的限流方式太過簡單,一個錯誤的客戶發送大量請求,可能會導致其他客戶訪問的請求異常,他是 MaxInFlightLimit 的另一種替代方案,可以參考 KEP-1040: Priority and Fairness for API Server Requests

  • APF 以更細粒度的方式,對請求進行分類和隔離。
  • 他還引入了空間有限的排隊機制,因此在非常短暫的突發情況下,API server 不會拒絕任何請求。
  • 通過使用公平排隊技術從對列中分發請求,這樣一個行為不佳的控制器,就不會餓死其他控制器 (即使優先即相同)。
  • APF 的核心
    • 多等級
    • 多對列

kube-apiserver work flow

概念

  • 傳入的請通過 FlowSchema 按照其屬性分類,並分配優先級。
  • 每個優先級維護自定義的併發限制,加強了隔離度,這樣不同優先級的請求,就不會互相餓死。
  • 在同一個優先集中,公平排隊算法可以防止不同的 flow 請求互相餓死。
  • 該算法將請求排隊,通過排隊機制,防止在平均附載較低時,通訊量暴增導致請求失敗。

Priority

  • 如果未啟用 APF,API server 中的整體併發量將受到 kubectl-apiserver 的參數 —max-requests-inflight 和 —maxmutating-requests-inflight 的限制。
  • 啟用 APF 後,對這些參數定義的併發限制進行求和,然後將總和分配到一組可配置的優先級中。每個傳入的請求都會分配一個優先級。
  • 每個優先級都有各自的配置,設置允許分發的併發請求數。

排隊

  • 即使在同一優先級中,也可能存在大量不同的流量源。
  • 在過載的情況下,防止一個請求流餓死其他流是非常有價值的 (尤其是在一個較為常見的場景中,有一個故障的客戶會瘋狂地向 kube-apiserver 發送請求,理想狀況下,這個有故障的客戶端,不應該對其他客戶端產生太大影響)。
  • 公平排隊算法在處理具有相同優先級的時候時,實現了上訴場景。
  • 每個請求都會被分配到某個 Flow 中,該 Flow 對應的 FlowSchema 的名字加上一個流區分項 (Flow Distinguisher) 來標示。
  • 這裡的流分區項,可以是發請請求的用戶、目標資源的名稱空間或者甚麼都不是。
  • 系統嘗試為不同流中,具有相同優先級的請求,賦予相似相等的權重。
  • 將請求劃分到流中之後,APF 功能將請求分配到對列中。
  • 分配時使用一種稱為混洗分配 (Shuffle-Sharding) 的技術。該技術可以相對有效的利用對列個離低強度與高強度的流。
  • 排隊算法的細節,可以針對每個優先等級進行調整,允許管理者在內存占用、公平性 (當總流量超標時,各個獨立的流將都會取得進展)、突發流量的蓉惹度已級排隊引發的額外延遲之間進行平衡。

豁免請求

某些特別不重要的請求不會受至於此特性施加的任何限制。這些豁免可以防止不當流量配置完全禁用 API server。

PriorityLevelConfiguration

一個 PriorityLevelConfiguration 表示單個隔離類型。 每個 PriorityLevelConfigurations 對未完成請求的請求數有各自的限制,對排隊中的請求數也已有限制。

apiVersion: flowcontrol.apiserver.k8s.io/v1alpha1
kind: PriorityLevelConfiguration
metadata:
  name: restrict-pod-lister
spec:
  type: Limited
  limited:
    assuredConcurrencyShares: 5 # 允許併發請求數
    limitResponse:
      queuing:
        handSize: 4 # shuffle sharding 的配置,每個 flowschema + distinguisher 的請求會被 enqueue 到多少個對列
        queueLengthLimit: 20 # 每個對列的對象數量
        queues: 10 # 當前 PriorityLevel 的對列總數
      type: Queue

FlowSchema

FlowSchema 匹配一些入站請求,並將它們分配給優先級。

每個入站請求都會對所有的 FlowSchema 測試是否匹配,首先從 matchingPrecedence 數值最低的開始匹配,然後依次進行,直到手個匹配對象出現。

apiVersion: flowcontrol.apiserver.k8s.io/v1alpha1
kind: FlowSchema
metadata:
  name: restrict-pod-lister
spec:
  matchingPriority: 800 # 規則優先級
  priorityLevelConfiguration:
    name: restrict-pod-lister # 對應的列隊優先級
  distinguisherMethod:
    type: ByUser # Distinguisher
  rules:
  - resourceRules: # 對應的資源和請求類型
    - apiGroups: [""]
      namespaces: ["demo"]
      resources: ["pods"]
      verbs: ["list", "get"]
    subjects:
    - kind: ServiceAccount
      serviceAccount:
        name: podlister-0
        namespace: demo
    - kind: ServiceAccount
      serviceAccount:
        name: podlister-1
        namespace: demo 
    - kind: ServiceAccount
      serviceAccount:
        name: podlister-2
        namespace: demo

總結

沒有想到 kube-apiserver 身為 cluster 的最重要的 API 盡然做了那麼多事情,也對了 APF 機制有了更深入的了解,期待這個 feature 早日 release。

歡迎到我的 Facebook Alan 的筆記本 留言,順手給我個讚吧!你的讚將成為我持續更新的動力,感謝你的閱讀,讓我們一起學習成為更好的自己。

參考