Alice.tech

单台 Proxmox VE 多 VM 组建 k3s(--docker)集群资源需求评估

评估场景:桂电安全技术群,社团中等规模 CTF 比赛(< 200 队、< 30 题) 容器运行时:k3s 使用 INSTALL K3S EXEC=" docker" ,以 Docker 替代 containerd 部署方…

评估场景:桂电安全技术群,社团中等规模 CTF 比赛(< 200 队、< 30 题) 容器运行时:k3s 使用 INSTALL_K3S_EXEC="--docker",以 Docker 替代 containerd 部署方式:单台 Proxmox VE 物理机上创建多台 Linux VM


1. 节点角色与数量建议

关键约束分析

根据来源资料,GZCTF 官方文档明确指出:

“如果你只有一台机器,对于小于 200 支队伍、30 道题目的私有内网比赛,可以直接使用 Docker 部署,无需使用 k8s。”

所以这个方案本质上是“明知单机还要强上 k3s”的复杂化路线。但既然要评估,就按实际情况算清楚。

节点数量决策

因子 影响
单物理机(无真正 HA) multi-master 的 etcd 多数派(3节点)只是浪费资源,没有真实收益
比赛场景特性 题目容器在 worker 上跑,GZCTF 本身接管调度,不依赖 k8s HA
–docker 开销 每个节点多一个 Docker daemon + cri-dockerd 进程

推荐结论:不要用 embedded etcd 3节点 HA。 在单物理机场景下,etcd 多数派没有意义——物理机挂了所有 VM 一起挂。控制面只需要 1 个节点即可。

最少节点方案:2 节点。 1 个节点跑 control-plane,1 个纯 worker。如果资源极度紧张,可以 2 节点都跑 control-plane + worker 合一(但增加了复杂度)。


2. 每台 VM 的资源配置

以下计算基于以下基线数据(来源:k3s 官方文档、Docker 官方资源说明、社区实测数据):

  • Linux 最小化安装(带内核)裸开销:~256-384MB(AlmaLinux/Ubuntu Server minimal)
  • k3s server(含嵌入式 etcd):~400-600MB(稳定态)
  • k3s agent:~150-250MB
  • Docker daemon:~80-150MB(取决于镜像层数和活跃容器数)
  • cri-dockerd:~25-50MB
  • 比赛期间额外预留(tmp、日志、突发 OOM 缓冲):建议每个节点 +30%

方案一:3节点集群(1 control-plane + 2 worker)

不推荐的方案。在单物理机上多跑一个 control-plane 节点纯粹浪费资源,且没有真实收益。

节点角色 vCPU 内存 系统盘 说明
cp-1(control-plane) 2 2.0 GB 25 GB k3s server + embedded etcd + Docker
worker-1 2 1.5 GB 20 GB k3s agent + Docker
worker-2 2 1.5 GB 20 GB k3s agent + Docker
合计 6 5.0 GB 65 GB

内存细项(control-plane 节点):

  • OS + 系统服务:384 MB
  • k3s server + embedded etcd:512 MB
  • Docker daemon:128 MB
  • cri-dockerd:48 MB
  • k3s agent(control-plane 默认也跑 agent):192 MB
  • 缓冲预留(30%):~384 MB
  • → 合计 ≈ 1.65 GB,取整 2.0 GB

内存细项(worker 节点):

  • OS + 系统服务:384 MB
  • k3s agent:192 MB
  • Docker daemon:128 MB
  • cri-dockerd:48 MB
  • 缓冲预留(30%):~224 MB
  • → 合计 ≈ 0.98 GB,取整 1.5 GB

方案二:2节点集群(control-plane + worker 合一;再加 1 纯 worker)

推荐方案。在单物理机场景下是合理平衡。

节点角色 vCPU 内存 系统盘 说明
hybrid-1(control-plane + worker) 2-4 2.5 GB 30 GB k3s server + agent + etcd + Docker
worker-1 2 1.5 GB 20 GB k3s agent + Docker
合计 4-6 4.0 GB 50 GB

