~xdavidwu/cskloudv3-thesis

cskloudv3-thesis/Sections/2.Backgrounds.tex -rw-r--r-- 17.5 KiB
b4127bf2Pinghao Wu appendix: survey: describe design 4 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
\chapter{背景知識}
\label{ch:backgrounds}

本章節敘述設計此 Kubernetes-as-a-Service 平台所需的背景知識。

\section{Kubernetes}

Kubernetes\cite{kubernetes} (簡稱 K8s)為一容器編排 (orchestration) 系統,其主要任務為將容器排程至叢集節點上執行。為了對網路服務容器達到理想的編排,Kubernetes 也帶有負載均衡、高可用性及自動擴展等網路應用常見功能,因此亦可將 Kubernetes 視為高度可擴展、可靠的網路程式平台。

\subsection{Kubernetes 架構}

Kubernetes 提供 RESTful API 做為主要控制手段,以 resources 代表操作意圖及其結果,將系統操作以非同步的形式建模為對 resources 進行讀寫,並且將系統大致切成兩大部份:負責提供 API 與 resources 資料存儲的 API 伺服器 kube-apiserver,以及實際實做 resources 所代表的操作的 controllers。典型的運作流程大致如下:

\begin{onehalfspacing}
\begin{enumerate}
    \item 使用者建立一 resource,並在其 \verb|spec| 欄位描述期望的系統狀態
    \item kube-apiserver 通知相關 controller 新的 resource 創立事件
    \item controller 根據 \verb|spec| 欄位進行操作,嘗試滿足 \verb|spec|,並將結果存入 \verb|status| 欄位
    \item kube-apiserver 通知使用者 resource 有所變更
    \item 使用者透過更新後的 \verb|status| 欄位得知操作結果
\end{enumerate}
\end{onehalfspacing}

\begin{figure}[htb]
    \centering
    \includegraphics[width=\textwidth]{assets/kubernetes.png}
    \caption{Kubernetes 運作模型簡易示意圖}
\end{figure}

此架構使得 Kubernetes 在功能面上極易擴展,只須對 kube-apiserver 註冊一個新的 resource 種類,並且實做相關 controller 邏輯,便可以擴展 Kubernetes API。運用此機制開發軟體又稱為 operator pattern,將 controller 比擬為自動的營運者。kube-apiserver 除了資料存儲以外,也包含了基本的資料驗證、身份驗證以及相關授權機制,使得 controller 能夠更專注於達成 resource 邏輯的實作,減少擴展開發者的負擔。同時在 resource 本身的設計上,也會盡量使描述的操作是可被重複執行的 (idempotent),令 controller 不須額外維護內部狀態 (stateless),簡化 controller 的部屬管理以及提高容錯空間,使整體系統更為易用且可靠。

\begin{figure}[htb]
    \centering
    \includegraphics[scale=1.2]{assets/kubernetes-resources.png}
    \caption{Kubernetes resources 架構示意圖}
\end{figure}

Kubernetes resources 的種類形成了既定的語意和格式,例如:Pod 代表一組可以互通部份設定的容器、Service 代表網路上具備負載均衡的一個存取點、Node 代表叢集中的一個節點等。Resource 種類又分為兩大類型:namespaced 與 cluster-scoped。Namespaced 代表此種類在 API 上受到 Namespace 分隔,於不同的 Namespace 下,各個 resources 無法相互關聯,通常用於描述賦予叢集的工作負載 (workload),Pod 與 Service 即為此類:Service 可以關聯到多個 Pods 提供實際服務內容,但設計上並不允許 Service 取用其他 Namespace 下的 Pod。Cluster-scoped 的種類則不受 Namespace 管轄,屬於整個叢集,常見於描述叢集本體的配置,Node 與 Namespace 本身即為此類。以使用慣例而言,Namespace 用以切分不同的應用,使得無關的應用在部屬設定上不會互相衝突影響,但須注意 Namespace 僅只限制 API 上能夠描述的相互關係,並不代表會對實際運行的容器或網路環境進行隔離加固。

\subsection{Kubernetes 身份驗證}

Kubernetes 提供多個身份驗證手段,可搭配混合使用,在設計上盡量單獨以驗證手段提供完整身份資訊,包含身份名稱以及所在的群組等,叢集本身以不存放身份對應的資料為原則。這樣的設計使得伺服器負擔減少,同時具有架構單純、易於除錯等優勢,但根據手段不同,可能會使得更動身份資訊(如修改所在的群組)顯得不便。常見的驗證手段主要有:X.509 憑證、authenticating proxy、static tokens、webhook tokens、ServiceAccount tokens 與 OpenID Connect tokens。

