如何像 Sealos 一樣在瀏覽器中打造一個 Kubernetes 終端?

2023-09-12 12:00:50

作者:槐佳輝。Sealos maintainer

在 Kubernetes 的世界中,命令列工具(如 kubectlhelm)是我們與叢集互動的主要方式。然而,有時候,我們可能希望能夠在 Web 頁面中直接開啟一個終端,執行這些命令,而不需要在本地環境中安裝和設定這些工具。本文將深入探討如何通過 Kubernetes 自定義資源定義(CRD)實現這個功能,並通過一個真實的範例展示其設計和實現過程。

Sealos 中的 App Launchpad 和 Database 等應用為我們遮蔽掉了 kubernetes 資源層面的邏輯,抽象為應用層,但是對應更為複雜的情況,可能需要我們更原生的操作 kubernetes。

如下所示,在 Terminal 中與 K8s API Server 互動:

檢視 Pod 資源(kubernetes 最小排程單位,真正執行容器的資源):

$ kubectl get pod

檢視儲存 pvc 資源(容器掛載的儲存資源,如 App Launchpad 中指定的儲存):

$ kubectl get pvc

Terminal 高階用法

Terminal 還支援更為複雜的操作。

Terminal + App Launchpad 一鍵互動

可以直接通過終端 App 進入每個應用所在容器的終端。假設你在應用管理中部署了一個應用 Nginx,可以直接進入 Nginx 應用的詳情頁面,依次點選詳情右側的三個點,再點選「終端」,便進入了 Nginx 應用的終端。

Terminal + Database 一鍵直連

在終端中一鍵直連資料庫 App 中建立的資料庫。

進入資料庫詳情頁面,點選左側的「一鍵連線」:

跳轉到 Terminal 並直連資料庫:

功能描述

這個功能的核心是一個名為 Terminal 的 Kubernetes CRD。使用者可以在 Web 頁面中建立一個新的 Terminal CRD,然後頁面會開啟一個新的 Terminal。這個 Terminal 具有指定 Kubernetes Namespace 的存取許可權,可以執行 kubectlhelm 等命令。

下面是一個 Terminal CRD 的範例:

spec:
  apiServer: https://kubernetes.default.svc.cluster.local:443
  ingressType: nginx
  keepalived: 4h
  replicas: 1
  token: xxxxx
status:
  availableReplicas: 1
  domain: https://xxxxxx.cloud.sealos.io

CRD 欄位說明

Terminal CRD 的 spec 部分,以下是各欄位的說明:

  • apiServer: Kubernetes API 伺服器的地址。Terminal 使用這個地址與 Kubernetes API 伺服器通訊。
  • ingressType: Ingress 控制器的型別,可以是 nginxapisix
  • keepalived: Terminal 的生存時間。例如,4h 表示 Terminal 在被建立 4 小時後會被自動刪除。
  • replicas: Terminal 的副本數。目前只支援 1
  • token: Kubernetes API 伺服器的存取令牌。Terminal 使用此令牌進行鑑權。

status 部分,以下是各欄位的說明:

  • availableReplicas: 可用副本數量。
  • domain: 用於在 Web 中與 Terminal 互動的地址。

建立 Terminal CRD 後,Web 頁面中就會開啟一個新的 Terminal。使用者可以在這個 Terminal 中執行 kubectlhelm 等命令。

設計與實現

Terminal 功能的設計與實現包括以下幾個關鍵部分:

Terminal Controller

Terminal Controller 是 Terminal 功能的核心部分。它負責監聽 Terminal CRD 的建立、更新和刪除事件,並響應這些事件。

Terminal Pod

Terminal Pod 是實際執行的 Terminal。它執行一個特殊的 Docker 映象,這個映象包含了 kubectlhelm 等命令列工具,以及一個 Web 終端伺服器(例如 ttyd)。Pod 內的 Web 終端伺服器監聽 8080 埠,並提供 Web 終端服務。

Service 和 Ingress

Terminal Controller 為每個 Terminal CRD 建立一個對應的 Kubernetes Service 和 Ingress。Service 將網路流量路由到 Terminal Pod,Ingress 將外部存取請求路由到 Service。

Terminal Docker 映象

Terminal Docker 映象是 Terminal Pod 執行的映象。它基於 Ubuntu 20.04,包含了 kubectlhelm 等命令列工具,以及一個 Web 終端伺服器 ttyd。此外,該映象還包含了 MySQL,MongoDB,Redis 的使用者端,以便使用者能夠直接在 Terminal 中連線和操作這些資料庫。

這個 Docker 映象的構建過程如下:

  1. 安裝必要的軟體包,包括 kubectlhelmvim 等。

  2. 將 Web 終端伺服器 ttyd 和一個啟動指令碼 start-terminal.sh 新增到映象中。

  3. 設定 ttyd 伺服器監聽 8080 埠,並設定 ttyd 伺服器的啟動引數,包括 Kubernetes API 伺服器的地址和存取令牌。

這個 Docker 映象的 Dockerfile 如下:

FROM ubuntu:20.04
LABEL org.opencontainers.image.authors="labring"

USER root
ENV HOME /root
ARG kubeVersion=1.25.6
ARG ttydVersion=1.7.3
ARG helmVersion=3.12.0
ARG ARCH
ARG DEBIAN_FRONTEND=noninteractive