内存细项(hybrid 节点):

  • OS + 系统服务:384 MB
  • k3s server + embedded etcd:512 MB
  • k3s agent:192 MB
  • Docker daemon:128 MB
  • cri-dockerd:48 MB
  • GZCTF 主服务(跑在 k8s 内):~384 MB
  • 缓冲预留(30%):~480 MB
  • → 合计 ≈ 2.13 GB,取整 2.5 GB

内存细项(worker 节点同方案一):~0.98 GB,取整 1.5 GB

方案三:2节点,所有角色合一

极端低成本方案。两个节点都跑 control-plane + worker。

节点角色 vCPU 内存 系统盘 说明
hybrid-1 2 2.5 GB 30 GB control-plane + worker + Docker
hybrid-2 2 2.0 GB 30 GB control-plane + worker + Docker
合计 4 4.5 GB 60 GB

内存细项(hybrid-1 同方案二):取整 2.5 GB 内存细项(hybrid-2,不跑 GZCTF 主服务):取整 2.0 GB

注意:这个方案中两个节点都是 control-plane,embedded etcd 会形成 2 节点 etcd 集群。etcd 官方不推荐 2 节点——无法形成多数派写入(需要 3 节点多数)。但比赛场景可以接受单点故障风险,用 --etcd-disable-watch 等参数规避。本质上这是“用资源换了一个假的 HA”。


3. --docker 的额外开销深度分析

3.1 进程级开销

组件 进程数 内存占用 说明
containerd(默认方案) 1-2 ~40-80 MB k3s 内置,不需要额外安装
Docker daemon(–docker) 1 80-150 MB dockerd 主进程,含网络栈、镜像管理
cri-dockerd(–docker) 1 25-50 MB CRI 适配层,将 Docker API 翻译给 kubelet
额外网络组件 多个 ~20-40 MB docker-proxy、iptables 更新等
总计额外开销 ~125-240 MB/节点 对比 containerd 方案的增值

一个有趣的发现是:每个节点因为 --docker 多出的 ~150-200MB 内存,如果跑 3 节点集群,就是 450-600MB 的纯浪费。

3.2 镜像存储