\begin{figure}[htb]
    \centering
    \begin{subfigure}{0.323\textwidth}
        \centering
        \includegraphics[width=\textwidth]{assets/authn-x509.png}
        \caption{X.509 憑證}
    \end{subfigure}
    \hspace{1pt}
    \begin{subfigure}{0.323\textwidth}
        \centering
        \includegraphics[width=\textwidth]{assets/authn-proxy.png}
        \caption{Authenticating proxy}
    \end{subfigure}
    \hspace{1pt}
    \begin{subfigure}{0.323\textwidth}
        \centering
        \includegraphics[width=\textwidth]{assets/authn-static-tokens.png}
        \caption{Static tokens}
    \end{subfigure}
    \begin{subfigure}{0.323\textwidth}
        \centering
        \includegraphics[width=\textwidth]{assets/authn-webhook-tokens.png}
        \caption{Webhook tokens}
    \end{subfigure}
    \hspace{1pt}
    \begin{subfigure}{0.323\textwidth}
        \centering
        \includegraphics[width=\textwidth]{assets/authn-sa-tokens.png}
        \caption{ServiceAccount tokens}
    \end{subfigure}
    \hspace{1pt}
    \begin{subfigure}{0.323\textwidth}
        \centering
        \vspace{1em}
        \includegraphics[width=\textwidth]{assets/authn-oidc-tokens.png}
        \caption{OpenID Connect tokens}
    \end{subfigure}
    \caption{Kubernetes 身份驗證手段簡易示意圖}
\end{figure}

Kubernetes 中的 X.509 憑證即為 TLS 客戶端憑證 (client certificate),在 TLS 的驗證模型下,除了伺服器端需要提供憑證證明本身的真實性以外,客戶端也可以提供憑證,使伺服器端得以驗證客戶端的身份 (client certificate authentication, CCA)。此機制近期又以 mutual TLS (mTLS) 的名稱流行,強調雙方都可以驗證彼此的身份。Kubernetes 將身份名稱與所在群組存放在客戶端憑證的 Subject 屬性內,並且要求憑證來自特定的簽發單位 (certificate authority, CA),通常直接由叢集管理,藉此確保資訊的真實性。雖然 X.509 標準有定義憑證的撤銷機制\cite{rfc5280}\cite{rfc6960},但目前 Kubernetes 並沒有相關實作,導致只能利用簽發短效期的憑證,達到金鑰洩漏場景的減災。缺乏撤銷機制也使得這個驗證方法不易修改身份資訊。由於客戶端憑證較不方便使用,尤其需要透過頻繁換發短效期憑證達到安全性,相關自動化成本較高,除了叢集內部元件的身份驗證外,較不常用於使用者端,多見於非正式環境,或是另外嚴謹保存作為管理者的備用手段。

Authenticating proxy 透過在 Kubernetes API 之前加一層代理伺服器進行驗證邏輯。在將請求轉發給 Kubernetes API 時,代理伺服器會加上約定的 HTTP headers 以表達使用者身份。對於代理伺服器驗證使用者的方式並沒有限制。這個方法等同於將驗證邏輯直接抽出另外自行實做,相當富有彈性,但開發成本較高,並且需自行注意撤銷等機制是否完善。

其餘的手段皆是透過 token 進行身份驗證,但 token 本身有所不同。Static tokens 是在 Kubernetes 本身預先設定好一個 token 對應身份資訊的清單,token 本身通常採用一個隨機的字串。由於目前更動這份清單需要重新啟動 kube-apiserver,這個方法較少叢集採用。Webhook tokens 則是透過管理者提供的 HTTP API 將 token 對應到身份資訊,比 static tokens 來的有彈性,可以動態更動而不須重啟 kube-apiserver。

ServiceAccount tokens 與 OpenID Connect tokens 則皆採用 JSON Web Token (JWT)\cite{rfc7519},一個有經過簽章的 token 格式,裡面包含身份資訊與效期等,Kubernetes 透過驗證簽章來確保真實性。ServiceAccount 是一個 resource 種類,代表一個身份,但不支援群組,由其可以簽發 ServiceAccount tokens。刪除 ServiceAccount resources 可以撤銷全部由其發出的 tokens,簽發 token 時也可以進一步綁定 Secrets\footnote{Secret: Resource 種類,提供資料儲存,本身並不帶有任何功能。} 或 Pods,使用當下會額外檢查這些 resources 是否存在,達成以 token 為單位的撤銷。由於可以透過 Kubernetes API 管理,ServiceAccount tokens 常用於自動化場景,也常用於 controllers 元件。因為 ServiceAccount tokens 採用標準的 JWT 格式,透過簽章即可確認真偽,也有自 Kubernetes 存取外部系統時,供外部系統驗證來源的應用。

