夜雨聆风学习资料网

ARTICLE · 1115121

当我把 k8s 的管理接入 dsh 插件系统后

当我把 k8s 的管理接入 dsh 插件系统后

/我是怎样把 Kubernetes 管理,做进 DSH 的?/

日常使用 Kubernetes,少不了几件事:切换集群、查看 Pod、检查日志、进入容器,以及调整工作负载。

这些操作,kubectl 都能完成。但当它们穿插在开发和排障过程中时,我往往需要反复切换窗口、输入命令,再把结果带回当前的工作界面。

于是,我有了一个想法们能不能直接使用我常用的 dsh 进行管理?

能不能把常用的 Kubernetes 管理操作,直接放进 DeepSeek Harness(DSH)?

围绕这个想法,我做出了 dsh-k8s,一个使用本地 kubectl 的 DSH 集群管理插件。

从第一版跑起来,到适配 DSH 0.2,整个过程里,真正花心思的地方,既有功能实现,也有那些“用起来才发现”的细节。

1

01|先让一条完整的操作路径跑起来

第一版的目标很具体:

添加集群后,能够浏览资源;找到某个 Pod 后,能够查看 YAML、读取日志,并进入容器。

我围绕这条路径搭起了插件的基本结构。

客户端负责展示和交互。

集群选择、资源导航、列表、详情,以及日志和终端,都放在插件页面里。

宿主端负责执行操作。

页面发起请求后,由宿主调用本地 kubectl,再把执行结果返回给界面。

这样,插件可以直接使用本机的工具和集群配置,不需要额外部署一个远程管理服务。

把它想成一条简单的链路,就容易理解了:

插件界面 → DSH 宿主 → 本地 kubectl → Kubernetes 集群

这个结构,也成为后续迭代的基础。

2

02|多集群管理,从 kubeconfig 开始

管理 Kubernetes,首先要解决“当前操作的是哪个集群”。

我为插件增加了集群配置管理:输入名称、粘贴 kubeconfig、保存,然后通过顶部下拉框切换。

每份配置单独保存在本地。执行命令时,插件通过 KUBECONFIG 指定对应文件,让每次操作明确绑定到所选集群。

但配置接入很快带来了一个具体问题。

kubeconfig 里的 current-context,不一定指向一个实际存在的 context。

早期实现根据 current-context 获取名称,再进行重命名。遇到这类配置时,这条路径就会出问题。

我调整了处理方式:先读取配置里实际存在的 context,再选择、重命名并设置当前 context。

这次修复没有带来一个显眼的新按钮,却解决了基础连接路径中的问题。

做工具时,经常会遇到这样的情况:页面已经能显示,功能也已经写完,但只有接入真实配置,才知道哪些假设需要改。

3

03|资源能列出来之后,还要让人找得到

第一版已经覆盖了多种常用资源,包括 Pod、Deployment、Service、ConfigMap、存储资源和节点等。

接下来,我开始打磨资源浏览的体验。

资源数量一多,单纯列出数据就不够用了。用户需要快速缩小范围,也需要知道下一步可以点哪里。

因此,在后续版本里,我重新整理了:

  • 概览卡片与资源列表的跳转;
  • 命名空间、Pod 阶段和节点状态筛选;
  • 关键词搜索;
  • 表格列的对齐与状态展示;
  • 资源详情和窄窗口布局。

例如,点击概览中的某类 Pod,可以直接进入对应阶段的资源列表;点击资源名称,则打开详情查看 YAML。

这里还有一个容易混淆的细节:

Pod 的阶段,与页面展示的具体异常状态,并不是同一个概念。

ImagePullBackOff 可以帮助我判断问题,但它并不是 Pod 的 phase。我需要分别处理筛选依据和展示信息,才能让列表行为与 Kubernetes 的实际含义保持一致。

这些细节看起来很小,却会影响用户对工具的信任。

4

04|容器终端,是这次迭代里的一道难题

查看资源和读取 YAML,主要是在处理请求与结果。

交互式终端则复杂得多。

它需要持续传输输入输出,还要处理中文字符、窗口尺寸变化,以及连接关闭后的进程清理。

旧实现使用独立的 node-pty,出现过:

posix_spawnp failed

这个问题促使我重新梳理终端的实现。在适配 DSH 0.2 时,我改用宿主提供的托管 PTY,通过 subprocess.spawnTerminal() 创建终端。

浏览器端由 xterm.js 展示终端,通过 WebSocket 与宿主双向传输数据,再由宿主运行 kubectl exec -it 进入容器。

我同时补齐了几件容易遗漏的事:

输入输出要正确处理 UTF-8。

