Incus 实战SWES · 技术记录

一台 2C2G 的 VPS,我把它切成了 6 台小鸡:为什么选 Incus?

一台 2C2G 年付 ¥144 的 VPS,为什么切成 6 台小鸡、为什么选 Incus 6.0 LTS、btrfs 共享配额池和 256MiB 规格背后的算账过程。

手里这台 AndNode 的年付小鸡(2 核 / 2G 内存 / 30G 盘,¥144/年)平时跑着 xboard 节点,负载常年个位数。一台机器只干一件事,剩下的 CPU 和内存全在睡大觉——看着心疼。于是我决定:把它切成 6 台 256MiB 的小鸡,剩下的资源继续跑节点。这篇讲清楚选型:为什么是 Incus,而不是 KVM,也不是直接跑 Docker。

隐私说明:文中出现的公网 IP 一律用 203.0.113.10 代指(RFC 5737 文档段,不可路由),请换成你自己的真实 IP 再操作。

为什么这么做:需求先行

先说我要什么。我要的是完整的小鸡:能 SSH 登录、有独立 root、能跑 systemd 服务、能装 Komari 监控、以后甚至能分给朋友用。KVM 太重——宿主机只有 2G 内存,KVM 每台虚机都要完整内核,开销吃不消。纯 Docker 不行——容器里没有 systemd,systemctl 用不了,很多运维习惯(服务自启、日志)全得改,而且 Docker 的网络模型是给"应用"用的,不是给"机器"用的。

Incus 正好卡在这个 sweet spot 上:它是 LXD 的社区延续,跑的是系统容器——容器里是一个完整的 Debian 用户态,systemd 照常工作,开销却接近 Docker。6 台 256MiB 的小鸡,内存总占用 1.5G,给宿主机留 512M,账算得过来。

怎么做:三个关键选型

1. 为什么用 Incus 6.0 LTS + Zabbly 源

Debian 12 官方仓库里的 incus 版本太旧,我要的是长期支持版。Zabbly 是 Incus 上游维护者 Stéphane Graber 做的官方包源,lts-6.0 分支对应 Incus 6.0 LTS。脚本里是这样加的:

curl -fsSL https://pkgs.zabbly.com/key.asc -o /etc/apt/keyrings/zabbly.asc

但直接信任一个远程 key 是运维大忌,所以脚本里多了一步指纹校验:

ACTUAL=$(gpg --show-keys --with-colons /etc/apt/keyrings/zabbly.asc 2>/dev/null \
  | awk -F: '$1=="fpr" {print $10; exit}')
[[ "$ACTUAL" == '4EFC590696CB15B87C73A3AD82CC8797C838DCFD' ]] || fail '软件仓库密钥指纹不匹配'

指纹对不上直接退出,一行代码都不往下跑。第三方源的中间人攻击是真实存在的威胁,这一步不能省。

2. 为什么用 btrfs 12GiB 共享池,而不是每台预留 3G

incus admin init --minimal 默认用 dir 后端——简单,但不支持磁盘配额,一台小鸡写满能把宿主机拖死。所以脚本单独建了一个 btrfs 池:

incus storage create "incus-quota" btrfs size="12GiB"

注意这是共享池,不是每台预留。tiny-vps 这个 profile 给每台小鸡的根盘设 size=3GiB:

incus profile device add tiny-vps root disk path=/ pool="incus-quota" size=3GiB

3GiB 是上限不是预留——6 台小鸡理论上限 18G,但池子只有 12G,用多少占多少。这就是 btrfs 配额的意义:防止单台失控,又不提前锁死空间。脚本注释里也写得很诚实:btrfs loop 后端的配额是"软隔离",防误操作可以,防恶意租户不够——我的场景是自用,够了。

顺带说下为什么没选别的后端:dir 最简单但不支持配额,一台小鸡 dd if=/dev/zero 能把宿主机写死;zfs 功能最强,但在 Debian 上要装 zfs-dkms,内核模块编译又慢、又容易随内核升级翻车;lvm 要预留分区,VPS 上一般就一块盘,动分区表风险高。btrfs 一行命令、用 loop 文件当后端,不用动分区,配额原生支持——对 2C2G 的小 VPS,这是摩擦最小的选择。

