<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>运维 on CAO ZUOHUA</title><link>https://caozuohua.github.io/tags/%E8%BF%90%E7%BB%B4/</link><description>Recent content in 运维 on CAO ZUOHUA</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Sun, 01 Nov 2026 00:00:00 +0800</lastBuildDate><atom:link href="https://caozuohua.github.io/tags/%E8%BF%90%E7%BB%B4/index.xml" rel="self" type="application/rss+xml"/><item><title>在小型 GCP VPS 上尝试用 OpenCode 接管个人助理</title><link>https://caozuohua.github.io/posts/2026-11-01-opencode-lark-takeover/</link><pubDate>Sun, 01 Nov 2026 00:00:00 +0800</pubDate><guid>https://caozuohua.github.io/posts/2026-11-01-opencode-lark-takeover/</guid><description>&lt;p&gt;我希望把日常对话、QPC 知识库与日历逐步放进一个个人助理，同时控制小型 VPS 的资源占用。已有 Hermes 网关正在使用另一只 Lark 机器人。这个实验的目标是暂停 Hermes，在同一台共享小机上尝试运行 OpenCode，并使用 personal-assistant 的机器人验证接管链路。&lt;/p&gt;&#10;&lt;p&gt;**同日补充：**第一次窗口结束前的消息被中断；经再次授权，重开受保护的短时窗口后，真实 Lark 两轮私聊均收到回复，第二轮正确使用了前文。模型任务期间的内存峰值和压力依然偏高，尚不能据此判断适合在这台小机上长期常驻。&lt;/p&gt;&#10;&lt;p&gt;这次实验的边界很窄：测试短时对话、资源和回退；QPC 与日历不是这次已经实现的能力。两只机器人独立，暂停 Hermes 会暂时影响原机器人，不会自动把它的会话和权限迁移到新机器人。&lt;/p&gt;&#10;&lt;h2 id="为什么不能只比较一个-rss"&gt;为什么不能只比较一个 RSS&lt;/h2&gt;&#10;&lt;p&gt;在决定切换前，观察到 Hermes 主进程的一次 RSS 约 341 MiB，另有进程数据进入 swap。本机 WSL 中 OpenCode 空闲服务的主进程 RSS 大约 224–262 MiB。但 Hermes 当时正在承担实际网关工作，OpenCode 的本机测试没有接真实 Lark 或模型。不同机器、不同负载和不同统计口径不能直接得出完整替代方案的节省量。&lt;/p&gt;&#10;&lt;p&gt;共享实例约有 952 MiB 可见内存，Hermes 运行时多次采样的可用内存只有一百多 MiB，还有明显 swap 使用。相比直接叠加一个服务，先暂停旧网关、在相同机器上测量完整链路，更接近实际问题。&lt;/p&gt;&#10;&lt;h2 id="把切换做成可回退试验"&gt;把切换做成可回退试验&lt;/h2&gt;&#10;&lt;p&gt;方案是由已有的轻量 Lark 入口负责本人身份检查、消息去重与回复状态，OpenCode 仅在本机回环地址提供模型对话接口。服务使用非特权用户、单独工作目录、内存和 CPU 限额；OpenCode 工具权限默认拒绝，试验不开放文件修改、Shell 或其他外部动作。模型凭证和机器人凭证分开提供，不放入仓库或文章。&lt;/p&gt;&#10;&lt;p&gt;切换前设置了十分钟自动回退，并持续观察内存余量、内存压力和关键服务状态。试验失败或达到时限时，停止试验服务，恢复 Hermes gateway 和 A2A bridge。两个服务独立恢复，是因为 bridge 没有声明会自动跟随 gateway 的依赖关系。&lt;/p&gt;&#10;&lt;p&gt;对话适配器每轮创建独立 OpenCode 会话，只加入已确认送达的有限历史；调用超时不自动重试。模型回答和 Lark 成功投递分开记录。OpenCode 自身会在状态目录写入会话数据，尝试调用 API 删除会话并不等于证明底层数据被彻底擦除，因此试验使用独立目录并在结束后清理。&lt;/p&gt;</description></item><item><title>不仅是定时：使用 systemd 构建企业级自动化运维体系</title><link>https://caozuohua.github.io/posts/2026-09-14-linux-systemd-ops/</link><pubDate>Mon, 14 Sep 2026 11:30:00 +0800</pubDate><guid>https://caozuohua.github.io/posts/2026-09-14-linux-systemd-ops/</guid><description>&lt;h1 id="不仅是定时使用-systemd-构建企业级自动化运维体系"&gt;不仅是定时：使用 systemd 构建企业级自动化运维体系&lt;/h1&gt;&#10;&lt;p&gt;在 Linux 环境下，如何让服务“永远在线”？对于企业级 Agent 系统而言，答案通常不是编写一个死循环的 Shell 脚本，而是将任务交给系统最底层的管家——&lt;code&gt;systemd&lt;/code&gt;。&lt;/p&gt;&#10;&lt;h2 id="1-为什么弃用用户态-daemon"&gt;1. 为什么弃用用户态 Daemon？&lt;/h2&gt;&#10;&lt;p&gt;在之前的运维实践中，我们尝试过使用自定义的 &lt;code&gt;blog_daemon&lt;/code&gt; 进行自动化调度，但结果证明它不可靠：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;状态丢失&lt;/strong&gt;：Daemon 若因崩溃、重启或环境抖动导致 PID 文件丢失，整个调度机制就会“瘫痪”。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;权限与依赖限制&lt;/strong&gt;：Daemon 难以管理任务间的依赖顺序，也无法精准进行资源限制（如 CPU/内存配额）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="2-systemd-的核心优势"&gt;2. systemd 的核心优势&lt;/h2&gt;&#10;&lt;p&gt;将任务转交给 &lt;code&gt;systemd&lt;/code&gt;（通过 &lt;code&gt;.service&lt;/code&gt; 与 &lt;code&gt;.timer&lt;/code&gt;），意味着将任务的生存责任交给了内核：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;内核级保障&lt;/strong&gt;：&lt;code&gt;systemd&lt;/code&gt; 与内核紧密协作，即使服务崩溃，它也能通过 &lt;code&gt;Restart=always&lt;/code&gt; 实现秒级恢复。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;资源限制 (Cgroups)&lt;/strong&gt;：通过配置 &lt;code&gt;MemoryMax&lt;/code&gt; 或 &lt;code&gt;CPUQuota&lt;/code&gt;，可以防止 Agent 因死循环或内存泄露耗尽主机所有资源。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;依赖管理&lt;/strong&gt;：通过 &lt;code&gt;After=network.target&lt;/code&gt;，确保服务在网络就绪后再启动，解决了 Daemon 启动时常见的“网络不可用”问题。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="3-局限性与避坑指南"&gt;3. 局限性与避坑指南&lt;/h2&gt;&#10;&lt;p&gt;尽管 &lt;code&gt;systemd&lt;/code&gt; 强大，但它并非完美，在生产环境中需注意：&lt;/p&gt;&#10;&lt;h3 id="systemd-的局限性"&gt;systemd 的局限性：&lt;/h3&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;侵入性强&lt;/strong&gt;：配置需要 Root 权限。在部分云原生环境（如只读文件系统）中，我们无法触及系统级目录，此时 &lt;code&gt;systemd&lt;/code&gt; 会失效。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;配置复杂&lt;/strong&gt;：相比 crontab，&lt;code&gt;systemd&lt;/code&gt; 的配置逻辑冗长。如果项目环境多变，配置迁移成本高。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;单点风险&lt;/strong&gt;：&lt;code&gt;systemd&lt;/code&gt; 本身是系统守护进程，一旦它出现异常，整个系统的服务管理将瞬间停滞（尽管这种情况极少见）。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="避坑指南"&gt;避坑指南：&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;配置验证&lt;/strong&gt;：在上线前，务必使用 &lt;code&gt;systemd-analyze verify&lt;/code&gt; 检查语法，防止服务启动失败导致雪崩。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;日志归一化&lt;/strong&gt;：&lt;code&gt;systemd&lt;/code&gt; 托管的服务日志默认由 &lt;code&gt;journald&lt;/code&gt; 管理，需配置好日志轮转，防止 &lt;code&gt;/var/log&lt;/code&gt; 空间被写满。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;非 Root 环境替代方案&lt;/strong&gt;：如果环境限制无法使用 &lt;code&gt;systemd&lt;/code&gt;（如无 Root 权限的容器内），请考虑 &lt;strong&gt;&lt;code&gt;supervisord&lt;/code&gt;&lt;/strong&gt; 或基于 &lt;strong&gt;容器调度器 (K8s/Nomad)&lt;/strong&gt; 的健康检查机制，而非编写简易 Daemon。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="4-企业级最佳实践systemd-配置模板"&gt;4. 企业级最佳实践：Systemd 配置模板&lt;/h2&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-ini" data-lang="ini"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# /etc/systemd/system/agent-task.timer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;[Unit]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Description&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;Daily Agent Task Timer&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;[Timer]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;OnCalendar&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;*-*-* 12:00:00&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;Persistent&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;[Install]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;WantedBy&lt;/span&gt;&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;timers.target&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="总结"&gt;总结&lt;/h2&gt;&#10;&lt;p&gt;对于企业级 Agent 系统，追求“高可靠性”的关键不在于代码写得多么复杂，而在于如何高效地利用操作系统的管理能力。&lt;code&gt;systemd&lt;/code&gt; 是 Linux 运维的定海神针，但我们也需清楚它的边界——当系统权限受到限制时，拥抱云原生架构（如 GitHub Actions/K8s）将是更优雅的选择。&lt;/p&gt;</description></item><item><title>理解 Linux 进程：信号机制与守护进程的生与死</title><link>https://caozuohua.github.io/posts/2026-09-14-linux-signals/</link><pubDate>Mon, 14 Sep 2026 00:00:00 +0000</pubDate><guid>https://caozuohua.github.io/posts/2026-09-14-linux-signals/</guid><description>&lt;h1 id="理解-linux-进程信号机制与守护进程的生与死"&gt;理解 Linux 进程：信号机制与守护进程的生与死&lt;/h1&gt;&#10;&lt;p&gt;在 Linux 系统中，进程是资源分配和调度的主体。理解进程的运行状态、如何终止以及如何实现优雅的重启，是保障服务高可用的基石。&lt;/p&gt;&#10;&lt;h2 id="进程的生命周期"&gt;进程的生命周期&lt;/h2&gt;&#10;&lt;p&gt;进程从 &lt;code&gt;fork()&lt;/code&gt; 开始，经历运行、睡眠、僵尸 (Zombie) 等状态。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;运行状态 (R)&lt;/strong&gt;：正在 CPU 上执行或在运行队列中等待。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;睡眠状态 (S/D)&lt;/strong&gt;：等待某种事件发生（如 I/O 完成）。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;僵尸状态 (Z)&lt;/strong&gt;：进程已终止但尚未被父进程回收，占用了进程描述符 (PID)。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="信号-signals进程间的紧急通信"&gt;信号 (Signals)：进程间的“紧急通信”&lt;/h2&gt;&#10;&lt;p&gt;信号是 Linux 中一种异步通知机制，用于通知进程发生了特定事件。&lt;/p&gt;&#10;&lt;table&gt;&#10;&#9;&lt;thead&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: left"&gt;信号&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: left"&gt;名称&lt;/th&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;th style="text-align: left"&gt;作用&lt;/th&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/thead&gt;&#10;&#9;&lt;tbody&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;SIGTERM&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;终止信号&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;请求进程优雅退出，允许进程清理资源&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;SIGKILL&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;强制杀死&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;立即终止进程，进程无法捕获或忽略&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&#9;&#9;&lt;tr&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;SIGHUP&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;终端挂起&lt;/td&gt;&#10;&#9;&#9;&#9;&#9;&#9;&lt;td style="text-align: left"&gt;常用于通知守护进程重新加载配置文件&lt;/td&gt;&#10;&#9;&#9;&#9;&lt;/tr&gt;&#10;&#9;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h2 id="优雅退出的艺术"&gt;优雅退出的艺术&lt;/h2&gt;&#10;&lt;p&gt;许多线上事故源于不当的进程终止方式。&lt;/p&gt;&#10;&lt;h3 id="1-为什么拒绝-kill--9"&gt;1. 为什么拒绝 &lt;code&gt;kill -9&lt;/code&gt;？&lt;/h3&gt;&#10;&lt;p&gt;强制使用 &lt;code&gt;SIGKILL&lt;/code&gt; 会打断进程正在进行的事务（如数据库写入），导致数据不一致或内存溢出。&lt;/p&gt;&#10;&lt;h3 id="2-优雅终止流程"&gt;2. 优雅终止流程&lt;/h3&gt;&#10;&lt;p&gt;守护进程应捕获 &lt;code&gt;SIGTERM&lt;/code&gt; 信号：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;停止接收新请求。&lt;/li&gt;&#10;&lt;li&gt;处理完当前正在进行的任务。&lt;/li&gt;&#10;&lt;li&gt;释放已申请的 socket、数据库连接。&lt;/li&gt;&#10;&lt;li&gt;进程退出。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 推荐做法：首先发送 SIGTERM&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;kill &amp;lt;PID&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# 等待几秒后，如果进程依然存在，再视情况决定是否强制清除&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# (但尽量避免直接使用 kill -9)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;hr&gt;&#10;&lt;h2 id="运维场景"&gt;运维场景&lt;/h2&gt;&#10;&lt;p&gt;在生产环境中，部署新的配置后，通常通过发送 &lt;code&gt;SIGHUP&lt;/code&gt; 信号触发服务的“平滑重启”，实现零停机部署：&lt;/p&gt;</description></item></channel></rss>