OpenID Connect (OIDC)\cite{oidc} 則是一個基於 OAuth 框架衍生的身份驗證協定,廣泛運用於網頁應用場景,由中心化的伺服器進行驗證,將身份資訊授予其他應用使用,並且可以讓使用者管理對應用存取身份資料的授權。Kubernetes 本身並不實做 OIDC 協定,而是利用此機制下,OIDC 伺服器所簽發的 JWT(在協定上以 \verb|id_token| 稱呼)進行驗證,並預期由客戶端處理 OIDC 協定流程。由於可以跟現有 OIDC 伺服器整合,實做容易且不須額外的使用者註冊流程,常用於使用者的互動存取。

\begin{table}[htb]
    \centering
    \caption{Kubernetes 驗證機制彙整}
    \setlength{\tabcolsep}{4pt}
    \begin{tabular}{l || c | c | c | l}
        & 效期 & 撤銷 & 管理、開發成本 & 典型場景 \\
        \hline\hline
        X.509 憑證 &&&& 叢集內部、測試環境 \\ \hline
        Authenticating proxy & 自行實做 & 自行實做 && 需深入客製化時 \\ \hline
        Static tokens &&&& 小型規模叢集 \\ \hline
        Webhook tokens & 自行實做 & 自行實做 && 需客製化時 \\ \hline
        ServiceAccount tokens &&&& 工作負載、自動化 \\ \hline
        OpenID Connect tokens &&&& 使用者互動存取 \\
    \end{tabular}
\end{table}

\subsection{Kubernetes 存取控制}

Kubernetes 主要透過兩個機制達成使用者的存取控制,其一是 RBAC (Role-based access control)。RBAC 可以根據 resources 的種類、所在的 Namespace 或是特定的 resource 實例授予使用者對其進行各種操作的權力,包含創立、刪除、更新、獲取、列舉等,不同類型的操作可以分別授予\cite{rostami2023role}。

另一個機制為 admission control,在 RBAC 後執行,可以根據被創立或更新的 resource 內容進行管控。實做控制邏輯的 admission controllers 主要又分為 mutating 與 validating 兩種。Mutating admission controllers 可以修改 resources 內容,常用於對 resource \verb|spec| 中的特定欄位賦予預設值。以 mutating admission controllers 賦予預設值的方法,比起在實做 resources 的 controller 定義預設行為,以使用者的角度更為明確,使用者可以觀察最終儲存的 resource 內容得知其行為,對於平台提供者,透過這個機制實做平台特定的預設值也更為方便。Validating admission controllers 則無法修改 resources 內容,只能做出允許或拒絕操作的決策,為了能夠驗證修改後的 resources 內容,編排在 mutating admission controllers 後執行,常用於執行特定設定上的管制政策。

由於 Kubernetes 功能上的廣泛,不適合將每個功能都規劃成獨立的 resource 種類,用 RBAC 針對 resource 種類進行存取控制有時會顯得不足,admission control 便補足了這方面的彈性。例如在 Linux 系統下容器的隔離措施具備模組化設計,可以依據需求不使用特定措施,Kubernetes 的 Pod 也沿襲了這個設計,雖在特殊場景有其用途,但在其外卻可能導致容器得以滲透運行的節點。由於仍屬於 Pod 種類,在 RBAC 下無法獨立限制此類使用行為,需以 admission control 另外進行加固。

Kubernetes 內建許多 admission controllers,其中一些用來實做基本功能並預設啟用,如資源配額的部份邏輯。另外也有些預設停用的 admission controllers,提供給管理者進行平台加固或者調整行為使用。這些 admission controllers 採取深度的切分設計,以適應多種不同的 Kubernetes 運用場景。如何針對場景配置各個 admission controllers,搭配出完整的解決方案,則是管理者需要專精研習的部份。

對於內建的 admission controllers 不敷使用的場合,Kubernetes 提供兩個機制讓管理者進一步自訂邏輯:webhooks 與 Common Expression Language\cite{cel} (簡稱 CEL)。Webhooks 透過呼叫管理者提供的 HTTP API 達成,支援 mutating 與 validating,可以透過任何能架設 HTTP API 的語言編寫,在生態系上已經有多個框架可以協助開發,例如:Open Policy Agent 與 Kyverno 等。CEL 為一結構資料處理語言,常用以使軟體功能可程式化,Kubernetes 將其導入作為延伸 kube-apiserver 邏輯的手段。以 Kubernetes 1.31 而言,目前只有 validating 進入穩定狀態,對 mutating 的支援仍在開發。相對於 webhooks,使用 CEL 可以直接在 kube-apiserver 上執行邏輯,省略了呼叫 HTTP API 的網路溝通,減少造成的延遲影響與管理負擔,但能夠進行的操作受限於 Kubernetes 對其執行環境提供的函式庫。

