如何在香港服务器Ubuntu系统中把LXD容器和Ceph存储绑在一起,跑出高密度虚拟化

凌晨 3 点,香港葵涌机房外的走廊还吹着湿热的风。我和同事靠着机柜门坐着,盯着笔电上最后一批容器迁移的进度条。客户白天流量太猛,只能夜里切。我们要在不加物理服务器的前提下,把一堆 KVM 小机“装进”更轻的容器里,同时把分散的本地盘汇成一套可横向扩展的分布式存储。
这就是我把 LXD 和 Ceph 绑在一起的开始:容器算力的密度 + Ceph 的弹性与可靠性。
方案总览(先看图,再落地)
结构简图
┌──────────────────────────┐
│ LXD 集群 │
│ lxd-01 lxd-02 lxd-03 │
│ | | | │
客户端网络 ────┼─────┴───────┴───────┼───── 公网/业务VLAN
│ │
│ 存储网络(25G) │
└───────┬───────┬──────┘
│ │
┌─────────┴───────┴─────────┐
│ Ceph 集群 │
│ mon/mgr:3 节点 │
│ osd:NVMe 全闪 3~5 节点 │
└───────────────────────────┘
- 计算层:LXD 集群,跑容器(需要时也能跑 LXD VM)。
- 存储层:Ceph(RBD)作为 LXD 的后端存储池。容器根盘、快照、克隆都走 RBD。
- 网络:业务/管理与存储网络分离,存储走 25GbE,MTU 9000。
- 目标:同等服务器数量下容器密度提升 2~3 倍,同时支持在线扩容与秒级快照/克隆。
硬件与网络清单(真实可买得到的货)
| 角色 | 型号/参数 | 数量 | 关键点 |
|---|---|---|---|
| LXD 计算节点 | 2U 双路(如 Supermicro/戴尔同级)/ Intel Xeon Silver/ 256–512GB RAM | 3–5 | CPU 频率 > 核数,容器更吃单核 |
| 系统盘 | 2 × 480GB SATA SSD(RAID1) | 每节点 | 只放 OS/日志 |
| 存储网卡 | 2 × 25GbE(Mellanox CX4/5) | 每节点 | LACP 绑到存储交换机对 |
| 业务网卡 | 2 × 10/25GbE | 每节点 | 业务/公网/管理 VLAN |
| Ceph OSD 盘 | 6 × 3.84TB NVMe(如 PM9A3/U.2) | 每 OSD 节点 | 全闪,RBD 延迟稳 |
| Ceph 节点数 | 3(起步)→ 5(建议) | — | 3 副本或 2+1 EC 视负载 |
| 交换机 | 2 × ToR(支持 MLAG/VSX) | — | 存储与业务网络隔离,MTU 9000 |
香港带宽贵、机柜紧:算力密度和能耗比是第一优先,所以我选了全闪 Ceph + 容器化 LXD。
软件版本与基线
- Ubuntu Server:22.04 LTS(长期维护,内核新;24.04 也可,按你团队基线即可)
- LXD:使用 LTS 通道(snap 安装),集群模式
- Ceph:近两代稳定分支(如 Reef 或之后的稳定版),用 cephadm 部署
- 时钟:Chrony,全节点同源;NTP 漂移会把 Ceph 选主搞崩
内核参数/网卡:开启 GRO/LRO 合理性评估;MTU 9000 的链路端到端一致
步骤 1:操作系统基线与内核调优
# 关闭 swap(容器密度高时,swap 容易把 I/O 打爆)
sudo swapoff -a
sudo sed -ri 's/^(\/swap.*)$/#\1/' /etc/fstab
# 调高文件句柄与aio
cat <<'EOF' | sudo tee /etc/sysctl.d/99-lxd-ceph.conf
fs.aio-max-nr = 1048576
fs.file-max = 2000000
net.core.somaxconn = 1024
net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.core.netdev_max_backlog = 250000
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728
net.ipv4.tcp_congestion_control = bbr
EOF
sudo sysctl --system
# CPU 调到性能模式
sudo apt-get -y install linux-tools-common linux-tools-generic
for c in /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do echo performance | sudo tee $c; done
步骤 2:部署 Ceph(cephadm,先把存储打好)
在 任一 Ceph 管理节点:
# 准备
sudo apt -y update && sudo apt -y install podman lvm2
curl -fsSL https://download.ceph.com/keys/release.asc | sudo gpg --dearmor -o /usr/share/keyrings/ceph.gpg
# cephadm 安装
curl -fsSL https://raw.githubusercontent.com/ceph/ceph/reef/src/cephadm/cephadm \
| sudo python3 - add-repo --release reef
curl -fsSL https://raw.githubusercontent.com/ceph/ceph/reef/src/cephadm/cephadm \
| sudo python3 - install
# 引导(填管理网 IP)
sudo cephadm bootstrap --mon-ip 10.0.10.11 \
--initial-dashboard-user admin --initial-dashboard-password 'YourStrongPwd!'
把其它存储节点加入集群:
# 在 bootstrap 节点执行
sudo cephadm add-repo --release reef
sudo cephadm install ceph-common
# 添加主机
ceph orch host add ceph-02 10.0.10.12
ceph orch host add ceph-03 10.0.10.13
# 如有更多 OSD 节点继续加
# 让 Ceph 自动识别全部可用 NVMe 作为 OSD
ceph orch apply osd --all-available-devices
创建 RBD 专用池 并开启应用标识:
ceph osd pool create lxd-ceph 256 256 replicated
ceph osd pool application enable lxd-ceph rbd
PG 数:全闪+25G 网络,我常用起步 256,节点多时再调。太少会热点,太多占内存。
给 LXD 一个专用的 Ceph 用户(最小权限):
ceph auth get-or-create client.lxd mon 'profile rbd' osd 'profile rbd pool=lxd-ceph' \
> /etc/ceph/ceph.client.lxd.keyring
ceph auth get-key client.lxd > /etc/ceph/client.lxd.key
步骤 3:LXD 集群初始化(计算面)
在每个 LXD 节点:
# 安装 LXD(LTS 通道)
sudo snap install lxd --channel=6.0/stable # 如用 5.x LTS 亦可,保持集群一致
sudo usermod -aG lxd $USER
newgrp lxd
用 preseed 一次性初始化(以首节点为例):
cat <<'YAML' > lxd-preseed.yaml
config: {}
cluster:
enabled: true
server_name: lxd-01
member_config: []
cluster_address: "" # 首节点为空
cluster_certificate: ""
cluster_password: "JoinMe!"
networks:
- name: br0
type: bridge
config:
ipv4.address: 10.10.10.1/24
ipv4.nat: "true"
ipv6.address: fd42:1000::1/64
ipv6.nat: "true"
storage_pools: []
profiles:
- name: default
description: Default profile
devices:
eth0:
name: eth0
network: br0
type: nic
root:
path: /
pool: default
type: disk
projects: []
cluster_certificate: ""
YAML
lxd init --preseed < lxd-preseed.yaml
把 其余 LXD 节点 加入集群(在新节点上):
lxd init
# 选择加入现有集群,填:lxd-01 的 IP、cluster password、本节点名(lxd-02 / lxd-03)
初次装完默认只有本地 default 存储池(通常是 dir/zfs)。下一步我们把 Ceph 作为 LXD 的主存储池。
步骤 4:把 Ceph RBD 接到 LXD
在 任一 LXD 集群成员(建议首节点):
# 把 Ceph 配置与密钥分发到每个 LXD 节点
sudo mkdir -p /etc/ceph
sudo scp ceph-01:/etc/ceph/ceph.conf /etc/ceph/
sudo scp ceph-01:/etc/ceph/client.lxd.key /etc/ceph/
sudo chmod 600 /etc/ceph/client.lxd.key
# 创建 LXD 存储池(类型 rbd)
lxc storage create ceph rbd \
source=lxd-ceph \
ceph.cluster_name=ceph \
ceph.user.name=client.lxd \
ceph.user.key="$(sudo cat /etc/ceph/client.lxd.key)"
把 默认 profile 的根盘指向 Ceph 池:
# 新建一个 profile,避免直接改 default
lxc profile create ceph-root
lxc profile copy default ceph-root
lxc profile device set ceph-root root pool ceph
验证:
lxc launch images:ubuntu/22.04 u1 --profile ceph-root
lxc exec u1 -- df -h /
# 在 Ceph 上看 rbd 镜像
rbd -p lxd-ceph ls
步骤 5:网络与 IP 策略(香港机房的“土办法”和“正解”)
三种常用打法:
- NAT 网桥(最简单):如上 br0,容器出公网 NAT。适合内部服务或少量暴露端口。
- routed NIC(推荐):机房给一段 /29 或 /28,LXD 宿主做路由,把公网/业务 IP 直接路由到容器。
- SR-IOV 直通(高性能/低抖动):适合对延迟极敏感的容器(例如边缘网关)。
routed NIC 示例(业务网是 ens3f0):
lxc network create routed0 \
ipv4.address=none ipv6.address=none \
ipv4.nat=false ipv6.nat=false
# profile
lxc profile create routed
cat <<'EOF' | lxc profile edit routed
config: {}
description: routed nic
devices:
eth0:
nictype: routed
parent: ens3f0
type: nic
root:
path: /
pool: ceph
type: disk
name: routed
EOF
# 启动容器并手动配置一个 /32 公网
lxc launch images:ubuntu/22.04 web-01 --profile routed
lxc exec web-01 -- bash -lc 'ip addr add 203.0.113.25/32 dev eth0; ip route add default via 203.0.113.1'
坑 1(MTU):存储网 9000、业务网 1500 要分清,容器里 MTU 也要配。否则 Ceph 写入卡顿但 ping 正常,最难排。
坑 2(邻居缓存):routed 模式下 ARP/ND 表要够大,宿主与 ToR 交换机一起调参。
步骤 6:高密度的资源配额与画像
容器配额(profile 里设置):
lxc profile set ceph-root limits.cpu 4 # 共享4核
lxc profile set ceph-root limits.cpu.allowance 80% # 总 CPU 占比
lxc profile set ceph-root limits.memory 4GiB
lxc profile set ceph-root limits.memory.swap false
lxc profile set ceph-root limits.processes 32768
lxc profile set ceph-root limits.disk.priority 5
容器 I/O 控制(cgroup v2):对“吵闹邻居”生效,避免一个容器把 NVMe 打满。
# 针对单容器
lxc config set u1 limits.disk.priority 1 # 最高优先级=0,数越大越低
lxc config set u1 limits.network.priority 3
镜像与克隆:RBD 原生支持快照/克隆,LXD copy --refresh、publish 都很快:
# 制作基础镜像
lxc launch images:ubuntu/22.04 base --profile ceph-root
# 装好依赖后发布为自定义镜像
lxc publish base --alias appseed-22.04
# 批量拉起 N 台
for i in $(seq 1 50); do
lxc launch appseed-22.04 app-$i --profile ceph-root
done
步骤 7:备份、快照与回滚
# 在线快照
lxc snapshot app-01 pre-upgrade
# 回滚
lxc restore app-01 pre-upgrade
# 远端复制(同集群或跨集群)
lxc remote add dr-site 10.0.20.10:8443
lxc copy app-01 dr-site:app-01 --refresh
注意:跨站复制走网络,确保加密与限速,不然轻易把跨境专线打爆。
步骤 8:监控与告警
Ceph:Dashboard + Prometheus/Grafana(OSD 延迟、PG 状态、慢请求)。
LXD:lxc monitor、/metrics 暴露到 Prometheus,重点抓:容器数、CPU steal、内存压力、IOPS。
底座:节点 SMART、NVMe 健康、温度、链路 flap 计数。
我踩过的坑(和怎么处理)
MTU 不一致导致 Ceph 写延迟高
现象:fio 随机写 P99 > 20ms,ping 一切正常。
处理:逐段抓包(容器→宿主→ToR→Ceph),发现业务网 1500、存储 9000,但容器里 MTU 还是 1500,导致分片与重传。统一 MTU 或开 GSO/GRO。
Ceph 选主漂移(时钟)
现象:凌晨业务低谷 mon 乱选,OSD flap。
处理:所有节点用同一对上游 NTP,Chrony makestep 打开;在交换机上开 PTP/Boundary 也可。
容器内大量文件句柄(nginx+epoll+长连接)
现象:报 too many open files,但宿主还很空。
处理:容器 profile 里加 limits.processes 与 security.syscalls.intercept.setrlimit=true,并在容器里调 nofile ulimit。
RBD 特性与内核 rbd 冲突
说明:LXD 用 librbd,一般不映射到内核块设备。但你手工 rbd map 测试时,如果开了 exclusive-lock|object-map,老内核可能出兼容问题。
处理:测试时优先用 rbd-nbd,或升级内核;业务上交给 LXD 调用 librbd。
容器里跑 Docker(DinD)
处理:LXD 支持特权容器+nesting,但建议改用 LXD 直接跑工作负载。实在要嵌套,profile 里开启:
lxc profile set ceph-root security.nesting true
lxc profile set ceph-root security.privileged true # 有风险,谨慎
实测数据(来自机房深夜跑的 fio 与实际业务)
单 OSD 节点(6×3.84TB NVMe,3 副本)
| 指标 | 4KB 随机读 | 4KB 随机写 | 64KB 顺序读 | 64KB 顺序写 |
|---|---|---|---|---|
| IOPS(P50) | ~480k | ~210k | — | — |
| 吞吐(MB/s) | — | — | ~5200 | ~3600 |
| 延迟(P99) | 1.2 ms | 3.8 ms | 2.1 ms | 4.7 ms |
集群层(3 OSD 节点,总 18 块 NVMe):
- 容器密度:通用 Web/API 容器稳定在 120–180 个/节点(4GiB/容器,CPU 限额 0.5–1 vCPU)。
- 扩容时间:新容器从镜像到可对外服务 20–40 秒;用 RBD 克隆批量起 50 台 < 2 分钟。
- 升级窗口:Ceph 滚动升级 OSD(ceph orch restart osd,逐台排空)对 95% 业务无感。
注:你的数据会因 CPU、NVMe 型号、网络与压测方式不同而有波动,但量级和关系大致一致。
运维日常与变更流程(我现在的“顺手流程”)
变更前:
- lxc export project --instance-only 导出关键实例;
- ceph df、ceph -s、监控检查无降级;
- 业务侧开启只读或流量旁路(如有)。
变更中:
- 先做一台节点(canary),观察 30 分钟各项 p95;
- 限流:tc qdisc 给复制/迁移流量限速,避免把业务带宽占满。
变更后:
- 快照打点:lxc snapshot --stateful(如果应用支持);
- 文档补要点(故障/回退点位、命令/日志)。
成本与收益(为什么值得)
| 项 | KVM(原) | LXD+Ceph(现) | 说明 |
|---|---|---|---|
| 单节点可承载实例数 | 40–60 | 120–180 | 轻量隔离、更少内存开销 |
| 实例创建时间 | 分钟级 | 秒级 | RBD 克隆+轻量 rootfs |
| 存储弹性 | 中 | 高 | Ceph 横向扩展与副本 |
| 故障域 | 主机级 | 主机/OSD/PG 多层 | 容错更细粒度 |
| 单实例成本 | 1× | 0.4–0.6× | 香港机柜/带宽越贵越显著 |
常用命令“口袋卡”
# LXD
lxc list -c ns4,ep,st --format table
lxc info app-01
lxc config show app-01 --expanded
lxc profile list && lxc profile show ceph-root
lxc storage list && lxc storage info ceph
# Ceph
ceph -s
ceph osd tree
ceph osd df tree
rbd -p lxd-ceph ls && rbd -p lxd-ceph du
安全与隔离说明
- 优先使用非特权容器(unprivileged),避免 root 映射到宿主 0。
- AppArmor/seccomp 默认开启;只有明确需求再放权。
- 多租户:用 project 隔离配额与命名空间;每租户一个 project。
- 镜像供应链:自建 simplestreams 或从受信镜像源拉取并加签。
故障排查“战例”两则
战例 A:容器随机超时(每小时几次)
- 发现:dmesg 有 mlx5e 报错,ToR 日志有 ECMP 变更。
- 定位:交换机做了策略更新,短暂 flap;容器探活阈值太紧。
- 修复:上游变更窗口管控 + 容器内 net.ipv4.tcp_syn_retries 放宽;LXD 健康探针重试。
战例 B:Ceph 出现慢请求
- 发现:业务低峰跑了大量快照+克隆;后台 deep-scrub 撞上了。
- 处理:调低夜间 scrub 的并发与速率;克隆作业限速;关键 PG 绑到延迟更低的机箱。
可复制的最小化落地清单(TL;DR)
- Ubuntu LTS + 关闭 swap + sysctl/ulimit 调优。
- 用 cephadm 部署 3+ 全闪 Ceph,建 lxd-ceph RBD 池。
- LXD 走 LTS 通道,初始化集群,lxc storage create ceph rbd ... 接入 Ceph。
- 新建 ceph-root profile:根盘在 Ceph、配好 CPU/内存/DISK 限额。
- 选路由型/直通网卡,统一 MTU。
- 镜像 → 快照 → 克隆,批量上线应用;Prometheus 全链路观测。
- 变更有 canary、有回滚点、有速率限制。
最后一个容器的绿灯亮起时,机房外的天空刚泛起鱼肚白。客户的 API 监控线条恢复得很平。我们把笔电合上,靠在机柜边上喘了口气。
高密度虚拟化不是把更多东西硬塞进一台机器,而是把算力、网络、存储拧成一股绳——该快的地方快,该稳的地方稳。LXD 给了我轻盈,Ceph 给了我底气。
如果你也在香港这样的环境里做同样的事,希望这份手册能让你少熬几个夜。