如何像 Sealos 一样在浏览器中打造一个 Kubernetes 终端?
作者:槐佳辉。Sealos maintainer
在 Kubernetes 的世界中,命令行工具(如 kubectl
和 helm
)是我们与集群交互的主要方式。然而,有时候,我们可能希望能够在 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 的访问权限,可以执行 kubectl
,helm
等命令。
下面是一个 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 控制器的类型,可以是nginx
或apisix
。keepalived
: Terminal 的生存时间。例如,4h
表示 Terminal 在被创建 4 小时后会被自动删除。replicas
: Terminal 的副本数。目前只支持1
。token
: Kubernetes API 服务器的访问令牌。Terminal 使用此令牌进行鉴权。
在 status
部分,以下是各字段的说明:
availableReplicas
: 可用副本数量。domain
: 用于在 Web 中与 Terminal 交互的地址。
创建 Terminal
CRD 后,Web 页面中就会打开一个新的 Terminal。用户可以在这个 Terminal 中执行 kubectl
,helm
等命令。
设计与实现
Terminal
功能的设计与实现包括以下几个关键部分:
Terminal Controller
Terminal
Controller 是 Terminal
功能的核心部分。它负责监听 Terminal
CRD 的创建、更新和删除事件,并响应这些事件。
Terminal Pod
Terminal
Pod 是实际运行的 Terminal。它运行一个特殊的 Docker 镜像,这个镜像包含了 kubectl
,helm
等命令行工具,以及一个 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,包含了 kubectl
,helm
等命令行工具,以及一个 Web 终端服务器 ttyd。此外,该镜像还包含了 MySQL,MongoDB,Redis 的客户端,以便用户能够直接在 Terminal 中连接和操作这些数据库。
这个 Docker 镜像的构建过程如下:
-
安装必要的软件包,包括
kubectl
,helm
,vim
等。 -
将 Web 终端服务器
ttyd
和一个启动脚本start-terminal.sh
添加到镜像中。 -
设置
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 机制来自动删除过期的 Terminal
。Terminal
的生存时间由 keepalived
字段指定,当 Terminal
存在的时间超过 keepalived
指定的时间后,Terminal
Controller 会自动删除 Terminal
。
前后端交互流程
下面是用户从点击 Terminal 按钮到进入 Terminal 的具体流程:
-
用户在 Web 页面中点击 Terminal 按钮,页面会发送一个请求到后端,请求中包含了 Terminal 的配置信息(如 Kubernetes Namespace 和生存时间)。
-
后端接收到请求后,会创建一个新的
Terminal
CRD,CRD 中包含了 Terminal 的配置信息。 -
Terminal
Controller 监控到新的Terminal
CRD 被创建,会创建一个对应的Terminal
Pod,Pod 运行的 Docker 镜像包含了kubectl
,helm
等命令行工具,以及一个 Web 终端服务器。 -
Terminal
Controller 还会创建一个对应的 Kubernetes Service 和 Ingress,Service 将网络流量路由到Terminal
Pod,Ingress 将外部访问请求路由到 Service。 -
后端会从
Terminal
CRD 的status
字段中获取到 Terminal 的域名,并将这个域名返回给前端。 -
前端接收到 Terminal 的域名后,会在新的标签页中打开这个域名,用户就可以看到一个新的 Terminal,并可以在这个 Terminal 中执行
kubectl
,helm
等命令。
自定义配置
多种 Ingress 控制器支持
Terminal
支持多种 Ingress 控制器,包括 Nginx 和 Apisix。用户可以根据自己的实际情况选择合适的 Ingress 控制器。
生存时间设置
用户可以设置 Terminal
的生存时间。Terminal
在被创建一段时间后会被自动删除,这样可以防止 Terminal
长时间未使用而占用系统资源。
未来的改进
更多的命令行工具支持
在 Terminal
Docker 镜像中添加更多的命令行工具,如 istioctl
,kn
等,这样用户就可以在 Terminal
中执行更多的操作。
更多的 Ingress 控制器支持
支持更多的 Ingress 控制器,如 Traefik,HAProxy 等,用户可以根据自己的实际情况选择合适的 Ingress 控制器。
使用 WebSocket 通信
通过 Ingress 暴露 WebSocket 服务。用户可以在 Web 页面中打开一个终端,通过 WebSocket 与 Kubernetes 集群进行交互。相比于 HTTP 协议,WebSocket 提供了更高效、实时的双向通信能力,极大地提升了用户的使用体验。
权限控制
增加权限控制功能,后续增加企业协作功能,多用户共享 namespace,terminal 通过获取相应权限来获得对应用户空间的权限,如 manager, developer 等。
集成更多开发工具
除了 kubectl
和 helm
外,还可以在 Terminal
中集成更多的开发和调试工具,如 git
,curl
,jq
等。
个性化配置
用户可以根据自己的需要,配置 Terminal 的外观,如主题颜色,字体大小等。也可以配置 Terminal 的行为,如命令历史记录的长度,键盘快捷键等。
结论
通过 Kubernetes 的 CRD 功能,我们可以轻松地在 Web 页面中添加一个功能强大的 Terminal。用户可以在这个 Terminal 中执行各种命令,更好地与 Kubernetes 集群交互。这不仅提高了用户的工作效率,也极大地提升了用户的使用体验。