尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

关停两年云主机:用WorkBuddy实现自动化任务迁移与编排

关停两年云主机:用WorkBuddy实现自动化任务迁移与编排 1. 那台跑了 2 年的云主机我是怎么一步步决定关掉的先交代背景。我手上有一台云主机从 2023 年初开始跑到关停那天正好两年出头。配置不算高2 核 4G40G 系统盘跑着一套自己攒的自动化脚本集合定时签到、数据抓取、文件同步、几个小 API 服务还有一堆 cron 任务。说白了就是我的个人自动化中枢。这两年它确实干活了但问题也攒了一堆。最烦的是三件事第一续费成本一年下来小几百块说多不多但每次续费都让我重新思考这钱花得值不值第二维护成本系统更新、依赖升级、磁盘清理、日志轮转每隔一段时间就得上去折腾一次有时候一个依赖版本冲突能让我耗掉一整个周末第三也是最要命的任务和运行环境强绑定。我所有的脚本都跑在这台机器的特定 Python 版本、特定系统库、特定目录结构下想迁移先花两天重装环境再说。转折点是我开始用 WorkBuddy。一开始我只是把它当成一个任务编排工具来试没抱太大期望。但用了一段时间之后我发现我原本跑在云主机上的那些活儿大部分根本不需要一台 7x24 小时开着的远程机器。它们需要的是一个能稳定调度、能管理依赖、能隔离环境、能随时查看执行结果的执行框架。云主机只是我过去实现这个目标的笨办法。于是我做了一个决定把云主机上所有任务迁移到 WorkBuddy然后关停那台机器。整个过程花了大概一周踩了不少坑也总结出一套可复现的迁移方法。这篇文章就是把这套方法完整讲清楚——为什么值得迁、怎么迁、迁的过程中会遇到什么、迁完之后怎么保证稳定。适合谁看如果你手上也有一台食之无味弃之可惜的云主机跑着一堆零散的自动化任务每个月还要为它操心那这篇内容应该能帮你省下不少时间和钱。如果你还没到那个阶段只是想了解 WorkBuddy 能干什么也可以看看至少能帮你判断这条路适不适合你。2. 先想清楚云主机到底在替我干什么WorkBuddy 又替掉了哪部分2.1 云主机真正提供的四样东西很多人关不掉云主机是因为没想明白自己到底在用它什么。我复盘了一下我那台机器实际提供的是四样东西持续运行能力机器一直开着cron 到点就触发不需要我本地电脑开机。环境隔离脚本跑在远程 Linux 上不污染我本地的 Mac 环境。网络出口有些任务需要稳定的公网访问云主机天然具备。数据落脚点抓下来的数据、生成的中间文件都存在远程磁盘上。这四样里真正不可替代的其实只有网络出口这一项而且还得看具体任务。持续运行能力WorkBuddy 的调度器可以覆盖环境隔离容器化方案比裸机更彻底数据落脚点对象存储或者本地 NAS 都能接。想清楚这一点迁移的底气就有了。2.2 WorkBuddy 补上的那块拼图WorkBuddy 这类工具的核心价值不是又一个跑脚本的地方而是把任务定义、依赖管理、执行调度、结果追踪这四件事统一到一个框架里。我过去在云主机上是这么干的写个 Python 脚本扔到/opt/scripts/加一行 crontab日志重定向到/var/log/出问题了 SSH 上去tail -f。这套流程能用但极其脆弱——换台机器就得重来一遍而且没有任何任务状态的概念跑没跑成功全靠翻日志。WorkBuddy 把这套东西结构化之后好处是显而易见的。任务是一个有明确输入输出的单元依赖写在配置里而不是散落在系统里执行记录可查失败可重试。它把运维一台机器变成了管理一批任务这是思维方式的转变也是我最终敢关掉云主机的根本原因。2.3 一个关键判断哪些任务能迁哪些不能不是所有任务都适合迁。我给自己定了个判断标准你可以直接拿去用任务类型是否适合迁移原因定时签到、打卡类适合纯逻辑无状态WorkBuddy 调度完全覆盖数据抓取与清洗适合容器化后依赖更干净结果可落对象存储文件同步、备份适合本地 NAS 调度即可不需要远程机器对外提供 API 服务谨慎需要公网入口WorkBuddy 本身不解决这个需要固定公网 IP 的任务不适合这是云主机不可替代的部分长时间常驻进程谨慎要看 WorkBuddy 是否支持常驻型任务我自己的任务里大概 80% 属于前三类剩下 20% 是需要公网入口的小服务。那 20% 我没有硬迁而是换了个更轻的方案单独处理。迁移不是全搬而是该搬的搬该留的留这一点想清楚能省很多无用功。3. 迁移前的准备工作别急着动手先把家底摸清3.1 把云主机上的任务全部列出来我做的第一件事是 SSH 上去把所有定时任务和常驻服务列了个清单。命令很简单# 列出当前用户的所有 crontab crontab -l # 列出系统级定时任务 ls -la /etc/cron.d/ /etc/cron.daily/ /etc/cron.hourly/ # 查看正在运行的服务 systemctl list-units --typeservice --staterunning # 查看监听端口找出对外服务 ss -tlnp这一步的目的是建立完整的任务清单包括每个任务的触发时间、执行命令、依赖的脚本路径、输出位置。我当时列出来 17 个 cron 任务和 3 个常驻服务其中有好几个是我早就忘了的僵尸任务跑了两年从来没成功过日志里全是报错。这种任务直接删掉不用迁。提示列清单的时候一定要顺手看一眼每个任务的日志确认它到底有没有在正常工作。我这次清理掉了 4 个看起来在跑其实早就挂了的任务等于白省了迁移工作量。3.2 梳理依赖这一步最容易翻车任务清单列完之后接下来是梳理每个任务的依赖。这是整个迁移过程中最容易翻车的一步因为云主机上的依赖往往是历史堆积的结果——你可能两年前装了个库后来升级过又装了个新版本系统里同时存在多个版本脚本能跑纯属运气。我的做法是给每个任务单独建一个依赖清单。对于 Python 脚本用pip freeze导出当前环境然后手动筛选出这个任务真正需要的包# 导出当前环境所有包 pip freeze all_packages.txt # 更精确的做法用 pipreqs 分析脚本实际导入的包 pip install pipreqs pipreqs /opt/scripts/your_task/ --force对于系统级依赖比如ffmpeg、imagemagick这类命令行工具单独记下来迁移时在容器镜像里装。不要偷懒直接复制整个pip freeze的结果那里面有一大半是别的任务用的混在一起只会让新环境越来越臃肿。3.3 数据落脚点怎么处理云主机上存的数据分两类一类是任务运行需要的输入数据一类是任务产出的结果数据。这两类的处理方式完全不同。输入数据比如配置文件、字典文件、证书体积小直接打包下载到本地迁移时打进容器或者挂载进去。产出数据比如抓取的网页、生成的报表体积可能很大我的做法是先全量下载到本地 NAS然后在新方案里改成直接写入对象存储或者 NAS 挂载点不再依赖云主机的磁盘。# 打包下载云主机上的数据目录 tar -czf backup_data.tar.gz /opt/data/ scp useryour-host:/opt/backup_data.tar.gz ./这一步做完云主机上就没有不可替代的数据了关停它才真正没有后顾之忧。4. 把任务搬进 WorkBuddy从单机脚本到任务编排的实操过程4.1 环境准备本地还是 NAS我选了哪个WorkBuddy 可以跑在本地机器上也可以跑在 NAS 或者一台常开的小主机上。我一开始想跑在 Mac 上但试了两天就放弃了——Mac 会休眠一休眠任务就断而且我不想让工作电脑承担这个职责。最后我选了一台低功耗的迷你主机常年开机功耗不到 10W一年电费可以忽略不计。如果你手头有 NAS那更省事直接在 NAS 上跑容器就行。核心要求只有一个这台机器要能稳定常开。至于系统Linux 发行版都行我用的是 Ubuntu Server主要是社区资料多遇到问题好查。WorkBuddy 本身的安装官方文档写得很清楚我这里只强调两个容易忽略的点。第一安装前先确认容器运行时是正常的很多人卡在 Docker 起不来这一步报错通常是虚拟化支持没开或者权限不对。第二数据目录要单独规划不要把 WorkBuddy 的数据和系统盘混在一起后面备份和迁移会方便很多。# 确认 Docker 正常运行 docker info # 如果报权限错误把当前用户加入 docker 组 sudo usermod -aG docker $USER # 重新登录后生效4.2 任务定义把 crontab 翻译成 WorkBuddy 任务这是迁移的核心工作。我拿一个真实的签到任务举例。原来云主机上的 crontab 是这样的# 每天早上 8 点执行签到 0 8 * * * /usr/bin/python3 /opt/scripts/checkin/main.py /var/log/checkin.log 21迁到 WorkBuddy 之后这个任务被拆成了三部分执行环境容器镜像、执行逻辑脚本、调度规则触发时间。执行环境用 Dockerfile 定义把依赖固化下来FROM python:3.11-slim WORKDIR /app # 只装这个任务需要的依赖 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY main.py . CMD [python, main.py]调度规则在 WorkBuddy 里配置指定每天 8 点触发指向这个镜像。关键区别在于原来依赖的是云主机这个环境现在依赖的是这个镜像。镜像可以在任何地方跑环境一致性有了保证。4.3 依赖隔离为什么我坚持一个任务一个镜像迁移过程中我做过一个错误决定就是把所有 Python 任务塞进同一个镜像想着省事。结果第三天就出问题了任务 A 需要requests2.28任务 B 需要requests2.31两个版本在同一个环境里打架任务 A 直接报错。后来我改成一个任务一个镜像虽然镜像数量多了但每个任务的环境完全独立互不影响。这跟云主机上所有任务共享一个系统环境是完全不同的思路也是容器化真正的价值所在。代价是磁盘占用会多一些但现在的磁盘便宜得很这点代价换来的是稳定性非常值。注意一个任务一个镜像不代表每个镜像都要从零构建。可以做一个基础镜像装好公共依赖比如 Python 本身、常用工具然后各个任务镜像基于它构建只加自己特有的依赖。这样既隔离又省空间。4.4 调度配置时间、重试、超时怎么设WorkBuddy 的调度配置比 crontab 丰富得多我重点调了三个参数超时时间crontab 没有超时概念任务卡死了就一直卡着。WorkBuddy 可以设超时超时自动终止。我给每个任务设的超时是正常执行时间的 3 倍比如签到任务正常 30 秒完成超时设 90 秒。重试策略网络类任务失败很常见设 2 到 3 次重试间隔 5 分钟能解决大部分偶发失败。并发控制同一个任务不允许并发执行避免上一次还没跑完下一次又来了导致数据错乱。这三个参数看起来不起眼但它们是从能跑到稳定跑的关键。我在云主机上从来没设过这些因为 crontab 根本不支持出了问题只能人工介入。现在这些都由框架兜底了。5. 迁移过程中踩过的坑这些错误你大概率也会遇到5.1 路径依赖脚本里写死的绝对路径全废了我第一个踩的坑是路径。云主机上脚本里到处是/opt/scripts/xxx、/var/log/xxx这种绝对路径迁到容器里之后工作目录变成了/app所有路径全错。第一次跑直接报FileNotFoundError。解决办法有两个一是改脚本把路径改成相对路径或者从环境变量读取二是在容器里创建同样的目录结构让老路径继续可用。我选了第一种虽然要改代码但改完之后脚本更干净了以后换环境也不用再改。如果你脚本很多可以先批量搜索一下硬编码路径# 找出脚本里所有绝对路径引用 grep -rn /opt/\|/var/\|/home/ /opt/scripts/5.2 时区问题任务在错误的时间跑了这个坑很隐蔽。云主机上系统时区是东八区crontab 按本地时间触发。迁到容器之后容器默认是 UTC 时区结果我设的早上 8 点变成了北京时间下午 4 点执行。签到任务在下午跑数据全乱了。修复方法是在容器里显式设置时区ENV TZAsia/Shanghai RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime echo $TZ /etc/timezone或者在 WorkBuddy 的调度配置里明确指定时区。这个坑几乎每个迁移的人都会踩一次因为它在测试阶段不容易发现——你测试的时候是手动触发手动触发不看时区只有等到定时触发才暴露。5.3 环境变量丢失密钥和配置全没了云主机上我习惯把一些密钥、API token 写在.bashrc或者 systemd 的 service 文件里脚本运行时自动能读到。迁到容器之后这些环境变量全没了脚本一跑就报缺少配置。正确的做法是把配置和密钥通过 WorkBuddy 的环境变量配置注入而不是写死在镜像里。写死在镜像里的密钥一旦镜像泄露就等于密钥泄露而且改密钥还得重新构建镜像非常麻烦。用环境变量注入改配置不用动镜像安全性和灵活性都好得多。5.4 日志看不到出问题了不知道去哪查在云主机上出问题我tail -f /var/log/xxx.log就行。迁到 WorkBuddy 之后一开始我不知道日志去哪了任务失败了只能看到执行失败四个字具体报错完全看不到。后来才搞明白容器的日志要输出到标准输出stdout/stderrWorkBuddy 才能捕获并展示。所以脚本里的日志配置要改从写文件改成打印到控制台import logging import sys logging.basicConfig( levellogging.INFO, format%(asctime)s [%(levelname)s] %(message)s, handlers[logging.StreamHandler(sys.stdout)] )改完之后所有日志都能在 WorkBuddy 的界面里看到比翻文件方便多了。这是容器化日志的最佳实践应用只管往 stdout 打日志的收集和存储交给平台。6. 关停云主机之后我的新架构长什么样6.1 整体架构一台迷你主机 WorkBuddy NAS关停云主机之后我的自动化任务架构变成了这样一台低功耗迷你主机跑 WorkBuddy 和容器负责调度和执行一台 NAS 负责存储数据和备份两者通过局域网连接。原来云主机上的任务现在全部跑在这套本地架构上。这个架构最大的好处是成本几乎为零。迷你主机是一次性投入NAS 本来就有电费一年几十块。相比云主机每年几百块的续费两年就回本了。而且数据全在本地隐私和可控性都更好。当然也有代价。原来云主机有公网 IP现在没有了那些需要对外提供服务的任务得另想办法。我的处理方式是能改成拉的就改成拉比如原来是对外提供 API现在改成定时把数据推到需要的地方实在需要公网入口的用轻量的内网穿透方案单独处理不占用主架构。6.2 稳定性怎么保证三层防护关掉云主机之后我最担心的是稳定性。毕竟云主机有服务商兜底本地机器全靠自己。我做了三层防护第一层硬件冗余。迷你主机和 NAS 都接了 UPS短时间断电不影响。硬盘做了 RAID单盘故障不丢数据。第二层任务级重试。前面说的超时和重试策略能自动处理大部分偶发失败。第三层失败告警。WorkBuddy 支持任务失败通知我配了通知渠道任务连续失败会推送到手机我能第一时间知道。这三层下来实际运行的稳定性比我预期的好。跑了三个月只有一次因为家里网络波动导致任务失败重试之后自动恢复了我甚至没来得及介入。6.3 备份策略数据不能只存一份本地架构最大的风险是单点故障——机器坏了数据可能就没了。所以备份必须做而且要异地备份。我的策略是NAS 上的数据每天增量备份到一块移动硬盘每周全量备份到另一块硬盘两块硬盘轮流放在不同地方。WorkBuddy 本身的配置和数据也要备份主要是任务定义和调度配置。这些数据体积小我直接导出成文件跟着 NAS 的备份一起走。恢复的时候只要重新装好 WorkBuddy导入配置任务就能全部恢复整个过程不超过半小时。7. 给准备迁移的人几条实在建议7.1 别一次性全迁先迁一个任务试水我见过太多人一上来就想把所有任务全搬过去结果遇到一堆问题最后放弃。正确的做法是先挑一个最简单、最独立的任务试水把整个流程跑通包括环境构建、调度配置、日志查看、失败处理。这一个任务跑顺了剩下的就是复制粘贴加微调。我第一个迁的是最简单的文件同步任务没有任何外部依赖半小时就搞定了。这个成功经验给了我信心也让我摸清了 WorkBuddy 的脾气后面迁复杂任务就顺多了。7.2 云主机别急着退先并行跑两周关停云主机之前我让新旧两套系统并行跑了两周。同样的任务云主机跑一遍WorkBuddy 也跑一遍对比结果。两周下来确认 WorkBuddy 这边的结果和云主机一致甚至更稳定我才正式关停。这两周的并行期非常值。它帮我发现了时区问题、路径问题、环境变量问题这些问题如果等关停之后才发现那就抓瞎了。并行期的成本是两周的云主机费用换来的是迁移的确定性这笔账怎么算都划算。7.3 把任务当代码管理别当配置管理最后一个建议也是我觉得最重要的把任务定义当成代码来管理。什么意思就是任务的所有配置——Dockerfile、脚本、调度规则——都放进版本控制里每次改动都有记录可以回滚。我一开始是直接在 WorkBuddy 界面上改配置改完就忘了改了什么出了问题想回滚都不知道回到哪个版本。后来我把所有配置抽出来放进 Git 仓库WorkBuddy 从仓库读取配置每次改动先提交再部署。这样一来任何问题都能追溯到具体的改动回滚也就是一条命令的事。这套做法在云主机时代我就该用但那时候任务少、改动少没觉得有必要。现在任务多了版本控制的价值就体现出来了。任务编排工具再强也替代不了良好的工程习惯这一点是我这两年折腾下来最深的体会。
返回列表