否则中文输入和输出可能出现问题。

终端尺寸要同步。

窗口或详情面板变化后,容器里的终端也需要知道新的行列数。

连接结束后要清理进程。

断开连接、关闭详情或卸载插件时,都要结束对应终端。

做到这些,页面里的终端才真正成为一条可用的排障路径。

5

05|适配 DSH 0.2,先把插件和宿主重新接好

终端之外,这次迭代还有一项基础工作:适配 DSH 0.2。

宿主升级后,插件需要重新检查依赖、命令执行方式和客户端入口。只修改版本号,无法完成这次迁移。

原有的客户端接入方式需要调整。我改用 dsh-client-ui-renderer 提供的插槽,把插件页面注册到宿主中;普通命令执行迁移到 shell.execute(),终端则交给宿主的 subprocess 能力。

同时,我移除了已经不再使用的依赖,并在插件声明中明确对应的宿主接口版本。

这一步的目的,是让前端页面、后端命令和终端连接,都能沿着新宿主提供的接口工作。

一个插件看起来只有一个页面,实际上却与宿主有多处连接。页面能打开,不代表后端命令可以执行;资源能读取,也不代表交互式终端已经可用。

因此,这次迁移需要把这些连接逐一接通,并留下兼容性检查。

当前插件版本为 0.2.0,仓库文档明确标注了已验证的宿主版本:DSH 0.2.0-rc.2。对仍在快速变化的预发布接口来说,把这个范围写清楚,也能帮助用户判断安装问题。

6

06|加一个侧栏入口,让集群管理随时可用

接通宿主之后,我重新梳理了进入插件的路径。

早期版本可以在会话视图中打开 Kubernetes 页面。这个入口得以保留,但集群管理也有很多独立于会话的使用场景:看一下节点状态、确认某个服务是否启动,或者临时查一段日志。

为此,我在左侧“插件”区域增加了 Kubernetes 入口。

点击后,就可以直接打开管理页面,无需先创建会话。

在实现上,侧栏入口和主页面通过对应的插槽连接,会话中的 Kubernetes 视图仍然可用。用户可以按照当前的工作方式选择入口。

这项改动并不复杂,却缩短了每次打开插件的路径。

工具会被反复使用,入口上的一步,值得认真处理。

7

07|界面打磨:主题、透明度和窄窗口都要考虑

插件进入宿主之后,还需要解决视觉上的融合问题。

如果界面把背景、文字和边框颜色全部写死,切换 DSH 主题时,插件就容易显得突兀。终端如果继续使用固定配色,也会与周围的页面割裂。

我让页面继承 DSH 的标准主题变量,把文字、按钮、状态色、边框和背景等样式连接到宿主的语义配色。

主画布保持透明,保留宿主背景;终端的配色也会动态同步。

这里需要注意,主题同步涉及的不只是颜色,还有背景的透明度和遮罩。仅仅把背景改成某个色值,可能仍然无法呈现宿主原本的效果。

因此,样式调整时也把这些表现一起纳入考虑。

另一部分工作,是窄窗口适配。

Kubernetes 资源表格通常包含名称、命名空间、状态、重启次数和运行时间等信息。窗口缩小时,导航、表格和详情如果继续挤在一起,阅读会变得困难。

我在窄窗口中让资源导航横向滚动,详情采用覆盖展示,表格也支持横向滚动。

目标是让不同窗口尺寸下,用户仍然能够找到资源、读清状态,再打开详情。

8

08|从查看资源,到完成一次具体操作

能看到资源之后,下一步通常是处理问题。

因此,插件也提供了工作负载操作:编辑并应用 YAML、滚动重启,以及调整副本数。

操作入口放在资源详情中。用户先选中具体资源,查看它的配置,再决定是否进行修改。

不同资源支持的操作有所区别。例如,Deployments、StatefulSets 和 DaemonSets 支持滚动重启;Deployments、StatefulSets 和 ReplicaSets 支持调整副本数。

我在这些会改变集群状态的操作中加入了二次确认。尤其是应用 YAML,界面会提醒用户确认操作对象。

操作完成后,可以手动刷新,获取资源的最新状态。目前资源列表没有自动定时刷新,因此文档也把这一点明确写了出来。

日志则补齐了另一条常用路径:选择 Pod 和容器,先读取最近 300 行,再跟随新日志,需要时停止跟随。

把这些能力连起来,插件就能够支持一个连续的排查过程:

找到异常资源 → 查看配置 → 读取日志 → 进入容器 → 按需要处理工作负载。

这也是我打磨详情面板的原因。资源详情需要承接用户的下一步动作。

9

