透過 Kubernetes Exec API 串接 WebSocket 實現 Web Terminal
一般我們在操作 K8S (Kubernetes) 都是透過 kubectl 命令,其實 kubectl 所有操作都是呼叫 K8S 提供的標準 WebService API,然而有時候需要進 Container Debug 的時候就需要透過 exec 功能。有用過 K8S Dashboard 應該也知道,管理者可以任意進入某一個 Container Terminal,其實就是透過 exec sh command 來實現。我一直很好奇 K8S Dashboard 要如何在 Web 實現這樣的功能,查一下果然不出所料有一個 WebSocket API 可以使用,於是開始研究如何自己實現像是 Dashboard Terminal 這樣的功能。
K8S Exec Command API WebSocket 串接
我今天的目的是要在 Web 做出跟 K8S Dashboard Terminal 一樣的功能,其中必須透過 WebSocker API 進行串接。這一個 Exec API 官方說明相當少,其實有一個 Kubernetes Project,叫做 container-terminal 已經有實做一樣的功能,但是我實際測試的時候並不 work,因為 K8S API 呼叫的 Token 必須透過 HTTP Header 傳遞,然而標準的 HTML5 並沒有夾帶自訂 Header 的方法,container-terminal 所使用在 Query String 夾帶 access_token 並不是標準作法。
我按下 F12 光明正大偷看了 K8S Dashboard 的作法,發現是透過 Cookie 自行驗證 WebSocket 權限,看來要透過 HTML5 標準來呼叫 API 就要自己實做 Server 了。
開始以前,我們先看看只有一條 IO 特性的 WebSocket 如何處理 exec 呢?其實 exec 就是命令呼叫,所有的程式在 Linux 執行一個程序都是一樣的,程序啟動時會分配三個檔案描述子 (File Descriptor),分別是 StdIn (標準輸入), Std Out (標準輸出), Std Error Out (標準錯誤輸出),當我們的 WebSocket 成功 Upgrade 為 TCP/IP 之後,K8S API 必須提供一個協定來處理這三種標準描述子的收發工作。區分方法就是在資料最前端加入一個 Byte,如下:
Byte 0 : 標準輸入
Byte 1 : 標準輸出
Byte 2 : 標準錯誤輸出
有了這些資訊我們就可以開始實做了 WebSocket 串接了。
透過 WebSocket 串接 K8S Exec API 實現 Terminal
由於剛剛提到 HTML5 WebSocket 標準並不提供自訂的 HTTP Header,因此我的想法是在 Server 端透過 NodeJS 夾帶 Token 來連線 K8S Exec WebSocket API,因為不在 Browser 的 NodeJS 就可以自訂 Request Header 好通過 K8S 的驗證機制。然後另外啟動一個 WebSocket Server 提供瀏覽器進行連線,當然這裡的認證機制要自己實做了,可以用 Cookie/Session 控制即可,這樣一來也不需要暴露 API Token。總而言之就是一個左手接右手傳的機制,這裡的終端機介面移植 container-terminal 用了 xterm.js 套件,跑起來的畫面如下:
這樣一來就可以在瀏覽器操作你的 Container,由於是命令模式並非 VM 那種傳整個畫面的終端機,所以用起來貌似飛快,速度就跟平常使用 SSH 差不多速度,滿酷炫的。
範例程式碼在 GitHub 有興趣請自己玩看看囉。
https://github.com/samejack/web-k8s-exec
此外,上述提到的 K8S API WebSocket 協定,其實用在 Log API 也是一樣的,就可以在 Web 做出 logs 畫面的即時輸出,也是很方便。閃電分享結束.......下台一鞠躬~