1. 从一台跑了 2 年的云主机说起两年前我在一台云主机上部署了一整套个人自动化工具链。当时的需求很朴素定时抓取一些公开数据、跑几个脚本做格式转换、偶尔远程连上去改改配置。为了这套东西我买了一台入门级云主机装的是 Linux 系统用 Docker 跑着几个容器日子过得还算安稳。但两年下来问题越来越多。首先是成本虽然单月看起来不多但两年累计下来也是一笔不小的开销。其次是维护系统更新、安全补丁、容器镜像升级每次都要 SSH 上去手动操作偶尔遇到依赖冲突还得花半天排查。最让人头疼的是有些任务其实根本不需要一台 24 小时在线的服务器我只是在特定时间点需要它跑一下而已。后来我开始用 WorkBuddy 这个工具把原来跑在云主机上的任务逐步迁移过去。迁移完成后我做了一个决定把那台跑了 2 年的云主机关停。这篇文章就是记录整个迁移过程的思考、操作和踩过的坑适合那些同样在维护个人服务器、想降低运维成本、或者对 WorkBuddy 这类工具感兴趣的朋友参考。2. 云主机这两年到底在跑什么2.1 任务清单的重新审视在决定迁移之前我先把云主机上跑的所有东西列了一遍。这一步很关键因为很多人维护服务器久了自己都不清楚上面到底跑了什么。我用的方法很简单登录上去之后依次检查几个地方crontab -l查看当前用户的定时任务systemctl list-units --typeservice查看系统服务docker ps -a查看所有容器包括已经停止的ls /etc/cron.d/查看系统级定时任务列完之后我发现真正还在用的任务其实只有三类一是每天定时抓取几个公开数据源并生成报告二是每周做一次文件格式批量转换三是偶尔需要临时跑一些脚本做数据处理。剩下的要么是当初装了就没用过的要么是已经失效但忘了清理的。这个发现让我意识到我花在维护云主机上的精力大部分都消耗在了那些僵尸任务上。它们不产生价值但会占用系统资源还会在系统更新时带来兼容性问题。2.2 哪些任务适合迁移哪些不适合不是所有任务都适合从云主机迁移到 WorkBuddy。我根据自己的实际经验整理了一个判断标准任务类型是否适合迁移原因定时抓取公开数据适合按需触发不需要常驻进程文件格式批量转换适合一次性执行完成后释放资源临时脚本运行适合按需调用无需长期在线需要固定公网 IP 的服务不适合WorkBuddy 不提供固定出口 IP高并发长时间运行的服务不适合更适合用专门的服务器承载需要大量本地存储的任务不适合受限于本地设备存储空间这个判断标准的核心逻辑是任务是否需要一个始终在线、随时待命的环境。如果任务本身是事件驱动或者定时触发的那它就不需要一台 24 小时开机的服务器。反过来如果任务需要持续监听端口、维持长连接、或者对外提供稳定的服务入口那云主机仍然是更合适的选择。2.3 成本账的重新计算关停云主机之前我算了一笔账。云主机的费用包括实例费、带宽费、快照存储费加起来每个月是一笔固定支出。而 WorkBuddy 运行在我本地的一台 MacMini 上这台机器本来就是我日常在用的电费可以忽略不计。更重要的是隐性成本。云主机需要我定期花时间做系统更新、安全加固、日志清理。这些时间如果折算成时薪其实比云主机的费用还高。迁移到 WorkBuddy 之后这些维护工作基本消失了因为 WorkBuddy 的运行环境是隔离的不需要我操心底层系统。提示算成本账的时候不要只看账单上的数字要把自己花在维护上的时间也算进去。很多时候时间成本才是大头。3. WorkBuddy 到底解决了什么问题3.1 它不是一个云主机的替代品很多人第一次接触 WorkBuddy 的时候会下意识地把它当成云主机的替代品。这个理解其实不太准确。WorkBuddy 更像是一个任务执行环境它不提供公网 IP不提供持久化的服务器进程也不保证 24 小时在线。它解决的核心问题是让一个任务在需要的时候在一个干净、隔离、可复现的环境里跑起来跑完就结束。这个定位决定了它的适用场景。如果你的需求是跑一个脚本处理一批数据那 WorkBuddy 很合适。如果你的需求是搭一个网站让所有人都能访问那 WorkBuddy 就不合适你还是需要一台云主机或者别的托管服务。我之所以能用它替代云主机是因为我原来的云主机上跑的本来就是任务型的负载而不是服务型的负载。这一点想清楚了迁移的路径就清晰了。3.2 环境隔离带来的好处WorkBuddy 的运行环境是隔离的这意味着每个任务都在自己的沙箱里执行不会互相干扰。这个特性在云主机上其实很难做到因为云主机是一个共享的操作系统环境不同任务之间可能会因为依赖版本冲突、端口占用、文件权限等问题互相影响。我之前在云主机上就遇到过这种情况两个 Python 脚本依赖不同版本的同一个库装在同一个环境里就会冲突。当时的解决方案是用 virtualenv 做隔离但管理起来很麻烦。迁移到 WorkBuddy 之后每个任务的环境是独立的我只需要在任务配置里声明依赖不需要操心环境冲突。3.3 从维护服务器到维护任务的思维转变用云主机的时候我的思维模式是维护一台服务器。我要关心系统版本、安全补丁、磁盘空间、内存占用、网络配置。这些工作跟我的实际业务没有直接关系但必须做否则服务器就会出问题。用 WorkBuddy 之后思维模式变成了维护任务。我只需要关心任务本身的逻辑输入是什么、输出是什么、什么时候触发、失败了怎么重试。底层的运行环境由 WorkBuddy 负责我不需要操心。这个转变带来的最大好处是我的注意力从基础设施回到了业务逻辑上。以前我花在服务器维护上的时间现在可以用来优化任务本身或者做更多有价值的事情。4. 迁移过程中的具体操作4.1 先把任务逻辑从服务器上剥离出来迁移的第一步不是急着装 WorkBuddy而是先把原来跑在云主机上的任务逻辑整理清楚。我的做法是对每一个要迁移的任务写一份简单的说明包括任务的输入是什么数据源、文件路径、参数任务的输出是什么生成的文件、写入的数据库、发送的通知任务的触发条件是什么定时、手动、事件驱动任务依赖哪些环境编程语言、库、系统工具这份说明不需要很正式用文本文件记下来就行。但这一步不能省因为很多任务在云主机上跑久了逻辑已经变得很隐晦不整理清楚就迁移很容易漏掉关键步骤。我整理的时候发现有一个抓取任务依赖了一个我两年前手动安装的系统工具这个工具没有记录在任何文档里。如果不是这次整理迁移之后这个任务肯定会失败而且报错信息可能很难定位到原因。4.2 在 MacMini 上准备 WorkBuddy 运行环境我的 WorkBuddy 跑在一台 MacMini 上。这台机器是 2014 款的配置不算高但跑任务型的负载足够了。准备工作主要有几步首先确认系统版本。这台 MacMini 我装的是 Linux 系统因为原来的 macOS 版本太老很多工具已经不支持了。装 Linux 的过程这里不展开网上教程很多关键是要选一个对老硬件支持好的发行版。然后是安装 Docker。WorkBuddy 的很多功能依赖容器化运行环境所以 Docker 是必须的。在 Linux 上安装 Docker 的命令大致如下# 更新包索引 sudo apt-get update # 安装依赖 sudo apt-get install -y ca-certificates curl gnupg # 添加 Docker 官方 GPG 密钥 sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg # 添加 Docker 仓库 echo deb [arch$(dpkg --print-architecture) signed-by/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release echo $VERSION_CODENAME) stable | sudo tee /etc/apt/sources.list.d/docker.list /dev/null # 安装 Docker sudo apt-get update sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin安装完成后用docker run hello-world验证一下。如果能看到欢迎信息说明 Docker 装好了。注意在老硬件上装 Docker可能会遇到virtualization support not detected之类的报错。这通常是因为 BIOS 里的虚拟化支持没打开或者 CPU 本身不支持某些虚拟化特性。遇到这种情况先检查 BIOS 设置如果硬件确实不支持可以考虑用 Docker 的替代方案或者换一台支持虚拟化的机器。4.3 把定时任务改写成 WorkBuddy 任务原来在云主机上定时任务是用 crontab 管理的。迁移到 WorkBuddy 之后触发方式变成了 WorkBuddy 自己的调度机制。改写的核心是把 crontab 里的命令行转换成 WorkBuddy 能识别的任务定义。以我那个每天抓取数据的任务为例原来的 crontab 条目是这样的0 6 * * * /usr/bin/python3 /home/user/scripts/fetch_data.py /var/log/fetch.log 21迁移到 WorkBuddy 之后我需要做几件事把脚本文件放到 WorkBuddy 能访问的目录声明脚本需要的依赖设置触发时间配置输出日志的位置。WorkBuddy 的任务定义通常是一个配置文件里面描述了任务的各个方面。这个改写过程看起来简单但有几个细节容易忽略。一是环境变量crontab 里的环境变量和 WorkBuddy 任务的环境变量可能不一样需要显式声明。二是工作目录crontab 默认的工作目录是用户主目录而 WorkBuddy 任务的工作目录可能是别的路径脚本里如果有相对路径引用需要改成绝对路径。三是日志crontab 里用重定向写日志WorkBuddy 有自己的日志机制需要适应一下。4.4 处理依赖和权限问题依赖问题是迁移过程中最容易出问题的地方。云主机上的依赖是全局安装的而 WorkBuddy 任务的环境是隔离的需要显式声明依赖。我的做法是对每个任务先在一个干净的环境里跑一遍看它报什么错然后根据报错逐个补依赖。这个过程可能需要反复几次但比一次性把所有依赖都列出来要可靠因为很多依赖是隐式的不跑一遍根本发现不了。权限问题也需要注意。云主机上我的用户有 sudo 权限可以执行一些需要特权的操作。WorkBuddy 任务通常以普通用户权限运行如果任务里有需要特权的操作需要提前调整。比如如果任务需要绑定 1024 以下的端口在云主机上可能直接就能跑但在 WorkBuddy 里就会失败需要改成用高位端口或者用其他方式转发。5. 那些让我卡了半天的坑5.1 502 write eacces 报错迁移过程中我遇到过一个报错502 write eacces。这个报错的意思是任务在写文件的时候没有权限。排查了半天发现原因是 WorkBuddy 任务的工作目录权限设置有问题。具体来说我在任务配置里指定的输出目录属主是 root而任务是以普通用户身份运行的所以写不进去。解决方案很简单把输出目录的属主改成运行任务的用户或者把目录权限改成可写。但这个问题的排查过程比较绕因为报错信息没有直接指出是哪个目录的权限问题。我的经验是遇到权限相关的报错先用ls -la看一下相关目录的权限和属主确认运行任务的用户有没有写权限。如果没有用chown或chmod调整。5.2 Docker 连接失败的问题还有一个坑是 Docker 连接失败。报错信息大概是failed to connect to the docker api at npipe:////./pipe/dockerdesktoplinuxen。这个报错看起来像是 Windows 上的路径但我明明是在 Linux 上运行的。排查之后发现原因是 WorkBuddy 的某个组件默认去找 Docker Desktop 的接口而我装的是 Docker Engine接口路径不一样。解决方案是在配置里显式指定 Docker 的 socket 路径通常是/var/run/docker.sock。这个问题的教训是WorkBuddy 的默认配置可能假设你用的是某种特定的环境如果你的环境和默认假设不一致就需要手动调整配置。遇到这类问题先确认自己的环境是什么然后去文档里找对应的配置项。5.3 定时任务时区不对时区问题也是迁移中容易忽略的。云主机的时区通常设置好了而 WorkBuddy 运行在本地设备上时区可能跟云主机不一样。我有个任务是每天早上 6 点触发迁移之后发现它在北京时间早上 6 点没跑而是在下午 2 点跑了。原因是 WorkBuddy 的调度器用的是 UTC 时间而我的云主机用的是北京时间。解决方案是在任务配置里显式指定时区或者把触发时间换算成 UTC 时间。提示迁移定时任务的时候一定要确认时区设置。最好的做法是在任务配置里显式声明时区不要依赖系统默认值。5.4 依赖版本不一致导致的诡异问题最后一个坑是依赖版本不一致。云主机上的某个库是两年前装的版本比较老而 WorkBuddy 任务里装的是最新版。结果任务跑起来之后行为跟原来不一样输出的数据格式有细微差别。这个问题比较隐蔽因为任务没有报错只是输出不对。我是对比了迁移前后的输出文件才发现差异的。解决方案是在 WorkBuddy 任务里锁定依赖版本跟云主机上保持一致。这个经验告诉我迁移任务的时候不仅要关注任务能不能跑起来还要关注跑出来的结果是不是跟原来一致。最好的做法是迁移前后各跑一次对比输出确认没有差异。6. 关停云主机之后的实际体验6.1 日常运维工作量的变化关停云主机之后最直观的变化是日常运维工作量大幅减少。以前我每周都要花时间登录服务器检查磁盘空间、看日志、更新系统。现在这些工作基本没有了因为 WorkBuddy 的运行环境由它自己管理我不需要操心底层系统。具体来说以前我每周大概要花 1 到 2 小时在服务器维护上现在这部分时间基本省下来了。一个月下来就是 4 到 8 小时一年就是 50 到 100 小时。这些时间可以用来做更有价值的事情。6.2 任务执行效率的对比任务执行效率方面WorkBuddy 和云主机各有优劣。云主机的优势是网络稳定、带宽充足抓取外部数据的时候速度比较快。WorkBuddy 运行在本地设备上网络条件取决于本地环境有时候会慢一些。但 WorkBuddy 的优势是启动快、环境干净。云主机上跑任务有时候会因为系统负载高、磁盘 IO 慢等原因导致任务执行时间变长。WorkBuddy 的任务环境是隔离的不受其他任务影响执行时间比较稳定。总体来说对于我这种任务型的负载WorkBuddy 的效率是够用的。如果你的任务对网络带宽要求很高或者需要大量并发那可能还是云主机更合适。6.3 数据安全和备份的考虑关停云主机之后数据安全的责任从云服务商转移到了我自己身上。以前云主机有自动快照、异地备份等功能现在这些都需要我自己做。我的做法是把 WorkBuddy 任务的输入和输出数据定期备份到外部存储。备份策略是每天增量备份、每周全量备份。备份的目标是一个外接硬盘偶尔也会同步到另一台设备上。这个方案的安全性肯定不如云服务商的专业备份但对于个人使用来说够用了。关键是要养成定期备份的习惯不要等到数据丢了才想起来。7. 什么情况下不建议关停云主机7.1 需要固定公网入口的服务如果你的云主机上跑的是需要对外提供服务的应用比如网站、API 接口、Webhook 接收端那不建议关停。WorkBuddy 不提供固定的公网入口外部服务无法主动访问它。这类服务的典型特征是有外部系统需要主动连接你或者有用户需要随时访问你的服务。这种情况下云主机的公网 IP 和稳定在线是必需的。7.2 对网络延迟敏感的任务如果你的任务对网络延迟很敏感比如高频交易、实时数据同步、在线游戏服务那也不建议迁移。WorkBuddy 运行在本地设备上网络条件受本地环境影响延迟和稳定性都不如专业的云主机。判断标准很简单如果你的任务因为网络延迟几毫秒就会出问题那就不要迁移。如果延迟几百毫秒甚至几秒都能接受那 WorkBuddy 是可以考虑的。7.3 需要大量计算资源的任务WorkBuddy 运行在本地设备上计算资源受限于本地硬件。如果你的任务需要大量 CPU、内存或者 GPU 资源本地设备可能扛不住。云主机的优势是可以按需扩容需要多少资源就买多少。我的 MacMini 是 2014 款的配置不高跑一些轻量级任务没问题但如果要跑机器学习训练或者大规模数据处理就力不从心了。这种情况下云主机或者专业的计算服务仍然是更好的选择。8. 给准备迁移的朋友几条实在建议如果你也在考虑把云主机上的任务迁移到 WorkBuddy我有几条从实际操作中总结出来的建议。第一条先整理再迁移。不要急着动手先把云主机上跑的所有任务列清楚搞清楚每个任务的输入、输出、依赖和触发条件。这一步做扎实了后面的迁移会顺利很多。第二条逐个迁移不要一次性全搬。我见过有人想一次性把所有任务都迁过去结果出了问题很难定位是哪个任务导致的。正确的做法是一个一个来每迁一个就验证一个确认没问题再迁下一个。第三条保留云主机一段时间作为回退方案。不要迁移完就立刻关停云主机先让它跑一段时间确认 WorkBuddy 上的任务都稳定了再关停。这样万一迁移出了问题还能回退。第四条做好数据备份。迁移过程中数据是最容易出问题的一定要提前备份。备份不仅要备一份最好备两份放在不同的地方。第五条关注时区和依赖版本。这两个是迁移中最容易踩的坑前面已经详细说过了这里再强调一下。迁移前确认时区设置迁移后对比输出结果确认依赖版本一致。最后说一句WorkBuddy 不是万能的它只是众多工具中的一种。选择工具的时候要根据自己的实际需求来判断不要因为别人说好就盲目跟风。我的经验是对于任务型的负载WorkBuddy 确实能省不少事但对于服务型的负载云主机仍然是更合适的选择。想清楚自己的需求再做决定。