外观
Docker 宿主虚拟机
Docker 能跑在 PVE 的虚拟机里,也能跑在 LXC 容器里。这篇只讲虚拟机方案怎么规划——它是官方支持、兼容性最好的做法,也是大多数人应该默认选择的方案。
适合谁
| 你的情况 | 适不适合 |
|---|---|
| 要跑一堆 Compose 编排的服务,不想为每个服务单独建 LXC | 适合,这是虚拟机方案最大的优势 |
已经很熟悉 LXC,愿意折腾 nesting/keyctl 和 UID 映射排查权限问题 | 可以考虑 LXC 方案,但本文不展开,见下文 |
| 容器需要用到内核特性、iptables、或者不确定的第三方镜像 | 用虚拟机更省心,隔离更彻底 |
为什么优先推荐虚拟机而不是 LXC
虚拟机有自己独立的内核,Docker 依赖的 overlay 文件系统、cgroups、命名空间都在一个完整内核里工作,不存在兼容性问题。LXC 里跑 Docker需要手动开启 nesting 和 keyctl 两个选项,而且非特权容器的 UID 映射可能和 Docker 自己的用户命名空间冲突,导致数据卷权限报错——这类问题排查起来比直接开一台虚拟机费时得多。
选型的通用判断标准见容器还是虚拟机:Docker 场景下「不确定内核特性是否兼容」这一条,虚拟机赢面更大。
资源规划
| 项 | 建议起点 | 说明 |
|---|---|---|
| vCPU | 2–4 | 按容器数量和负载调整 |
| 内存 | 4 GB 起 | 每个容器的实际占用差异很大,先观察 docker stats 再加 |
| 系统盘 | 32 GB | 只放操作系统,不放容器数据 |
| 数据盘 | 单独一块,按需 | 见下文,这是本文最重要的一条建议 |
| 气球驱动 | 可以开 | Docker 宿主对内存动态回收不算敏感,和数据库/NAS 虚拟机不同 |
把容器数据单独分盘的理由
Docker 的镜像、容器可写层和数据卷默认都存在 /var/lib/docker 下,在系统盘所在的根分区里。容器数据涨起来没有上限——一次日志失控或者一个下载类容器的卷写满磁盘,会连累根分区,导致系统本身也出问题(无法写日志、无法登录)。
单独给一块虚拟磁盘、挂载到 /var/lib/docker(或者用 Docker 的 data-root 配置指过去),写满的是数据盘而不是系统盘,出问题时恢复也更简单:只需要处理这块盘,不影响系统。
创建与安装
按创建第一个虚拟机的通用建议创建一台 Debian 或 Ubuntu(也可以用Debian / Ubuntu 云镜像模板十秒钟开一台)。System 页不需要 TPM,Machine 用默认的 q35 或 i440fx 均可。
装完系统后,在客户机内部加一块数据盘并挂载:
sh
# 在虚拟机内部执行,<数据盘设备> 用 lsblk 确认,通常是新加的那块(例如 /dev/sdb)
lsblk
mkfs.ext4 /dev/sdb
mkdir -p /var/lib/docker
mount /dev/sdb /var/lib/docker
echo '/dev/sdb /var/lib/docker ext4 defaults,noatime 0 2' >> /etc/fstab先挂载再装 Docker,顺序不能反
如果 Docker 已经在 /var/lib/docker 里写了数据再挂载新盘,旧数据会被新盘的空目录「盖住」(挂载点覆盖)。先建好挂载点、挂好盘,再装 Docker,或者用 data-root 配置项指向一个还没使用过的新路径,避免手工搬迁数据。
安装 Docker Engine 按照 Docker 官方为你的发行版提供的安装脚本或仓库配置进行,具体命令随发行版版本变化,以 Docker 官网当前文档为准。
第一次启动之后
安装 guest agent(做法和其他 Linux 客户机一样,见 VirtIO 驱动与 QEMU Guest Agent):
sh
# 在虚拟机内部执行
apt update && apt install -y qemu-guest-agent
systemctl enable --now qemu-guest-agent确认 Docker 使用的存储驱动和数据目录符合预期:
sh
# 在虚拟机内部执行
docker info | grep -E "Storage Driver|Docker Root Dir"Storage Driver 应该是 overlay2(默认且推荐),Docker Root Dir 应该指向你挂载的数据盘路径。
ZFS 存储上的虚拟机磁盘怎么选文件系统
宿主机用 ZFS 存放虚拟机磁盘(zvol 或数据集)不影响这一步——虚拟机看到的仍然是一块普通磁盘,客户机内部照常格式化成 ext4 即可。overlay2 需要的是客户机内部文件系统的支持,和宿主机存储类型无关。不建议让 overlay2 直接跑在宿主机透传进来的 ZFS 数据集上,会有性能损失。
检查结果
docker run hello-world能正常拉取镜像并运行成功,说明网络和存储驱动都工作正常。docker info | grep "Storage Driver"显示overlay2。df -h /var/lib/docker指向的是数据盘而不是根分区。- 起一个真实的 Compose 服务,重启虚拟机(PVE 里 Shutdown 再 Start),确认容器随
docker服务自动拉起、数据卷内容还在。 - PVE 的
虚拟机 → Summary能看到 IP,说明 guest agent 正常。
备份与维护
把这台虚拟机纳入常规的 vzdump 备份任务,方法见配置备份任务与保留策略。由于数据盘和系统盘是分开的虚拟磁盘,vzdump 默认会把两块都备份进去——检查一下虚拟机的备份任务没有把数据盘排除在外。
大容量数据卷会拖慢整机备份
如果某个容器的数据卷体积很大(比如媒体库、数据库文件),每次全量备份这块数据盘会很慢、很占空间。可以考虑:数据库类应用用它自己的导出/物理备份工具做增量备份,vzdump 只负责保底的整机快照式备份。具体策略取舍见家庭实验室的最小可用备份方案。
升级
Docker Engine 和宿主发行版的升级按各自的常规流程(apt full-upgrade、Docker 官方的升级说明)进行。升级前,尤其是发行版大版本升级前,在 PVE 里打一个快照,出问题可以回滚,做法见快照、克隆与模板。
常见问题
容器能起,但拿不到网络。 先排查客户机自身的网络(网关、DNS)是否正常,再检查 Docker 的网桥(docker network ls)和宿主机防火墙规则;和 PVE 层面的网络配置通常无关。
磁盘满了,但 /var/lib/docker 明明挂在单独的盘上。 检查是不是 Docker 的日志驱动没有限制大小(docker logs 默认可能无限增长),或者镜像/悬空容器层没有清理,用 docker system df 看占用分布,docker system prune 清理前先确认不会删掉还需要的数据。
想在 LXC 里跑 Docker,而不是虚拟机。 需要给容器开 nesting: 1(部分场景还要 keyctl: 1),并接受非特权容器可能遇到的 UID 映射和存储驱动兼容性问题。PVE 9 配合较新的 ZFS 版本时 overlay2 在 LXC 里能正常工作,但整体排查成本比虚拟机高,本站不展开具体配置步骤。
参考资料
- 容器还是虚拟机
- 创建第一个虚拟机
- Debian / Ubuntu 云镜像模板
- 配置备份任务与保留策略
- Docker 官方文档:安装指南与存储驱动说明(随发行版版本变化,以官网当前内容为准)