我迁到 Docker,不是因为容器更酷,而是因为家庭服务需要可复现、可恢复、可排障。

\n
我第一次把家庭服务从“宿主机直接安装”迁到 Docker,并不是因为原来的方式完全不能用。相反,很多服务一开始跑得很稳,问题出在时间拉长以后:系统升级、依赖变化、端口冲突、临时改过的配置找不到记录。机器还能开机,页面也许还能打开,但我已经说不清某个服务到底依赖了哪些包、数据放在哪里、下次换硬盘时应该先搬什么。

Docker 对我最大的价值,是把运行事实写进文件。镜像版本、启动命令、环境变量、端口、卷挂载、网络和重启策略都在 Compose 里。哪怕半年后回来维护,也能先看文件,而不是翻聊天记录、浏览器收藏和终端历史。HomeLab 不怕慢一点,怕的是“现在能跑,但谁也不知道为什么能跑”。

先按风险给服务分类

我不会一上来就把所有东西都迁。比较稳的顺序是先迁无状态或低状态服务,例如仪表盘、文档页、临时工具、监控展示;再迁有配置但数据量不大的应用;最后才考虑数据库、账号系统、同步类任务和依赖硬件的服务。

每迁一个服务,我都会问三个问题:配置目录在哪里,业务数据在哪里,停机后怎么恢复。答不上来就先不动。直接安装时代码、配置、缓存容易混在一起,容器化以后反而逼着我把这些边界拆清楚。服务能不能迁,不只看有没有镜像,还要看它的数据和恢复路径是否清楚。

可复现比“装成功”更重要

手动安装经常是一次性动作,成功以后很难复盘。Docker Compose 的好处是可以反复执行同一套声明:今天在这台机器上启动,明天在测试目录里拉起,换机器时也能先恢复目录再启动。可复现不是保证永远不坏,而是坏了以后能回到同一个起点。

我会尽量固定镜像版本,例如 example/app:1.4.2,少用没有计划的 latest。如果必须临时用新版本,也会把升级前的版本记下来。端口和路径同样写死在 Compose 或 .env 里,不靠面板临时点出来。这样做看起来啰嗦,但真正排障时少掉很多“我是不是改过这里”的猜测。

回滚要在迁移前想清楚

迁移前我会先做一次旧服务备份:配置文件、数据库、上传目录、启动脚本和当前端口。迁移后如果新容器行为不对,最坏情况应该能停掉容器,把旧服务按原方式拉回来。这个回滚点不需要漂亮,但必须可执行。

我的习惯是给每个服务留一份小记录:

service: notes
old_port: 8080
new_port: 18080
config: /srv/docker/notes/config
data: /srv/docker/notes/data
image_before: example/notes:1.3.8
image_after: example/notes:1.4.2
rollback: stop compose, restore old config, start old service

这类记录不用写成长文,关键是让下一次维护时能知道“改了什么”和“怎么退回去”。

哪些服务不适合急着迁

有些东西我会先留在宿主机:强依赖内核模块的服务,需要特殊 USB 设备直通的服务,对局域网广播发现特别敏感的服务,以及供应商面板深度接管的系统组件。它们不是不能容器化,而是迁移后排障面会变大。为了“看起来统一”强行迁进去,最后可能会得到一个更难维护的系统。

还有一类服务虽然能迁,但要等备份和恢复演练做完再迁。尤其是账号、数据库、同步任务和长时间运行的队列,不能只看容器启动成功。页面能打开只说明第一步过了,数据一致性、权限、定时任务和日志状态还要继续看。

我的迁移节奏

我现在更愿意一周只迁一两个服务。迁完后保留观察窗口,确认重启、备份、恢复、日志和入口访问都正常,再动下一个。过程中会反复用这些命令:

docker compose config
docker compose up -d
docker compose ps
docker inspect notes --format '{{json .Mounts}}'
docker compose logs --tail=120 notes

docker compose config 用来确认最终配置是否按预期展开;inspect 用来确认数据确实落在宿主机目录;日志用来判断应用是不是在重复初始化、权限失败或连接不上依赖。等这些都清楚了,Docker 才真的变成维护工具,而不是又一个新的不确定来源。

迁移的核心不是把服务塞进容器,而是把运行方式、数据位置和回滚办法固定下来。只要这三件事清楚,HomeLab 后面的升级、换盘、重装和排障都会轻很多。

最后修改:2026 年 06 月 13 日
如果觉得我的文章对你有用,请随意赞赏