单台 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 社群反馈):
- cri-dockerd 在 k3s 下的 SIGTERM 传播问题:当 k3s agent 重启时,cri-dockerd 可能滞后退出,导致孤儿容器
- Docker 的 iptables 与 k3s 的 kube-proxy iptables 规则冲突:Docker 也会写 iptables NAT 规则,高并发创建/删除容器时偶发规则残留在
DOCKER链 - 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 被额外的基础设施吞噬了
如果是社团比赛场景,真正的理性选择是:
- 单台物理机 + 直接 Docker → 投入产出比最高
- 如果一定要练手 k8s,在物理机上跑一个单节点的 k3s(不拆多 VM),用 containerd 而非 Docker 作为运行时,资源利用率最高
- 多 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