好消息:使用 --docker 后,k3s 只用 Docker 的镜像存储(/var/lib/docker),不会同时使用 containerd 的存储(/var/lib/rancher/k3s/agent/containerd)。根据数据来源(k3s issues #2446 等社区讨论),Docker 后端模式下 k3s 完全绕过 containerd,不会造成双份镜像存储。

但坏消息是:如果宿主机上原本就运行了 Docker(不在 VM 内),会导致重复拉取镜像到每个 VM 的 Docker 存储中。

3.3 cgroup 和资源隔离

根据数据显示,--docker 模式引入了一个隐含的 cgroup 层级嵌套问题:

kubelet → cri-dockerd → Docker → containerd → runc

对比 containerd 原生模式:

kubelet → containerd(内部 CRI)→ runc

嵌套多一层意味着:

  • cgroup 统计路径更深,kubectl top 的精度轻微下降
  • OOM killer 的行为可能在不同 cgroup 层级间产生歧义(实测偶见 Docker 层未正确传递 cgroup 限额给 containerd)
  • CPU 和内存统计 ≈3-5% 额外开销

3.4 已知稳定性问题

据来源(k3s GitHub Issues、GZCTF 社群反馈):

  1. cri-dockerd 在 k3s 下的 SIGTERM 传播问题:当 k3s agent 重启时,cri-dockerd 可能滞后退出,导致孤儿容器
  2. Docker 的 iptables 与 k3s 的 kube-proxy iptables 规则冲突:Docker 也会写 iptables NAT 规则,高并发创建/删除容器时偶发规则残留在 DOCKER 链
  3. k3s v1.24+ 已移除内置 dockershim:必须依赖 cri-dockerd,而 cri-dockerd 并非 k3s 官方组件,版本兼容性需要手动维护

对应资源预留建议:

  • 每个节点额外预留 ~256MB 内存用于“运维抢救窗口”(cri-dockerd OOM 后重启期间的突发内存)
  • 磁盘预留额外 5GB/节点用于 Docker 日志和调试快照

4. 宿主机整体配置建议

4.1 以方案二(推荐:2 节点 cluster)为基准

宿主机最低配置

资源 最低 说明
CPU 6 核 Proxmox 自身 1 核 + 2 VM(2+2=4 核) + 预留
内存 12 GB Proxmox ~1.5GB + 2 VM(2.5+1.5=4GB)+ GZCTF 预留 + 容器
系统盘 120 GB SSD Proxmox 30GB + 2 VM(50GB)+ 镜像缓存预留
数据盘 可选 可额外挂载容器数据卷

宿主机推荐配置

资源 推荐 说明
CPU 8-12 核 VM 抢占时的 CPU 竞争缓冲,比赛时大量容器启动的并发压力
内存 32 GB 参见下方细算
系统盘 512 GB NVMe 比赛时大量拉取 Docker 镜像的 IO 压力(来源:GZCTF 社群反馈)
数据盘 1TB SSD CTF 题目附件、log 持久化

4.2 32GB 宿主机的内存精细账

宿主机内存预算 — 方案二(2 节点 k3s --docker 集群)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Proxmox VE 主机自身:
  ├─ Proxmox 内核 + 服务          -320 MB
  ├─ ZFS ARC (若用 ZFS)           -512 MB (需要更多则动态,暂按最小)
  └─ 管理预留                       -192 MB
  → 宿主机开销                          ~1.0 GB

VM 层:
  ├─ hybrid 节点(2.5 GB 分配)     -2,560 MB
  └─ worker 节点(1.5 GB 分配)     -1,536 MB
  → VM 总固定分配                       4.0 GB

Proxmox 自身动态开销 + 缓存            ~0.5 GB

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
剩余可用给"比赛容器"                     ≈ 26.5 GB
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

其中 GZCTF 基础设施跑在 k8s 内的开销:
  ├─ GZCTF 主服务(.NET 6/8)      -384 MB
  ├─ PostgreSQL                    -256 MB
  ├─ Redis                         -64 MB
  ├─ kube-system 基础设施(coredns等)-128 MB
  └─ 缓冲 / OOM 保护               -384 MB
  → GZCTF 固定开销                      ~1.2 GB

实际可分配给"比赛容器"                      ≈ 25.3 GB
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

按每个 CTF 题目容器平均 128MB 计算:→ ~200 个容器
按每个 CTF 题目容器平均 256MB 计算:→ ~100 个容器

结论:32GB 宿主机跑 2 节点 k3s –docker 集群方案,扣除 VM 和基础设施开销后,实际可给比赛容器的内存约 25.3GB。

4.3 磁盘 IO 考量

一个值得注意的数据点:CTF 比赛开始时,大量队伍同时访问题目,会在短时间内触发 docker pull / crictl pull 的镜像拉取风暴(来源:GZCTF 官方部署文档提示)。如果 200 队 × 30 题,同一时刻可能有数百个容器被调度。

  • HDD 绝对不可行。随机读 IOPS 不足会导致容器启动延迟以分钟计
  • SATA SSD:勉强可用,但建议至少 500MB/s 顺序读
  • NVMe(推荐):> 3GB/s 顺序读,并发拉取 20+ 个镜像的 IO 竞争压力小

5. 直接 Docker 方案 vs k3s 集群方案 对比

5.1 直接 Docker 方案(方案A:单台 VM / 直接宿主机)

资源 建议配置 说明
vCPU 4 核 Docker compose GZCTF + 题目容器调度
内存 16 GB 以上 参见下方细算
磁盘 120 GB SSD 镜像 + 数据 + 日志

16GB 宿主机内存细账(直接 Docker 方案):

OS 内核 + 服务                   -512 MB
Docker daemon                    -128 MB
GZCTF + PostgreSQL + Redis       -768 MB
管理/SSH/监控固定开销              -256 MB
→ 总固定开销                          ~1.6 GB

实际可分配给"比赛容器"              ≈ 14.4 GB  
(以 16GB 物理机为例)
按 128MB/容器计算:→ ~112 个容器
按 256MB/容器计算:→ ~56 个容器

5.2 核心对比表

对比维度 直接 Docker(方案A) k3s –docker 多VM(方案B) k3s 劣势
最少物理内存 8 GB 可勉强运行 16 GB 最低(2 VM) k3s 高 ~2x
推荐物理内存 16 GB 32 GB k3s 高 ~2x
每 GB 可用给容器的效率 ~88%(1.6/16 开销) ~79%(6.7/32 开销) k3s 低 9pp
基础固定开销 ~1.6 GB ~6.7 GB(含 3个OS+3个Docker+etcd) k3s 多 ~5 GB
镜像拉取效率 单份存储,一次 pull 每 VM 一份,重复 pull k3s 每 VM 拉一次
容器调度灵活性 docker-compose 手动 k8s 原生调度 ✅ k3s 优势
资源隔离 OS 级 VM 级硬隔离 ✅ k3s 优势
运维复杂度 低(一条 docker compose up) 高(多 VM、k3s 管理、网络打通) k3s 显著更高
比赛动态启停 需自己写脚本 k8s Deployment 原生支持 ✅ k3s 优势

5.3 “浪费的”内存定量分析

以 32GB 宿主机、2 节点方案为例:

直接 Docker 方案可用比赛内存:      ~29 GB(扣除~3GB 总开销)
k3s 2节点方案可用比赛内存:         ~25 GB(扣除~7GB 总开销)

差异:~4GB 纯粹浪费在:
  - 多跑 1 个完整 OS(~384MB)
  - 多跑 1 个 Docker daemon(~128MB)
  - 多跑 1 个 cri-dockerd(~48MB)
  - k3s server + etcd + agent 的重复进程(~500MB)
  - Proxmox 的 VM 管理开销、内存气球膨胀(~200MB)
  - VM 内无法精确超分的内存预留缓冲(~500MB)
  - 其他...

→ 4GB × 100 队 = 每队浪费了 40MB 的潜在容器空间
→ 按 128MB/容器 = 约 32 个容器的容量被浪费

6. 结论与最终建议

如果一定要用这个方案

最低配置(能跑起来):

  • 宿主机:6 核 CPU、16 GB 内存、120 GB SSD
  • VM 方案:2 节点(1 hybrid + 1 worker)
  • 可用比赛内存:~10 GB(约 80 个 128MB 容器)
  • 适合 < 50 队、< 15 题的极小型比赛

推荐配置(200队30题):

  • 宿主机:8-12 核 CPU、32 GB 内存、512 GB NVMe
  • VM 方案:2 节点(推荐方案二)
  • 可用比赛内存:~25 GB(约 200 个 128MB 容器,或 100 个 256MB 容器)
  • 这个容量可以覆盖 200 队 × 30 题的典型需求

但是——认真建议

根据来源资料(GZCTF 官方文档)的明确指引:

“对于小于 200 支队伍、30 道题目的私有内网比赛,可以直接使用 Docker 部署,无需使用 k8s。”

这个建议是有道理的。数据显示:

  • 直接 Docker 方案在 16GB 宿主机上提供 ≈ 14.4GB 可用容器内存,足够支撑 100+ 个 128MB 容器
  • k3s 方案在 32GB 宿主机上提供 ≈ 25GB 可用容器内存,多了 10GB 但多花了 16GB 物理内存(翻倍) 去换取 k8s 的调度灵活性
  • 多出的内存(16GB → 32GB)中只有约 10GB 实际转化为可用容器容量,6GB 被额外的基础设施吞噬了

如果是社团比赛场景,真正的理性选择是:

  1. 单台物理机 + 直接 Docker → 投入产出比最高
  2. 如果一定要练手 k8s,在物理机上跑一个单节点的 k3s(不拆多 VM),用 containerd 而非 Docker 作为运行时,资源利用率最高
  3. 多 VM 拆 k3s + --docker 是“三个坏选择叠在一起”——多 VM 浪费资源、--docker 额外开销、单机跑集群没有 HA 收益

数据总结一览

指标 直接 Docker(16GB) k3s –docker 多VM(32GB) 差异
总物理内存 16 GB 32 GB +16 GB
基础设施开销 ~1.6 GB ~6.7 GB +5.1 GB
可用比赛内存 ~14.4 GB ~25.3 GB +10.9 GB
效率比 88% 79% -9pp
支持 128MB 容器数 ~112 个 ~200 个 +88 个
支持 256MB 容器数 ~56 个 ~100 个 +44 个
运维复杂度 低 高 不推荐
适合场景 私有内网赛 练手/学习 -

原始笔记:cloud/gz-ctf/资源配置评估.md