09|把容易出错的细节,变成可以重复检查的测试

完成迁移和功能调整后,我补充了 30 项回归测试,覆盖兼容性、资源解析与筛选、主题,以及终端生命周期等部分。

这些测试针对的是具体行为。

例如,Pod 表格可能显示 ImagePullBackOff 或 CrashLoopBackOff,但筛选需要使用实际的 phase。测试会检查后端是否保留了这些真实阶段,避免概览卡片跳转后筛选出错误结果。

节点状态也有类似问题。

Ready 和 NotReady 在文字上很接近。如果只根据字符串是否包含“Ready”来判断,就可能把未就绪节点误识别为就绪。

实现中采用节点的 Ready condition 判断,测试则覆盖就绪、未就绪、未知以及缺少对应条件的情况。

还有一些问题,发生在用户离开页面之后。

日志跟随是否在插件卸载时停止?终端断开后是否清理进程?客户端卸载时,注册的入口和注入的样式是否移除?

这些行为不一定能从一张正常的界面截图里看出来,却会影响长时间使用的体验。

测试把这些要求留下来,让下一次修改仍然有依据可查。

仓库提供了类型检查和测试命令:

1npm run typecheck2npm test3

其中,测试命令会先构建,再运行测试,让检查覆盖到构建后的代码。

10

10|写完源码之后,还要让用户装得上

插件开发的最后一段,是构建、安装和升级。

项目包含宿主端和客户端两部分。宿主端输出到 lib/,客户端经过打包后输出到 client/client.js。

客户端构建还有一步后处理:把打包结果包装成 DSH 的 ModuleLoader 能够加载的形式,并接入样式的加载与卸载。

这意味着,修改源码之后,需要完成正式构建,才能让已安装的插件加载到最终产物。

我也在文档中解释了 watch 模式的范围:它只监视客户端源码,不会完成宿主编译和最终客户端包装。要验证完整插件,仍然需要执行构建并重启 DSH。

开发时的临时输出,与用户实际加载的插件,需要明确区分。

安装方式同样需要分场景说明。

桌面客户端通过插件管理页面选择本地项目目录;Web 场景则可以使用对应 profile 的命令,从 GitHub 或本地源码安装。

仓库提交了构建后的 lib/ 和 client/,因此从 GitHub 安装时,无需再手动执行源码构建。

升级后也需要重启宿主。仅刷新页面,不会重新加载后端模块。这类说明看起来很基础,却直接关系到用户能否看到修复后的行为。

11

11|把已知边界写清楚,才能少走排错弯路

最后,我同步更新了中英文 README,把安装、升级、使用方式和常见问题放到一起。

文档里有几处需要特别说清楚。

第一,集群配置的保存与合并方式。

插件扫描的是 ~/.kube/configs/,不会自动导入已有的 ~/.kube/config。添加或删除配置,会根据该目录重新生成主配置,因此操作前需要备份已有主配置。

删除插件中的配置,只会移除本地 kubeconfig 文件,不会删除远端 Kubernetes 集群。

第二,终端连接的前提条件。

DSH 需要能够找到本地 kubectl,目标 Pod 和容器需要可用,容器中需要包含 /bin/sh,账号也需要具备 pods/exec 权限。

第三,不同错误需要沿着不同方向排查。

如果错误仍然显示旧插件版本,或者出现旧终端实现的提示,就需要检查实际加载的版本,并重新构建、安装和重启。

如果安装被宿主的依赖发布时间策略拦截,则需要根据错误中的包名、版本和发布时间检查原因。它与插件接口不兼容并不是同一种问题。

这些内容把开发过程中容易混淆的地方,转成了用户可以遵循的排查步骤。

12

写在最后|从第一版能运行,到一条完整的使用路径

回看仓库记录,2026 年 8 月 21 日,我提交了第一版,随后修正安装说明和集群名称问题;10 月 1 日,完成了 DSH 0.2 适配,以及入口、界面、主题、终端和测试的进一步完善。

这条过程里,没有哪一个按钮能够代表全部工作。

多集群配置决定操作会去哪里;资源状态决定用户看到什么;终端连接决定能否继续排查;主题和布局决定是否顺手;构建和文档则决定别人能否把它真正用起来。

这些部分连在一起,才形成了现在的 dsh-k8s。

在 DSH 里找到资源、查看状态、读取日志,再进入容器继续排查。

这是最初的想法,也是这次开发最终落下来的操作路径。

如果你也在使用 DSH 和 Kubernetes,欢迎看看这个项目。

项目地址:

dsh-k8s · GitHub ( https://github.com/MrYangyt/dsh-k8s )


相关学习资料