\section{Helm}

Helm\cite{helm} 是用來簡化 Kubernetes 上的應用部屬流程的工具,其原理為透過模板化,使得部屬上的設定可以透過更貼近應用本身的角度撰寫。在 Kubernetes 上,典型的部屬應用流程涉及多個 resources,例如:Deployment\footnote{Deployment: Resource 種類,提供高層次的 Pod 管理,以實做 Pod 的更新與複製等。} 用以管控 Pods、Service 將 Pods 提供的服務集結做負載均衡、Ingress\footnote{Ingress: Resource 種類,配置叢集的 HTTP 反向代理,將多個網頁服務集中提供外界存取。} 為 Service 的網頁服務設立反向代理至公網公開等。多個 resources 使得應用部屬有一定的複雜程度,Helm 可以提供更高層級、以應用為中心的單一設定界面,藉此簡化 Kubernetes 的使用。

Helm 用來產生 Kubernetes resources 的模板稱為 Helm Chart,Helm Charts 會集中在 Helm Repository 裡提供使用,Helm Chart 的模板參數稱為 Helm Values,由 Helm 安裝起來的一套應用稱為 Helm Release。透過模板產生的 resources 定義除了套用到叢集上以外,Release 會對其額外進行版本紀錄,用以實做更新、回滾、解除安裝等操作。Release 的版本追蹤資訊通常以 Secrets 的形式儲存在叢集內。

\begin{figure}[htb]
    \centering
    \includegraphics[width=\textwidth]{assets/helm.png}
    \caption{Helm 原理示意圖}
\end{figure}

Helm 使得在 Kubernetes 叢集上安裝軟體變得相當簡便,Helm Chart 已經成為十分常見的軟體交付手段。在生態系上,軟體開發者通常會於自行架設的 Helm Repository 提供產品的 Helm Charts。另外也存在第三方的業者(如 Bitnami)對常見的開放原始碼軟體進行包裝,大量的提供 Helm Charts。

\section{Single-Page Application}

Single-Page Application (簡稱 SPA)是一種網頁架構。傳統網頁架構由伺服器端控制網頁內容,在伺服器上執行模板輸出 HTML。SPA 則以 API 的形式從伺服器端獲取資料,再由瀏覽器端執行呈現邏輯。以瀏覽器端控制呈現可以局部的修改 HTML,在不重新載入整個頁面的情況下達到動態的資料更新。SPA 同時也以瀏覽器端邏輯控制頁面導覽,透過局部更新使在不同頁面間的轉換更為順暢。不同網址的頁面實質上是以同樣的起始 HTML 載入瀏覽器端程式碼,再經由程式碼中的分流邏輯根據網址做不同的呈現。比起傳統網頁架構,SPA 除了能達成更流暢的使用者體驗外,因為將呈現邏輯移到了瀏覽器端,於伺服器端的負擔降低,在運行成本上也有相當的優勢。在網頁編寫上,將資料處理(伺服器端)與資料呈現(瀏覽器端)分離,也有助於將兩者使用不同語言或框架,分別採用對更擅長於該方面的產品實作。

\section{WebAssembly}

WebAssembly\cite{haas2017bringing} (簡稱 WASM)是在瀏覽器上的一個通用型虛擬機指令集,用途並非模擬特定實際存在的硬體架構,而是提供一個一致的軟體執行環境。比起其他類似目的的通用虛擬機(如 Java virtual machine),WebAssembly 設計上更接近硬體,但仍然維持一定程度的通用性,使其能夠在各種不同的硬體架構上,以較為接近原生應用的效能執行。許多程式語言透過於編譯器增加對 WebAssembly 指令集的支援,達成有效率地支援瀏覽器環境,使得網頁開發技術有更多不同的選擇,同時也有利於將一般應用程式或函式庫移植到瀏覽器上運行。WebAssembly 也包含與瀏覽器上 JavaScript 程式碼界接的基本要素,使得 WebAssembly 程式可以利用瀏覽器上既有的程式化界面,另外也令網頁開發能夠採取傳統 JavaScript 與 WebAssembly 混合的策略。

% 以下講了沒啥用 不講又覺得缺了點什麼

WebAssembly 近期也發展出網頁生態以外的應用\cite{spies2021evaluation}。透過 WebAssembly 與外界溝通的能力,只須定義 Application Binary Interface (ABI),即可建構一個擴充元件的機制,使得軟體產品能夠利用多種不同的程式語言擴充邏輯,並且不受運行環境的硬體架構限制,比起傳統使用 C 語言動態載入函式庫作為中介的方式來的更有彈性。