ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

OpenShell:一个Go写的本地优先多主机SSH批量执行工具

OpenShell:一个Go写的本地优先多主机SSH批量执行工具 去年冬天的时候我接手了一批旧服务器。机器数量不算夸张也就十来台但它们分散在不同机房用途也完全不一样有的跑线上业务有的做测试还有的是帮朋友托管的小服务。每天最费时间的不是写代码而是在每台机器之间来回切换。登完这台看日志切到另一台查磁盘再切一台拉配置一个上午就这么没了。更痛苦的是想批量跑一个命令比如同时检查所有机器的负载我最初的做法是在本地终端里开好几个窗口复制粘贴同一个命令一个个执行然后靠肉眼对比输出。说句实话这种活干久了人是会暴躁的。所以我决定自己写一个工具名字就叫 OpenShell。它的定位很简单一个本地优先的多主机命令行管理终端把你所有服务器的 SSH 连接、命令执行、脚本下发、结果收集统一收敛到一台本地机器上。你不需要装 Agent不需要把服务器信息托管到任何在线平台不用搞一套重量级系统只需要一个二进制文件一份 YAML 配置就能把散落在各处的远程机器变成一组可以在本地统一操作的“资源池”。这篇文章就是 OpenShell 从想法到落地、再到日常使用的完整复盘。我会从设计思路讲起然后拆解核心实现最后附上完整的配置示例和踩坑记录。如果你也遇到过和我一样的烦恼并且不想引入复杂的外部系统那这篇内容应该能给你一个参考。1. 这个工具到底想解决什么问题1.1 日常操作的三大痛点先说第一个痛点重复登录。服务器一多每次干活的第一步永远是找 IP、找端口、找密钥路径。你心里得记着“这台机器要用 deploy 用户登那台机器改了端口”稍微记岔了就登错。在线索靠不住的时候我甚至会把主机信息贴在一个本地文档里但这玩意儿一旦更新晚了就又是一堆乌龙。第二个痛点是批量执行。运维里最常干的活就是对一组机器做同样的操作更新配置、检查磁盘、重启服务、拉取日志。没有工具的时候你的选择要么是一台台手动执行要么写一个 shell 脚本在脚本里循环 ssh。后者稍微聪明了一点但输出会糊在一起根本分不清哪段输出来自哪台机器而且一旦某台机器连接失败整个脚本的执行流程很快就乱了。说白了这种脚本只能“自己应付自己”完全不具备工程化能力。第三个痛点是可复现性。我今天想让所有机器检查磁盘我临时打了一条命令。下个月我又想再跑一次结果发现自己不记得那条命令长什么样了。命令没有沉淀、没有版本、没有记录每次都是手写。这其实是一种隐性的重复劳动也在不断拉低工作效率。1.2 现有方案的两种极端当时我也看过市面上的一些开源工具方向大致分成两派。一派是重量级的资产管理平台功能很全主机管理、身份认证、合规审计都有。但问题也很明显要部署服务端要开数据库要有 Web 界面要维护一套自己的用户体系。对只有十几台机器的小团队来说这个成本我觉得是溢出的。而且这类系统往往会把服务器凭据集中存到服务端只要服务端出问题所有机器的登录凭据都存在一起风险其实不小。另一派是简单粗暴的“脚本全家桶”一个 sh 文件负责连接一个 txt 文件记主机一个 log 文件存输出。好处是零依赖坏处是没有任何结构性。主机多了之后脚本之间互相调用配置散落各处整个人都会被这种混乱拖进去。OpenShell 想走的是中间路线本地优先不部署服务端用配置文件的声明式写法代替一坨脚本用插件机制代替硬编码功能。没有 GUI不需要在线存储所有状态都留在本地。1.3 适合用它的场景和人群如果你满足下面几条里的任何一条OpenShell 这套思路应该能帮上忙手里有 3 台以上的 Linux 服务器平时要频繁登录操作。经常需要对一组机器跑同样的命令并且关心每台机器的返回结果。不想把服务器信息和登录方式交给第三方在线平台。受够了在多个终端窗口之间反复切换、复制粘贴。希望自己的运维操作有记录、可审计、能重放。这个工具对个人开发者、小团队运维、DevOps 工程师都能适配。它的理念是本地终端是最值得信任的界面你只需要把所有远程机器的入口统一安放到你自己面前的这个终端里。2. 核心设计思路与架构选型2.1 先拆解真实需求动手写代码之前我列了一张需求清单。这很重要因为只有从真实场景出发才不会被花哨的功能带偏。当时我的需求大概是这几条能用一条命令连接任意主机不需要每次敲完整的 ssh 参数。能对一组主机批量执行命令并且清晰区分每台机器的输出。能定义常用的巡检脚本定期复用。能记录每一次操作的输入输出方便事后追溯。能扩展以后想加什么功能不需要改主程序。这里面有一个关键取舍我不需要实时的终端交互。也就是说OpenShell 不打算做成那种“在一个面板里打开好几个 shell 窗口”的工具也不需要像 tmux 那样同步操作。我的核心场景是“发出命令、收集结果”所以工具的主模型应该是命令级而不是会话级。这会直接影响架构设计。如果我做“会话级”那我必须维护一个常驻连接池处理各种终端协议细节复杂度会高很多。而“命令级”就简单了每执行一条命令就建立一次连接执行完后关闭。可能有人会觉得这样效率低但实际用下来SSH 连接建立的耗时通常在几百毫秒到一两秒之间完全可以接受而且这种“短连接”模式天然适合并发和超时控制。2.2 为什么选择 Go 而不是 Python技术栈方面我先否掉了 Python。虽然 Python 写这类工具非常顺手生态里也有 paramiko 这种老牌 SSH 库但 Python 有一个绕不开的坑分发。你要在其他机器上用它就得有一份解释器还得安装依赖哪怕打成 Docker 镜像也显得重。我当时的想法是做一个“丢到 PATH 里就能用”的工具用户不需要理解任何底层依赖。Go 在这方面优势太明显了。编译出来就是单个静态二进制丢到任何 Linux x64 机器上都能直接跑。goroutine 也让并发批量执行变得很简单几十台机器同时发命令只需要控制好并发上限不会像多进程方案那样管理起来很麻烦。SSH 库方面我用了知名的 golang.org/x/crypto/ssh。它虽然不是个“开箱即用”的高层库但底层能力非常扎实可以用它构建出一个完全自定义的执行模型这个自由度比套用封装好的现成库更舒服。2.3 三个核心设计原则OpenShell 从第一天起就定下了三个原则后面所有功能开发都是围绕它们展开的。第一个原则是本地优先。所有配置、密钥、日志、历史记录都放在用户本机的一个目录里不依赖任何外部服务。这意味着断网的时候它也能工作安全边界完全由你自己掌控服务器信息不会出现在任何第三方系统的缓存里。第二个原则是声明式配置。我讨厌在一个散装脚本里用变量拼接字符串来描述“我要连哪台机器、用什么用户名、执行什么命令”。OpenShell 的做法是所有主机信息、分组信息、任务脚本全部用 YAML 文件声明。写配置的过程就是梳理运维资产的过程你一眼就能看出整个环境长什么样。第三个原则是插件化扩展。一开始我也想在主程序里加入各种实用功能比如日志切割、Nginx 状态检查、Docker 容器管理。但后来想明白了这种东西永远做不完。与其在核心里堆功能不如把“执行命令并返回结果”这个最基础的能力做好然后开放插件接口。所有定制化的需求交给插件去解决。3. 安装部署与第一个可用版本3.1 安装保持零依赖体验OpenShell 的安装只有一件事把编译好的二进制文件放到 PATH 里。我用 Makefile 管理构建流程编译命令很直接make build产物会生成在 dist 目录下文件名是 openshell。把它复制到 /usr/local/bin 或者用户目录下的 bin 目录即可cp dist/openshell ~/.local/bin/如果你用 macOS 并且装了 Homebrew也可以直接通过自定义 tap 安装但本质还是下载二进制不涉及系统级依赖。装完之后第一条命令我建议先看看版本openshell version这个命令会同时输出 Go 的编译版本后面排查问题的时候这个信息有时能派上用场。3.2 通过 init 向导生成初始配置OpenShell 安装后默认不会自动创建配置需要你主动跑一次初始化命令openshell init这条命令会做四件事创建 ~/.openshell 目录作为主目录。生成一份空的配置文件 config.yaml。生成一份主机清单样例 hosts.yaml。创建 tasks 和 plugins 两个子目录分别放任务脚本和插件。初始化完成后你可以先不用急着填任何服务器信息。先打开 config.yaml里面主要是日志级别、默认密钥路径、并发数、超时时间等全局参数。我当时的默认配置是这样global: timeout: 30s default_user: root default_key: ~/.ssh/id_ed25519 max_concurrency: 8 log: level: info output: ~/.openshell/logs/openshell.log里面有两个关键参数需要解释一下。default_key 是全局默认的 SSH 私钥路径。我推荐优先使用 ed25519 类型的密钥而不是 RSA。它更短、更快安全性也不错。如果你已经有 RSA 密钥也可以继续用但新生成的密钥我建议统一用 ed25519。max_concurrency 是批量执行时同时开多少个 SSH 连接。这个值不要拍脑袋乱填。如果你对 50 台机器执行同一个命令最大并发是 8那么 OpenShell 会分成 7 批来处理每一批 8 台左右。设得太大会把本地机器的文件描述符打满。8 是我试下来比较稳的一个值你如果机器性能好可以调到 16但我不建议超过 16。3.3 第一份主机清单接下来是 hosts.yaml这是 OpenShell 第一个真正需要你花点心思的配置文件。基础写法如下groups: web: hosts: - 192.168.10.11 - 192.168.10.12 - 192.168.10.13 user: deploy key: ~/.ssh/id_ed25519 db: hosts: - 192.168.10.21 user: dba port: 6322这里说明一下几个字段groups 下每个 key 就是一个分组名。hosts 是机器 IP 或域名列表。user 如果不填就使用 config.yaml 里的 default_user。key 如果不填就使用 default_key。port 如果不填默认走 22。配置写好后可以用 doctor 子命令验证配置是否正确同时测试连接openshell doctordoctor 会逐个尝试连接清单里的所有主机并打印“连通”或“失败”的状态。第一次配置完我强烈建议你先把本机加进去试试groups: local: hosts: - 127.0.0.1 user: root先确保工具能连上 localhost再去碰远程机器这样能把“工具本身的问题”和“网络连通性的问题”隔离开。3.4 执行你的第一条批量命令配置完成后试试最简单的两条命令。先看有哪些分组openshell list再对某个分组执行命令openshell run uptime --group web执行后OpenShell 会在每个主机上执行 uptime并把输出按主机名或 IP 分组打印出来。输出大概长这样[192.168.10.11] OK 14:23:22 up 10 days, 2:03, 1 user, load average: 0.05, 0.03, 0.01 [192.168.10.12] OK 14:23:22 up 3 days, 18:44, 2 users, load average: 0.11, 0.08, 0.06这一步能跑通说明你已经拥有了最基本的“多主机命令执行”能力。后面所有高级功能都是在这两条命令的基础上扩展出来的。4. 核心实现配置系统、批量执行引擎与插件机制4.1 配置系统YAML 的全量覆盖OpenShell 的配置系统整体用 YAML 描述。我选 YAML 而不是 JSON原因很感性它有注释可以写说明文档。JSON 虽然严谨但给人看的时候非常不友好。配置系统里有一个比较微妙的设计主机信息支持继承和覆盖。比如你可以在 group 层面设置 user 和 key然后在 hosts 列表里单独给某台机器覆盖 user 字段groups: web: user: deploy key: ~/.ssh/id_ed25519 hosts: - host: 192.168.10.11 - host: 192.168.10.12 user: admin在这个例子里192.168.10.12 会用 admin 用户登录其他机器用 deploy。这种设计很实用因为真实环境里同组机器的登录方式往往并不完全一致。配置解析的坑在于“变量引用”。比如某个任务脚本里需要用到主机 IP 作为参数显然不应该把 IP 硬编码在任务文件里。OpenShell 的处理是提供内建的模板变量{{.Host}}表示当前主机地址。{{.Group}}表示当前分组名。{{.User}}表示当前登录用户。在任务文件里你可以这样写steps: - run: echo 当前分组: {{.Group}}主机: {{.Host}} /tmp/info.txt每次执行时OpenShell 会先把模板渲染成真实命令再扔给远程机器。这个机制让同一份任务脚本在不同环境下可以复用真正做到了“一份配置多处运行”。4.2 批量执行引擎批量执行引擎是 OpenShell 的核心模块。它的工作是读取任务定义、渲染变量、按并发数分配任务、建立 SSH 连接、执行命令、收集标准输出和标准错误、判断退出码、把结果聚合展示。这个引擎有一个我自认为做得很好的细节流式输出。你运行 openshell run 的时候每台机器的结果是一台一台陆续出现的而不是全部等齐了再一次性打印。刚开始实现的时候我一直把结果放在内存里等所有主机都返回后才统一渲染。结果就是跑一条耗时的批量命令时屏幕上十几秒没有动静用户体验非常差。后来改成“结果一出来就实时渲染”感觉完全不一样了。并发控制的实现方式就是典型的 worker pool 模型。我用 Go 实现了一个很轻量的池子任务放进 channel固定数量的 worker 从 channel 里取任务执行。核心代码大概长这样func RunBatch(tasks []Task, workers int) []Result { taskCh : make(chan Task) resultCh : make(chan Result) for i : 0; i workers; i { go worker(taskCh, resultCh) } go func() { for _, t : range tasks { taskCh - t } close(taskCh) }() results : make([]Result, 0, len(tasks)) for range tasks { r : -resultCh results append(results, r) } return results }这个模型非常简单但它解决了并发数量控制、结果有序收集、错误隔离三个关键问题。某个主机连接失败不会影响其他主机继续执行失败主机的错误会记录在结果里并在最后展示时标红提示。超时处理方面我分了两层连接超时和命令执行超时。连接超时默认 10 秒命令超时默认 30 秒都可以在 config.yaml 里调整。对耗时较长的任务你可以在任务文件里单独覆盖 timeout 字段避免因为默认超时把长任务杀掉。4.3 任务编排单条命令与复合任务openshell run适合跑临时命令但真正常用的场景是“复合任务”先检查磁盘再看系统负载最后把结果写入一个摘要文件。这类任务我建议定义成任务文件放在 tasks 目录下。任务文件是 YAML 格式结构参考 GitHub Actions 的写法name: daily-check description: 日常巡检磁盘、内存、负载 timeout: 60s steps: - name: 检查磁盘 run: df -h - name: 检查内存 run: free -m - name: 检查负载 run: uptime - name: 汇总写入远程日志 run: | echo $(date) /var/log/openshell-check.log df -h /var/log/openshell-check.log执行方式openshell run daily-check --group web注意我用了 daily-check 的写法。这是 OpenShell 的一个约定 开头表示任务名不带 的普通字符串视为一条原始命令。这个设计让用户不需要去区分“这是任务文件还是命令”用起来很自然。任务文件的另一端是“引用”。某些复杂的运维流水线往往会依赖前面任务的结果比如只有在磁盘空间小于某个阈值时才触发清理脚本。OpenShell 虽然不会做真正的“流程编排”但可以通过步骤的 continue_on_error 和 exit_code 判断来做基础的条件控制steps: - name: 检查磁盘余量 run: test $(df / | awk NR2 {print $4}) -gt 1000000 continue_on_error: true - name: 仅当磁盘余量不满足时执行清理 run: bash /opt/scripts/cleanup.sh only_on_error: true这里的语义是第一步检查磁盘余量如果失败余量不足才触发第二步清理。如果第一步通过清理步骤会被自动跳过。这种“失败才执行”的机制在运维场景里非常好用因为它刚好对应了“告警才处理”的思路。4.4 插件机制把扩展能力交还给用户如果说配置系统和执行引擎是 OpenShell 的骨架那插件机制就是它的关节。我不想陷入“功能堆砌”的泥潭所以 OpenShell 的主程序里只保留最通用的能力剩下的全交给用户通过插件扩展。插件本质上是一个可执行文件。OpenShell 在遇到默认命令无法处理的请求时会去 plugins 目录里查找同名插件然后以约定格式调用它。约定格外简单插件只从标准输入接收 JSON向标准输出返回 JSON。我写过一个最简单的插件 getip用来获取指定主机的 IP 归属和网络接口信息。插件的核心逻辑可以用任意语言写。下面是一个 Python 的最小实现文件名为 getip放在 plugins 目录里并加执行权限#!/usr/bin/env python3 import json import sys def main(): data json.load(sys.stdin) host data[host] result {host: host, status: ok} # 在这里写针对 host 的具体探测逻辑 # 示例里直接返回一个静态结构 result[interfaces] [eth0, eth1] print(json.dumps(result)) if __name__ __main__: main()调用方式统一为openshell plugin getip --host 192.168.10.11主程序会把参数封装成 JSON通过 stdin 传给插件再把插件返回的 JSON 解析渲染。这套设计最大的好处是插件可以用任何语言写不依赖 Go 的编译环境。你只需要遵守一个输入输出协议就能无限扩展 OpenShell 的能力。我实际用下来这个机制特别适合做监控指标上报、自定义报告生成、跟内部 CMDB 系统对接这类场景。核心程序一直在演进但我从来不需要为每个新需求重新编译它。4.5 与日常脚本的集成OpenShell 并不是一个孤岛它可以跟你已有的运维体系无缝衔接。我在使用中最常用的集成方式有两种。第一种是给 openshell 设置 shell alias让高频命令变得更短。比如alias osallopenshell run --group all alias oswebopenshell run --group web这样我只需要敲 osweb uptime就能对 web 分组执行 uptime 命令。第二种是配合 crontab 做定时巡检。例如每天早上 8 点执行一次巡检任务并把结果写入日志0 8 * * * openshell run daily-check --group all ~/.openshell/logs/cron.log 21这种用法让 OpenShell 可以直接充当一个轻量监控和巡检工具没有额外的常驻进程也不会产生额外的系统负担。5. 实测用 OpenShell 完成一次批量巡检理论说了不少我用一次真实的批量巡检来走一遍完整流程。我的场景是 12 台机器其中 8 台属于 web 分组4 台属于 db 分组。巡检内容包含四项磁盘空间、内存使用率、系统负载、最近一小时是否有异常登录记录。第一步定义巡检任务文件 tasks/audit.yamlname: audit description: 全站巡检 timeout: 60s steps: - name: 磁盘空间 run: df -h - name: 内存与负载 run: free -m uptime - name: 异常登录检查 run: | last -n 50 | grep -v localhost | head -20第二步先对 web 分组执行openshell run audit --group web执行过程中左侧每一行会实时刷新当前状态最先完成的主机结果先显示。大概三十秒内8 台 web 服务器的巡检结果就全部返回了。我直接扫了一眼磁盘使用率发现其中有两台机器的根分区超过了 90%这在后续的告警里是要重点关注的。第三步再对 db 分组执行一次openshell run audit --group dbdb 分组里有一台机器的端口改成了 6322这在我之前的配置里已经通过 port 字段处理好了所以执行时不需要额外指定。整个过程没有任何连接失败。当然这只是一次最简单的“跑巡检”。实际使用时我会把这几条命令封装成一个 shell 函数放在 ~/.bashrc 里audit() { echo Web 巡检 $(date) openshell run audit --group web echo DB 巡检 $(date) openshell run audit --group db }每次跑巡检只需要在本地终端敲一个 audit然后把输出收下来花十分钟扫一眼就行。6. 常见问题与排查技巧实录工具用久了坑也踩了不少。下面几个问题是我自己和同事在实际使用中碰到次数最多的整理成速查表方便你少走弯路。现象可能原因排查与解决连接超时目标机器防火墙屏蔽、SSH服务未启动、本地网络不通先用 ping 和 nc 测试端口连通性再确认 sshd 状态公钥认证失败 Permission denied (publickey)私钥路径写错、权限过宽、公钥没有安装到目标机私钥权限必须为 600执行 chmod 600 key确认目标的 authorized_keys命令返回结果为空目标机器环境变量缺失、标准输出重定向到了 stderr在 OpenShell 里将 stdout 和 stderr 合并展示后排查中文输出乱码远程机 locale 不支持 UTF-8在任务步骤前添加 export LANGen_US.UTF-8 或 zh_CN.UTF-8批量执行速度很慢并发数设太低或者目标机器 DNS 解析慢适当调大 max_concurrency在 hosts 配置里优先使用 IP部分主机失败导致整体输出混乱没开启失败隔离确认版本支持 result channel 模式并查看错误结果中的具体主机标识使用了 sudo 后命令失败非交互式 shell 下 sudo 可能缺少终端支持尝试在任务步骤里添加-tt参数OpenShell 需支持该 flag插件总是报错插件缺少可执行权限、或输出 JSON 格式不合法检查插件权限、先手动 echo 调试 JSON 输出这里面我想额外展开两个经验。第一个是 SSH 连接变慢的问题。后来我发现很大一部分“连接超时”并不是网络不通而是 DNS 反向解析太慢。解决办法是在 OpenShell 的 SSH 客户端配置里显式设置 ServerAliveInterval并且连接时不解析主机名。如果你的 OpenShell 版本支持建议在配置里开启ssh: server_alive_interval: 30第二个经验是关于日志审计。OpenShell 默认会把每次执行记录的输入输出写到 ~/.openshell/logs 下。有一次线上出了问题我们翻查半天没找到是谁在什么时间执行了那条高危命令结果打开 OpenShell 的日志一看命令、时间、主机列表、退出码全都有。从那次以后我养成了定期把日志目录归档的习惯。千万别只依赖记忆命令一旦批量跑起来人会记不住自己刚才干了啥。7. 安全与审计建议7.1 密钥管理永远不要进仓库OpenShell 的所有操作都依赖 SSH 凭据所以密钥管理是安全性的第一道防线。我的原则很简单私钥永远不写进 hosts.yaml 或其他任何配置仓库文件。OpenShell 支持通过环境变量注入密钥路径export OPENSHELL_KEY_DIR/home/user/.keys openshell run uptime --group web这样配置文件里只存机器地址和用户名私钥本身停留在文件系统之外不进入任何版本管理工具。如果确实需要多人共用同一套配置最好在 CI/CD 环节里通过 Secret 管理工具注入不要明文提交。7.2 使用最小权限账号执行任务不少人为了方便喜欢在 OpenShell 里用 root 用户批量执行任务。我用过一段时间后来发现还是不行。一旦某台机器被攻破批量执行的入口就会成为横向扩散的跳板。所以我现在给 OpenShell 配置的是一个独立运维账号只授予执行命令、读取日志、重启指定服务的权限。批量操作如果需要 root我会在命令里用 sudo 并配合 sudoers 规则而不是直接用 root 登录。下面是我在目标机器上的 sudoers 配置示例deploy ALL(ALL) NOPASSWD: /usr/bin/systemctl, /usr/bin/df, /usr/bin/free这个配置让 deploy 用户只能免密执行 systemctl、df、free 这几个命令其他命令需要密码或没有权限。这样即使 OpenShell 的某个插件被滥用影响范围也限制在几条安全命令之内。7.3 日志脱敏与审计周期OpenShell 日志会记录完整的命令和输出但这意味着如果你的命令里含有密码、Token、临时凭据它们也会被原样写进日志。我建议在所有涉及敏感信息的命令里使用环境变量引用而不是直接明文传递。另外在日志落盘前OpenShell 会对明显匹配密码模式的字符串做脱敏处理把你输出的 keyxxx 中的 xxx 替换成 ******。脱敏逻辑我用正则实现核心模式很简单var secretPattern regexp.MustCompile((?i)(password|token|secret|key)([^\s]))匹配到这类模式后将捕获组内容替换成掩码。这样即使有人翻历史日志也不会直接看到完整的敏感信息。审计周期方面我给自己定的规矩是每两周检查一次 OpenShell 的日志总量和历史记录确认没有不认识的执行记录。这个习惯持续了很久虽然大部分时候翻到的都是自己跑的任务但那种“能交底”的感觉在团队合作里是很值钱的。7.4 校验配置指纹防止配置被篡改OpenShell 在加载 hosts.yaml 时会同时读取一个可选的校验文件 config.sig。如果配置文件在生成后被手动篡改过校验指纹就会失败OpenShell 会主动拒绝执行。这个功能不是强制性的但我强烈建议在多人协作的场景里开启。生成指纹的命令是openshell verify --init开启后每次修改主机列表都需要重新生成一次指纹。这虽然多了一步操作但保证了“批处理入口”不会被悄无声息地替换成危险目标。其实原理很简单就是给配置文件的文本内容算一个哈希。然而在批量执行大量机器时这层确定性能让你事后有一个固定的“版本对照点”避免说“我记得当时配置是对的为什么后来不一样了”这种话。写在最后的个人体会写了这么多其实 OpenShell 最核心的理念只有一句话不要盲目制造复杂也不要盲目拒绝工具找到一个中间点然后把它打磨顺手。对我而言这个中间点就是“本地终端 命令行入口 声明式配置”。它不像商业产品那样有漂亮界面但它足够透明透明到每个机制我都能解释清楚这对一个运维工具来说比什么都重要。如果你也打算在团队里推动类似的东西我的建议是先不要追求功能大而全先把“批量执行命令、分组管理、日志留存”这三件事做好。一个工具真正被用起来靠的不是需求的堆叠而是在最琐碎的日常操作里能不能让人“用起来不别扭”。我后续打算把 OpenShell 的方向继续往轻量监控上面靠给批量采集的结果做一个汇总趋势展示而不是只看一次性的快照。这个功能还没做完等跑过一轮真实环境再找机会详细聊聊。
返回列表