为什么是 256MiB,而不是 128MiB 或 512MiB:Debian 12 最小化安装 + sshd 跑起来约占 80–100M,apt-get upgrade 时需要额外的内存做解包缓冲,128M 会频繁捉襟见肘;512M 则 6 台就要 3G,宿主机只有 2G 的机器上直接超标。256M 是"刚好够用再多一点"的平衡点,后续 Komari 面板里能看到真实的内存曲线,届时再调。

还有个不起眼但重要的参数:boot.autostart=true。宿主机(年付 VPS)偶尔会重启维护,没有这个,小鸡全得手动 incus start 一台台拉起来。有了它,宿主机开机后小鸡自动恢复——无人值守的第一步。

网络拓扑:内网 + 最小暴露面:容器挂在 incusbr0 网桥的内网段(默认 10.x),出站走 NAT,公网默认只暴露 SSH 端口(2201–2206)。业务端口需要时再用端口管理器一个个加。这种"默认关闭、按需开放"的拓扑,是公网机器的基本素养——端口扫出来越少,半夜被吵醒的概率越低。

3. 规格 1核 / 256MiB / 3GiB 怎么定

256MiB 跑 Debian 12 + sshd + Komari agent 实测够用(后面系列会给出监控数据)。1 核是 Incus 的软限制,6 台小鸡抢 2 个物理核,靠 CFS 调度;都是轻负载场景,超分没问题。SSH 端口按 2200+N 规律分配(vps1=2201 … vps6=2206),好记,好写防火墙规则。为什么不用 22?一是宿主机自己的 SSH 已经占了 22,二是 2201–2206 这个段在公网扫描里不算高频目标,多少能躲掉一部分无脑爆破——当然,真正防爆破靠的是后面要讲的密钥登录和 fail2ban,端口号只是顺手。

踩坑与演进:先在练手鸡上交学费

其实在动生产机之前,我先在另一台 RackNerd 的练手机上用 runman 开了 5 台 256MB 的小鸡做实验。结论:5 台同时压测,母鸡 CPU 直接 100%,每台只分到约 14%。这个实验让我定了两条规矩:生产机上的小鸡只跑轻负载,以及所有脚本必须自带资源上限(limits.cpu / limits.memory 写死在 profile 和 launch 参数里)。

横向对比:KVM / Docker / PVE / Incus 怎么选

方案 内存开销 有 systemd 运维习惯 结论
KVM 虚机 每台一个完整内核,2G 宿主机开 6 台很吃力 有 和物理机一样 太重,放弃
纯 Docker 极低 无 全得改(无 systemctl、无 sshd 习惯) 我要的是"小鸡"不是"应用",放弃
PVE 和 KVM 同级 有 功能全但重 杀鸡用牛刀,放弃
Incus 系统容器 接近 Docker 有 incus exec 即进系统,ssh/systemd 照常 选中

PVE 也考虑过——它是大而全的虚拟化平台,但我要的只是"把一台机器切成几台小鸡",PVE 的集群、存储、Web UI 全是多余重量。Incus 是 LXD 的社区延续,单机一条命令 incus admin init --minimal 就跑起来,复杂度刚刚好。

这套方案不适合谁:如果你要把小鸡分给互不信任的人用,Incus 系统容器的隔离强度不如 KVM(共享宿主机内核),btrfs 配额也是软隔离。我的场景是自用 + 给熟人用,这个强度够了。

最终效果与成本账

  • 部署脚本(incus_3vps_docker_compatible_verified.sh)已在 AndNode 年付机真机跑过,vps1 已 launch,SSH 端口已映射到公网,存储池 incus-quota、profile tiny-vps 就绪。
  • 成本:¥144/年 ÷ 6 台 ≈ ¥24/台/年。这个价位市面上买不到任何带独立 SSH 的小鸡。

下一篇讲这个一键部署脚本的逐段解析:每一行为什么这么写。

感谢阅读 · 保持好奇,认真记录。浏览更多文章 ↗