WORKDIR /root
COPY ./inline.html ./index.html
COPY vim/ .
COPY scripts/start-terminal.sh /usr/bin/
COPY scripts/ttyd-kubectl.sh /usr/bin/

RUN arch && \
    apt-get update && \
    apt-get install -y --no-install-recommends -o Acquire::http::No-Cache=True \
    ca-certificates curl wget bind9-utils git g++ gcc libc6-dev make pkg-config vim \
    ncurses-dev libtolua-dev exuberant-ctags gdb dnsutils iputils-ping net-tools postgresql-client && \
    apt-get clean && rm -rf /var/lib/apt/lists/* && \
    chmod a+x /usr/bin/ttyd-kubectl.sh && \
    bash /usr/bin/ttyd-kubectl.sh && \
    vim +PlugInstall +qall && \
    chmod a+x /usr/bin/start-terminal.sh

ENV USER_TOKEN ""
ENV APISERVER "https://apiserver.cluster.local:6443"
ENV USER_NAME "admin"
ENV NAMESPACE "default"

EXPOSE 8080

CMD ["sh","/usr/bin/start-terminal.sh"]

映象 Dockerfile:https://github.com/labring-actions/cluster-image/blob/main/dockerimages/terminal/latest/Dockerfile

映象託管 GitHub 自動化構建倉庫:https://github.com/labring-actions/cluster-image

Terminal 刪除和生存時間

Terminal Controller 使用 Kubernetes 的 Finalizer 機制來處理 Terminal CRD 的刪除事件。當 Terminal CRD 被刪除時,Finalizer 會阻止 Kubernetes 立即刪除 CRD,而是等待 Terminal Controller 清理與 Terminal CRD 相關的資源(如 Deployment,Service 和 Ingress)後再刪除 CRD。

此外,Terminal Controller 還使用 Keepalive 機制來自動刪除過期的 TerminalTerminal 的生存時間由 keepalived 欄位指定,當 Terminal 存在的時間超過 keepalived 指定的時間後,Terminal Controller 會自動刪除 Terminal

前後端互動流程

下面是使用者從點選 Terminal 按鈕到進入 Terminal 的具體流程:

  1. 使用者在 Web 頁面中點選 Terminal 按鈕,頁面會傳送一個請求到後端,請求中包含了 Terminal 的設定資訊(如 Kubernetes Namespace 和生存時間)。

  2. 後端接收到請求後,會建立一個新的 Terminal CRD,CRD 中包含了 Terminal 的設定資訊。

  3. Terminal Controller 監控到新的 Terminal CRD 被建立,會建立一個對應的 Terminal Pod,Pod 執行的 Docker 映象包含了 kubectlhelm 等命令列工具,以及一個 Web 終端伺服器。

  4. Terminal Controller 還會建立一個對應的 Kubernetes Service 和 Ingress,Service 將網路流量路由到 Terminal Pod,Ingress 將外部存取請求路由到 Service。

  5. 後端會從 Terminal CRD 的 status 欄位中獲取到 Terminal 的域名,並將這個域名返回給前端。

  6. 前端接收到 Terminal 的域名後,會在新的分頁中開啟這個域名,使用者就可以看到一個新的 Terminal,並可以在這個 Terminal 中執行 kubectlhelm 等命令。

自定義設定

多種 Ingress 控制器支援

Terminal 支援多種 Ingress 控制器,包括 Nginx 和 Apisix。使用者可以根據自己的實際情況選擇合適的 Ingress 控制器。

生存時間設定

使用者可以設定 Terminal 的生存時間。Terminal 在被建立一段時間後會被自動刪除,這樣可以防止 Terminal 長時間未使用而佔用系統資源。

未來的改進

更多的命令列工具支援

Terminal Docker 映象中新增更多的命令列工具,如 istioctlkn 等,這樣使用者就可以在 Terminal 中執行更多的操作。

更多的 Ingress 控制器支援

支援更多的 Ingress 控制器,如 Traefik,HAProxy 等,使用者可以根據自己的實際情況選擇合適的 Ingress 控制器。

使用 WebSocket 通訊

通過 Ingress 暴露 WebSocket 服務。使用者可以在 Web 頁面中開啟一個終端,通過 WebSocket 與 Kubernetes 叢集進行互動。相比於 HTTP 協定,WebSocket 提供了更高效、實時的雙向通訊能力,極大地提升了使用者的使用體驗。

許可權控制

增加許可權控制功能,後續增加企業共同作業功能,多使用者共用 namespace,terminal 通過獲取相應許可權來獲得對應使用者空間的許可權,如 manager, developer 等。

整合更多開發工具

除了 kubectlhelm 外,還可以在 Terminal 中整合更多的開發和偵錯工具,如 gitcurljq 等。

個性化設定

使用者可以根據自己的需要,設定 Terminal 的外觀,如主題顏色,字型大小等。也可以設定 Terminal 的行為,如命令歷史記錄的長度,鍵盤快捷鍵等。

結論

通過 Kubernetes 的 CRD 功能,我們可以輕鬆地在 Web 頁面中新增一個功能強大的 Terminal。使用者可以在這個 Terminal 中執行各種命令,更好地與 Kubernetes 叢集互動。這不僅提高了使用者的工作效率,也極大地提升了使用者的使用體驗。