虚拟化技术
课程概述
本教程深入讲解操作系统虚拟化技术,从虚拟机到容器,从Hypervisor到cgroup/namespace,帮助你全面理解现代云计算和容器化技术的底层原理。
学习目标:
- 理解虚拟化的类型与演进历史
- 掌握KVM/QEMU架构与原理
- 深入了解Hypervisor的实现机制
- 学习Docker容器技术的内核基础
- 掌握cgroup资源限制与namespace隔离
- 理解虚拟化的性能优化技术
1. 虚拟化基础
1.1 虚拟化类型
┌─────────────────────────────────────────────────────────────┐
│ 虚拟化技术分类 │
└─────────────────────────────────────────────────────────────┘
按虚拟化层次分类:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 1. 硬件虚拟化(Full Virtualization) │
│ ┌─────────────────────────────────────────────────┐ │
│ │ VM1 VM2 VM3 │ │
│ │ ┌──────┐ ┌──────┐ ┌──────┐ │ │
│ │ │Guest │ │Guest │ │Guest │ 用户态 │ │
│ │ │ OS │ │ OS │ │ OS │ │ │
│ │ └───┬──┘ └───┬──┘ └───┬──┘ │ │
│ │ │ │ │ │ │
│ │ ════╪═════════╪═════════╪═══════════════════ │ │
│ │ │ │ │ 内核态 │ │
│ │ └─────────┴─────────┘ │ │
│ │ │ │ │
│ │ ┌───────▼────────┐ │ │
│ │ │ Hypervisor │ (KVM/Xen/VMware) │ │
│ │ │ (虚拟机监视器) │ │ │
│ │ └───────┬────────┘ │ │
│ │ │ │ │
│ │ ┌───────▼────────┐ │ │
│ │ │ Host OS │ │ │
│ │ └───────┬────────┘ │ │
│ │ │ │ │
│ │ ┌───────▼────────┐ │ │
│ │ │ 硬件(x86/ARM) │ │ │
│ │ └────────────────┘ │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ 2. 操作系统虚拟化(OS-level Virtualization / Container) │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Container1 Container2 Container3 │ │
│ │ ┌──────┐ ┌──────┐ ┌──────┐ 用户态 │ │
│ │ │ App1 │ │ App2 │ │ App3 │ │ │
│ │ │ Libs │ │ Libs │ │ Libs │ │ │
│ │ └───┬──┘ └───┬──┘ └───┬──┘ │ │
│ │ │ │ │ │ │
│ │ ════╪═════════╪═════════╪═══════════════════ │ │
│ │ │ │ │ 内核态 │ │
│ │ └─────────┴─────────┘ │ │
│ │ │ │ │
│ │ ┌───────▼────────┐ │ │
│ │ │ Container │ (Docker/LXC) │ │
│ │ │ Runtime │ │ │
│ │ └───────┬────────┘ │ │
│ │ │ │ │
│ │ ┌───────▼────────┐ │ │
│ │ │ Host OS │ (共享内核) │ │
│ │ │ Linux Kernel │ │ │
│ │ └───────┬────────┘ │ │
│ │ │ │ │
│ │ ┌───────▼────────┐ │ │
│ │ │ 硬件 │ │ │
│ │ └────────────────┘ │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ 3. 半虚拟化(Paravirtualization) │
│ • Guest OS知道自己被虚拟化 │
│ • 使用Hypercall代替特权指令 │
│ • 性能更好,但需要修改Guest OS │
│ • 例: Xen PV, Hyper-V Enlightenments │
└─────────────────────────────────────────────────────────────┘
性能对比:
┌──────────────┬────────┬────────┬────────┬──────────────┐
│ 类型 │ 隔离性 │ 性能 │ 启动速度│ 资源开销 │
├──────────────┼────────┼────────┼────────┼──────────────┤
│ 全虚拟化 │ ★★★★★ │ ★★☆ │ 分钟级 │ 大(完整OS) │
│ 半虚拟化 │ ★★★★ │ ★★★★ │ 分钟级 │ 较大 │
│ 容器 │ ★★★ │ ★★★★★ │ 秒级 │ 小(共享内核) │
└──────────────┴────────┴────────┴────────┴──────────────┘1.2 CPU虚拟化
┌─────────────────────────────────────────────────────────────┐
│ CPU虚拟化技术演进 │
└─────────────────────────────────────────────────────────────┘
x86特权级:
┌────────────────────────────────────────────────────┐
│ Ring 0 (最高特权) │
│ ┌──────────────┐ │
│ │ 内核 │ │
│ └──────────────┘ │
│ Ring 1, 2 (很少使用) │
│ ┌──────────────┐ │
│ │ │ │
│ └──────────────┘ │
│ Ring 3 (用户态) │
│ ┌──────────────┐ │
│ │ 应用程序 │ │
│ └──────────────┘ │
└────────────────────────────────────────────────────┘
虚拟化挑战:
Guest OS期望运行在Ring 0,但实际运行在Ring 3
→ 敏感指令无法执行,导致Guest OS崩溃
解决方案演进:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 1. 软件模拟(Binary Translation) │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Guest OS执行特权指令 │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌──────────────┐ │ │
│ │ │ Trap to VMM │ (陷入Hypervisor) │ │
│ │ └──────┬───────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌──────────────┐ │ │
│ │ │ 二进制翻译 │ (将特权指令翻译成安全指令) │ │
│ │ └──────┬───────┘ │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌──────────────┐ │ │
│ │ │ 执行翻译后指令│ │ │
│ │ └──────────────┘ │ │
│ │ │ │
│ │ 例: VMware Workstation早期版本 │ │
│ │ 缺点: 性能损耗大(10-20%) │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ 2. 硬件辅助虚拟化(Hardware-assisted Virtualization) │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Intel VT-x / AMD-V │ │
│ │ │ │
│ │ 新增CPU模式: │ │
│ │ • VMX Root Mode (Hypervisor运行) │ │
│ │ • VMX Non-Root Mode (Guest OS运行) │ │
│ │ │ │
│ │ VMCS (Virtual Machine Control Structure) │ │
│ │ ┌──────────────────────────────────────────┐ │ │
│ │ │ Guest State (虚拟CPU状态) │ │ │
│ │ │ • CS, EIP, CR0, CR3... │ │ │
│ │ │ │ │ │
│ │ │ Host State (宿主CPU状态) │ │ │
│ │ │ • 返回地址 │ │ │
│ │ │ │ │ │
│ │ │ VM-Execution Controls │ │ │
│ │ │ • 哪些指令会导致VM Exit │ │ │
│ │ │ │ │ │
│ │ │ VM-Exit Information │ │ │
│ │ │ • 退出原因, 错误码 │ │ │
│ │ └──────────────────────────────────────────┘ │ │
│ │ │ │
│ │ VM Entry: Host → Guest │ │
│ │ VM Exit: Guest → Host (特权指令/中断) │ │
│ │ │ │
│ │ 性能: 接近原生(1-5%损耗) │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ 3. VCPU调度 │
│ ┌─────────────────────────────────────────────────┐ │
│ │ 物理CPU: 4核 │ │
│ │ ┌─────┬─────┬─────┬─────┐ │ │
│ │ │ CPU0│ CPU1│ CPU2│ CPU3│ │ │
│ │ └──┬──┴──┬──┴──┬──┴──┬──┘ │ │
│ │ │ │ │ │ │ │
│ │ │ │ │ │ 时间片轮转 │ │
│ │ │ │ │ │ │ │
│ │ ┌──▼─────▼─────▼─────▼──┐ │ │
│ │ │ Hypervisor Scheduler │ │ │
│ │ └──┬─────┬─────┬─────┬──┘ │ │
│ │ │ │ │ │ │ │
│ │ ▼ ▼ ▼ ▼ │ │
│ │ VM1 VM2 VM3 VM4 │ │
│ │ 2VCPU 1VCPU 4VCPU 2VCPU │ │
│ │ │ │
│ │ 超配(Overcommit): VCPU总数 > 物理CPU数 │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘2. KVM虚拟化
2.1 KVM架构
┌─────────────────────────────────────────────────────────────┐
│ KVM (Kernel-based Virtual Machine) │
└─────────────────────────────────────────────────────────────┘
KVM架构:
┌─────────────────────────────────────────────────────────────┐
│ 用户空间 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ QEMU进程 │ │
│ │ ┌────────────────────────────────────────────────┐ │ │
│ │ │ 虚拟机 │ │ │
│ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │
│ │ │ │ Guest │ │ Guest │ │ Guest │ │ │ │
│ │ │ │ CPU │ │ Memory │ │ I/O │ │ │ │
│ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ │ │
│ │ │ │ │ │ │ │ │
│ │ └───────┼─────────────┼─────────────┼───────────┘ │ │
│ │ │ │ │ │ │
│ │ ┌───────▼─────────────▼─────────────▼───────────┐ │ │
│ │ │ QEMU Device Model │ │ │
│ │ │ • 虚拟网卡(virtio-net) │ │ │
│ │ │ • 虚拟硬盘(virtio-blk) │ │ │
│ │ │ • VGA显卡 │ │ │
│ │ └────────────────┬──────────────────────────────┘ │ │
│ │ │ │ │
│ │ │ ioctl(/dev/kvm) │ │
│ └───────────────────┼──────────────────────────────────┘ │
│ │ │
│ ════════════════════▼══════════════════════════════════ │
│ │
│ 内核空间 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ KVM模块 (kvm.ko, kvm-intel.ko/kvm-amd.ko) │ │
│ │ ┌────────────────────────────────────────────────┐ │ │
│ │ │ VM结构体 │ │ │
│ │ │ ┌──────────────────────────────────────────┐ │ │ │
│ │ │ │ VCPU 0 │ │ │ │
│ │ │ │ • VMCS (虚拟CPU状态) │ │ │ │
│ │ │ │ • 寄存器 │ │ │ │
│ │ │ │ • GDT/IDT │ │ │ │
│ │ │ └──────────────────────────────────────────┘ │ │ │
│ │ │ ┌──────────────────────────────────────────┐ │ │ │
│ │ │ │ VCPU 1 │ │ │ │
│ │ │ └──────────────────────────────────────────┘ │ │ │
│ │ │ │ │ │
│ │ │ ┌──────────────────────────────────────────┐ │ │ │
│ │ │ │ Guest Physical Memory │ │ │ │
│ │ │ │ (GPA → HPA映射, EPT/NPT页表) │ │ │ │
│ │ │ └──────────────────────────────────────────┘ │ │ │
│ │ └────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────▼──────────────────────────────────┐ │
│ │ Linux内核 │ │
│ │ • 进程调度 │ │
│ │ • 内存管理 │ │
│ │ • 设备驱动 │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │
│ ════════════════════▼══════════════════════════════════ │
│ │
│ 硬件层 │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Intel VT-x / AMD-V │ │
│ │ EPT (Extended Page Tables) │ │
│ │ APIC虚拟化 │ │
│ └──────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
KVM vs QEMU:
┌─────────────────────────────────────────────────────────────┐
│ KVM: │
│ • 内核模块 │
│ • 提供虚拟化能力(/dev/kvm) │
│ • 处理CPU/内存虚拟化 │
│ • 不能单独使用 │
│ │
│ QEMU: │
│ • 用户空间程序 │
│ • 设备模拟(网卡、硬盘、显卡等) │
│ • 可以纯软件模拟CPU(慢) │
│ • 可以使用KVM加速 │
│ │
│ KVM + QEMU = 完整的虚拟化解决方案 │
└─────────────────────────────────────────────────────────────┘2.2 内存虚拟化
┌─────────────────────────────────────────────────────────────┐
│ 内存虚拟化 - 三层地址转换 │
└─────────────────────────────────────────────────────────────┘
地址空间:
┌─────────────────────────────────────────────────────────────┐
│ │
│ Guest Virtual Address (GVA) │
│ ┌──────────────────────────────────────┐ │
│ │ Guest进程看到的虚拟地址 │ │
│ │ 例: 0x7fff1234 │ │
│ └────────────────┬─────────────────────┘ │
│ │ Guest页表(CR3) │
│ ▼ │
│ Guest Physical Address (GPA) │
│ ┌──────────────────────────────────────┐ │
│ │ Guest OS看到的"物理"地址 │ │
│ │ 例: 0x10000000 │ │
│ └────────────────┬─────────────────────┘ │
│ │ EPT/NPT页表 │
│ ▼ │
│ Host Physical Address (HPA) │
│ ┌──────────────────────────────────────┐ │
│ │ 真实的物理内存地址 │ │
│ │ 例: 0xA0000000 │ │
│ └──────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
影子页表(Shadow Page Table) - 传统方案:
┌─────────────────────────────────────────────────────────────┐
│ Guest页表 影子页表 物理内存 │
│ (GVA→GPA) (GVA→HPA) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ GVA: 0x0 │ │ GVA: 0x0 │ │ │ │
│ │ ↓ │ │ ↓ │ │ │ │
│ │ GPA:0x10 │─┐ │ HPA:0xA0 │───▶ │ HPA:0xA0 │ │
│ └──────────┘ │ └──────────┘ └──────────┘ │
│ │ │
│ │ VMM维护映射 │
│ │ (软件方式) │
│ ▼ │
│ ┌──────────┐ │
│ │GPA→HPA表 │ │
│ └──────────┘ │
│ │
│ 问题: │
│ • Guest页表变化时需要同步影子页表 │
│ • 开销大,每次TLB miss都要VMM介入 │
└─────────────────────────────────────────────────────────────┘
EPT/NPT(硬件辅助) - 现代方案:
┌─────────────────────────────────────────────────────────────┐
│ Guest页表 EPT页表 物理内存 │
│ (GVA→GPA) (GPA→HPA) │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ GVA: 0x0 │ │ GPA:0x10 │ │ │ │
│ │ ↓ │ │ ↓ │ │ │ │
│ │ GPA:0x10 │──▶ │ HPA:0xA0 │───▶ │ HPA:0xA0 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ │
│ │ │ │
│ │ MMU硬件自动完成两级转换 │
│ └──────────────────┘ │
│ │
│ 优点: │
│ • 硬件支持,无需VMM介入 │
│ • 性能接近原生 │
│ • Guest页表变化无需通知VMM │
└─────────────────────────────────────────────────────────────┘
大页支持(Huge Pages):
┌─────────────────────────────────────────────────────────────┐
│ 普通4KB页: 大页2MB/1GB: │
│ ┌────────────────┐ ┌────────────────┐ │
│ │ 页表层级: 4级 │ │ 页表层级: 减少 │ │
│ │ TLB条目: 多 │ │ TLB条目: 少 │ │
│ │ TLB miss: 频繁 │ │ TLB miss: 减少 │ │
│ └────────────────┘ └────────────────┘ │
│ │
│ 配置大页: │
│ echo 1024 > /proc/sys/vm/nr_hugepages │
│ 启动VM: -mem-path /dev/hugepages -mem-prealloc │
│ │
│ 性能提升: 10-30% (内存密集型应用) │
└─────────────────────────────────────────────────────────────┘2.3 I/O虚拟化
┌─────────────────────────────────────────────────────────────┐
│ I/O虚拟化技术 │
└─────────────────────────────────────────────────────────────┘
1. 设备模拟(Device Emulation):
┌──────────────────────────────────────────────────────┐
│ Guest OS │
│ ┌────────────────────────┐ │
│ │ 驱动程序(e1000) │ │
│ └────────┬───────────────┘ │
│ │ MMIO/PIO访问 │
│ ▼ │
│ ════════════════════════════════════════════════ │
│ │ VM Exit │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ QEMU设备模型 │ │
│ │ • 模拟寄存器 │ │
│ │ • 模拟DMA │ │
│ │ • 转发给TAP设备 │ │
│ └────────┬───────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ Host网卡 │ │
│ └────────────────────────┘ │
│ │
│ 缺点: 每次I/O都VM Exit,性能差 │
└──────────────────────────────────────────────────────┘
2. 半虚拟化(Para-virtualization - VirtIO):
┌──────────────────────────────────────────────────────┐
│ Guest OS │
│ ┌────────────────────────┐ │
│ │ VirtIO驱动(前端) │ │
│ │ • 知道自己被虚拟化 │ │
│ │ • 使用高效协议 │ │
│ └────────┬───────────────┘ │
│ │ VirtQueue │
│ │ (共享内存环形队列) │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ VirtIO后端(QEMU) │ │
│ │ • 批量处理I/O请求 │ │
│ │ • 减少VM Exit │ │
│ └────────┬───────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ Host设备 │ │
│ └────────────────────────┘ │
│ │
│ VirtQueue结构: │
│ ┌──────────────────────────────────────────────┐ │
│ │ Descriptor Table (描述I/O请求) │ │
│ │ ┌────┬────┬────┬────┐ │ │
│ │ │ D0 │ D1 │ D2 │ D3 │ │ │
│ │ └────┴────┴────┴────┘ │ │
│ │ │ │
│ │ Available Ring (Guest提交请求) │ │
│ │ ┌───────────────────┐ │ │
│ │ │ idx: 2 │ │ │
│ │ │ ring: [0, 1, ...]│ │ │
│ │ └───────────────────┘ │ │
│ │ │ │
│ │ Used Ring (Host返回结果) │ │
│ │ ┌───────────────────┐ │ │
│ │ │ idx: 1 │ │ │
│ │ │ ring: [0, ...] │ │ │
│ │ └───────────────────┘ │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ 性能提升: 2-3倍 │
└──────────────────────────────────────────────────────┘
3. 直通(Device Passthrough - SR-IOV):
┌──────────────────────────────────────────────────────┐
│ Guest OS1 Guest OS2 │
│ ┌──────────┐ ┌──────────┐ │
│ │ VF驱动 │ │ VF驱动 │ │
│ └────┬─────┘ └────┬─────┘ │
│ │ 直接访问 │ 直接访问 │
│ ═════▼══════════════════════▼═════════════════ │
│ │
│ 物理网卡(支持SR-IOV) │
│ ┌────────────────────────────────────────────────┐ │
│ │ PF (Physical Function) │ │
│ │ ┌────────┐ │ │
│ │ │ 管理接口│ │ │
│ │ └────────┘ │ │
│ │ │ │
│ │ VF (Virtual Function) │ │
│ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ │
│ │ │ VF0 │ │ VF1 │ │ VF2 │ │ VF3 │ │ │
│ │ └──┬──┘ └──┬──┘ └──┬──┘ └──┬──┘ │ │
│ │ └────────┴────────┴────────┘ │ │
│ │ (独立的DMA/中断) │ │
│ └────────────────────────────────────────────────┘ │
│ │
│ 优点: │
│ • 接近原生性能(95%+) │
│ • 无VM Exit开销 │
│ • 硬件级隔离 │
│ │
│ 缺点: │
│ • 需要硬件支持 │
│ • VF数量有限 │
│ • 迁移困难 │
└──────────────────────────────────────────────────────┘3. 容器技术
3.1 Namespace隔离
┌─────────────────────────────────────────────────────────────┐
│ Linux Namespace - 6种隔离 │
└─────────────────────────────────────────────────────────────┘
1. PID Namespace (进程隔离)
┌─────────────────────────────────────────────────────┐
│ Host: Container: │
│ ┌──────────┐ ┌──────────┐ │
│ │ PID 1 │ │ PID 1 │ (容器内init) │
│ │ systemd │ │ /bin/sh │ │
│ ├──────────┤ ├──────────┤ │
│ │ PID 1234 │ │ PID 2 │ │
│ │ sshd │ │ nginx │ │
│ ├──────────┤ └──────────┘ │
│ │ PID 5678 │←─映射─▶ 容器看不到Host进程 │
│ │ dockerd │ │
│ └──────────┘ │
│ │
│ 实现: /proc/sys/kernel/ns/pid │
└─────────────────────────────────────────────────────┘
2. Network Namespace (网络隔离)
┌─────────────────────────────────────────────────────┐
│ Host网络栈 Container网络栈 │
│ ┌──────────┐ ┌──────────┐ │
│ │ eth0 │ │ eth0 │ (veth pair) │
│ │ 192.168. │ │ 172.17. │ │
│ │ 1.100 │ │ 0.2 │ │
│ ├──────────┤ ├──────────┤ │
│ │ 路由表 │ │ 路由表 │ (独立) │
│ ├──────────┤ ├──────────┤ │
│ │ iptables │ │ iptables │ (独立) │
│ └──────────┘ └──────────┘ │
│ │ │ │
│ └────bridge(docker0)─┘ │
└─────────────────────────────────────────────────────┘
3. Mount Namespace (文件系统隔离)
┌─────────────────────────────────────────────────────┐
│ Host: Container: │
│ / / │
│ ├── bin ├── bin │
│ ├── etc ├── etc (独立的) │
│ ├── var ├── var │
│ └── home └── home │
│ │
│ 容器看到的是chroot后的根文件系统 │
└─────────────────────────────────────────────────────┘
4. UTS Namespace (主机名隔离)
┌─────────────────────────────────────────────────────┐
│ Host: hostname = myhost │
│ Container: hostname = container123 │
│ │
│ 独立的hostname和domainname │
└─────────────────────────────────────────────────────┘
5. IPC Namespace (进程间通信隔离)
┌─────────────────────────────────────────────────────┐
│ 隔离: │
│ • 消息队列 (msgqueue) │
│ • 信号量 (semaphore) │
│ • 共享内存 (shared memory) │
│ │
│ 容器内进程无法访问Host的IPC对象 │
└─────────────────────────────────────────────────────┘
6. User Namespace (用户隔离)
┌─────────────────────────────────────────────────────┐
│ Host UID 1000 ←映射→ Container UID 0 (root) │
│ │
│ 容器内root权限,但在Host上是普通用户 │
│ 增强安全性 │
└─────────────────────────────────────────────────────┘
创建Namespace:
┌────────────────────────────────────────────────┐
│ /* C语言示例 */ │
│ #include <sched.h> │
│ #include <unistd.h> │
│ │
│ int child_func(void *arg) { │
│ /* 在新namespace中运行 */ │
│ execl("/bin/bash", "bash", NULL); │
│ return 0; │
│ } │
│ │
│ int main() { │
│ char stack[4096]; │
│ │
│ clone(child_func, │
│ stack + sizeof(stack), │
│ CLONE_NEWPID | /* PID namespace */ │
│ CLONE_NEWNET | /* Network ns */ │
│ CLONE_NEWNS | /* Mount ns */ │
│ CLONE_NEWUTS | /* UTS ns */ │
│ CLONE_NEWIPC | /* IPC ns */ │
│ CLONE_NEWUSER, /* User ns */ │
│ NULL); │
│ │
│ wait(NULL); │
│ return 0; │
│ } │
└────────────────────────────────────────────────┘3.2 Cgroup资源限制
┌─────────────────────────────────────────────────────────────┐
│ Cgroup (Control Groups) - 资源限制 │
└─────────────────────────────────────────────────────────────┘
Cgroup层级结构:
┌─────────────────────────────────────────────────────────────┐
│ /sys/fs/cgroup/ │
│ ├── cpu (CPU子系统) │
│ │ ├── docker/ │
│ │ │ ├── container1/ │
│ │ │ │ ├── cpu.shares (相对权重) │
│ │ │ │ ├── cpu.cfs_quota_us (配额) │
│ │ │ │ └── cpu.cfs_period_us (周期) │
│ │ │ └── container2/ │
│ │ └── system.slice/ │
│ │ │
│ ├── memory (内存子系统) │
│ │ ├── docker/ │
│ │ │ ├── container1/ │
│ │ │ │ ├── memory.limit_in_bytes (上限) │
│ │ │ │ ├── memory.usage_in_bytes (当前用量) │
│ │ │ │ └── memory.oom_control (OOM控制) │
│ │ │ └── container2/ │
│ │ │
│ ├── blkio (块设备I/O) │
│ │ ├── docker/ │
│ │ │ ├── container1/ │
│ │ │ │ ├── blkio.throttle.read_bps_device (读带宽) │
│ │ │ │ └── blkio.throttle.write_bps_device (写带宽) │
│ │ │
│ ├── pids (进程数限制) │
│ │ └── docker/container1/pids.max │
│ │ │
│ └── devices (设备访问控制) │
│ └── docker/container1/devices.list │
└─────────────────────────────────────────────────────────────┘
Cgroup子系统详解:
┌─────────────────────────────────────────────────────────────┐
│ │
│ 1. CPU子系统 │
│ ┌─────────────────────────────────────────────────┐ │
│ │ cpu.shares (权重) │ │
│ │ • 相对值,默认1024 │ │
│ │ • Container A: 1024, Container B: 512 │ │
│ │ • 在CPU竞争时,A获得2/3,B获得1/3 │ │
│ │ │ │
│ │ cpu.cfs_quota_us / cpu.cfs_period_us (绝对限制) │ │
│ │ • quota=50000, period=100000 │ │
│ │ • 50ms/100ms = 50% CPU │ │
│ │ • 等价于0.5个核 │ │
│ │ │ │
│ │ cpuset.cpus (CPU亲和性) │ │
│ │ • 指定在哪些CPU上运行 │ │
│ │ • 例: "0-3" 只能在CPU0-3上运行 │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ 2. Memory子系统 │
│ ┌─────────────────────────────────────────────────┐ │
│ │ memory.limit_in_bytes │ │
│ │ • 内存硬限制 │ │
│ │ • 超过限制触发OOM Killer │ │
│ │ • 例: 512MB = 536870912 bytes │ │
│ │ │ │
│ │ memory.soft_limit_in_bytes │ │
│ │ • 内存软限制 │ │
│ │ • 内存压力大时尝试回收 │ │
│ │ │ │
│ │ memory.swappiness │ │
│ │ • 控制swap倾向(0-100) │ │
│ │ • 0: 尽量不swap │ │
│ │ • 100: 积极swap │ │
│ │ │ │
│ │ memory.oom_control │ │
│ │ • 0: OOM时杀进程 │ │
│ │ • 1: OOM时暂停容器 │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ 3. BlkIO子系统 │
│ ┌─────────────────────────────────────────────────┐ │
│ │ blkio.weight (相对权重) │ │
│ │ • 范围10-1000,默认500 │ │
│ │ │ │
│ │ blkio.throttle.read_bps_device │ │
│ │ • 绝对读带宽限制 │ │
│ │ • 格式: "8:0 10485760" (10MB/s) │ │
│ │ │ │
│ │ blkio.throttle.read_iops_device │ │
│ │ • 读IOPS限制 │ │
│ │ • 格式: "8:0 1000" (1000 IOPS) │ │
│ └─────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
实战示例:bash
#!/bin/bash
# Cgroup资源限制示例
# 1. 创建cgroup
CGROUP_NAME="mycontainer"
CGROUP_PATH="/sys/fs/cgroup"
# CPU限制: 50%
mkdir -p $CGROUP_PATH/cpu/$CGROUP_NAME
echo 50000 > $CGROUP_PATH/cpu/$CGROUP_NAME/cpu.cfs_quota_us
echo 100000 > $CGROUP_PATH/cpu/$CGROUP_NAME/cpu.cfs_period_us
# 内存限制: 512MB
mkdir -p $CGROUP_PATH/memory/$CGROUP_NAME
echo 536870912 > $CGROUP_PATH/memory/$CGROUP_NAME/memory.limit_in_bytes
# BlkIO限制: 读10MB/s
mkdir -p $CGROUP_PATH/blkio/$CGROUP_NAME
echo "8:0 10485760" > $CGROUP_PATH/blkio/$CGROUP_NAME/blkio.throttle.read_bps_device
# 2. 将进程加入cgroup
PID=$$
echo $PID > $CGROUP_PATH/cpu/$CGROUP_NAME/cgroup.procs
echo $PID > $CGROUP_PATH/memory/$CGROUP_NAME/cgroup.procs
echo $PID > $CGROUP_PATH/blkio/$CGROUP_NAME/cgroup.procs
# 3. 查看资源使用
cat $CGROUP_PATH/cpu/$CGROUP_NAME/cpuacct.usage
cat $CGROUP_PATH/memory/$CGROUP_NAME/memory.usage_in_bytespython
#!/usr/bin/env python3
"""
使用Docker API设置资源限制
"""
import docker
client = docker.from_env()
# 创建容器并设置资源限制
container = client.containers.run(
"nginx:latest",
detach=True,
name="limited_nginx",
# CPU限制
cpu_period=100000, # 100ms
cpu_quota=50000, # 50ms (50% CPU)
cpuset_cpus="0-1", # 只用CPU0和CPU1
# 内存限制
mem_limit="512m", # 512MB硬限制
mem_reservation="256m", # 256MB软限制
memswap_limit="1g", # swap + memory = 1GB
# 块I/O限制
blkio_weight=500, # 权重
device_read_bps=[
{"Path": "/dev/sda", "Rate": 10485760} # 10MB/s
],
device_write_iops=[
{"Path": "/dev/sda", "Rate": 1000} # 1000 IOPS
],
# 进程数限制
pids_limit=100
)
print(f"Container created: {container.id}")
# 查看资源使用
stats = container.stats(stream=False)
print(f"CPU usage: {stats['cpu_stats']['cpu_usage']['total_usage']}")
print(f"Memory usage: {stats['memory_stats']['usage']}")4. 容器网络
4.1 Docker网络模式
┌─────────────────────────────────────────────────────────────┐
│ Docker网络模式 │
└─────────────────────────────────────────────────────────────┘
1. Bridge模式(默认)
┌──────────────────────────────────────────────────────┐
│ Host │
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │Container1│ │Container2│ │
│ │ eth0 │ │ eth0 │ │
│ │172.17.0.2│ │172.17.0.3│ │
│ └────┬─────┘ └────┬─────┘ │
│ │ veth pair │ veth pair │
│ │ │ │
│ ┌────▼─────────────────────▼─────┐ │
│ │ docker0 bridge │ │
│ │ 172.17.0.1 │ │
│ └────────────┬───────────────────┘ │
│ │ NAT │
│ │ │
│ ┌────────────▼───────────────────┐ │
│ │ eth0 (Host网卡) │ │
│ │ 192.168.1.100 │ │
│ └────────────────────────────────┘ │
│ │ │
└──────────────┼───────────────────────────────────────┘
│
Internet
特点:
• 容器有独立IP(docker0网段)
• 通过NAT访问外网
• 需要端口映射(-p 8080:80)
2. Host模式
┌──────────────────────────────────────────────────────┐
│ Host │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Container (共享Host网络栈) │ │
│ │ • 无独立IP │ │
│ │ • 直接使用Host端口 │ │
│ │ • 性能最好 │ │
│ └──────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────▼──────────────────────────┐ │
│ │ Host网络栈 │ │
│ │ eth0: 192.168.1.100 │ │
│ └────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
使用: docker run --network=host nginx
3. Container模式
┌──────────────────────────────────────────────────────┐
│ Container1 Container2 │
│ ┌──────────┐ (共享Container1网络) │
│ │ eth0 │ ┌──────────┐ │
│ │172.17.0.2│◀────────│ 共享网络 │ │
│ └──────────┘ └──────────┘ │
│ │
│ 使用场景: Kubernetes Pod (多容器共享网络) │
└──────────────────────────────────────────────────────┘
使用: docker run --network=container:container1 app2
4. None模式
┌──────────────────────────────────────────────────────┐
│ Container │
│ ┌────────────────────────────┐ │
│ │ 无网络配置 │ │
│ │ 只有lo接口 │ │
│ │ 用户自定义网络配置 │ │
│ └────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
使用: docker run --network=none myapp4.2 Overlay网络
┌─────────────────────────────────────────────────────────────┐
│ Overlay网络(跨主机通信) │
└─────────────────────────────────────────────────────────────┘
VXLAN隧道:
┌─────────────────────────────────────────────────────────────┐
│ Host1 (192.168.1.10) Host2 (192.168.1.20) │
│ │
│ Container A Container B │
│ ┌──────────┐ ┌──────────┐ │
│ │ 10.0.0.2 │ │ 10.0.0.3 │ │
│ └────┬─────┘ └────┬─────┘ │
│ │ │ │
│ ┌────▼────────┐ ┌────▼────────┐ │
│ │ veth pair │ │ veth pair │ │
│ └────┬────────┘ └────┬────────┘ │
│ │ │ │
│ ┌────▼────────┐ ┌────▼────────┐ │
│ │ br0 (bridge)│ │ br0 (bridge)│ │
│ └────┬────────┘ └────┬────────┘ │
│ │ │ │
│ ┌────▼────────┐ ┌────▼────────┐ │
│ │ vxlan0 │ │ vxlan0 │ │
│ │ VNI: 100 │ │ VNI: 100 │ │
│ └────┬────────┘ └────┬────────┘ │
│ │ VXLAN封装 │ VXLAN封装 │
│ │ │ │
│ ┌────▼────────┐ ┌────▼────────┐ │
│ │ eth0 │ │ eth0 │ │
│ │192.168.1.10 │◀──UDP 4789──▶│192.168.1.20 │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
VXLAN报文格式:
┌─────────────────────────────────────────────────────────────┐
│ Outer Ethernet Header │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Dst MAC | Src MAC | EtherType │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Outer IP Header │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Src IP: 192.168.1.10 | Dst IP: 192.168.1.20 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Outer UDP Header │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Src Port: random | Dst Port: 4789 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ VXLAN Header │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ VNI: 100 (24 bits) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Inner Ethernet Header │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 容器A MAC | 容器B MAC │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Inner IP Packet │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Src: 10.0.0.2 | Dst: 10.0.0.3 │ │
│ │ Payload │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘5. 虚拟化性能优化
bash
#!/bin/bash
# 虚拟化性能调优脚本
echo "=== KVM性能优化 ==="
# 1. CPU优化
echo "1. CPU亲和性绑定"
virsh vcpupin myvm 0 0 # VCPU0绑定到物理CPU0
virsh vcpupin myvm 1 1 # VCPU1绑定到物理CPU1
# 2. 大页内存
echo "2. 启用大页"
echo 1024 > /proc/sys/vm/nr_hugepages
echo "vm.nr_hugepages = 1024" >> /etc/sysctl.conf
# 3. VirtIO驱动
echo "3. 确保使用VirtIO"
virsh dumpxml myvm | grep -i virtio
# 4. 多队列网卡
echo "4. 启用多队列VirtIO-net"
# 在VM配置中: <driver name='vhost' queues='4'/>
# 5. vhost-net内核加速
echo "5. 加载vhost_net模块"
modprobe vhost_net
lsmod | grep vhost
# 6. CPU cache tune
echo "6. 配置CPU cache-passthrough"
# <cpu mode='host-passthrough' check='none'>
echo ""
echo "=== 容器性能优化 ==="
# 1. 使用Overlay2存储驱动
echo "1. 检查存储驱动"
docker info | grep "Storage Driver"
# 2. 禁用swap
echo "2. 禁用swap"
swapoff -a
# 3. 调整vm参数
echo "3. 优化内存管理"
sysctl -w vm.swappiness=0
sysctl -w vm.overcommit_memory=1
# 4. 使用host网络模式(需要时)
echo "4. 高性能网络建议使用host模式"
# 5. cgroup v2
echo "5. 检查cgroup版本"
stat -fc %T /sys/fs/cgroup/6. 总结
本教程深入讲解了虚拟化技术:
核心知识点:
- 虚拟化类型: 全虚拟化、半虚拟化、容器
- KVM架构: CPU虚拟化、内存虚拟化、I/O虚拟化
- Namespace: 6种隔离机制
- Cgroup: CPU/内存/IO资源限制
- 容器网络: Bridge、Host、Overlay
实战技能:
- 搭建KVM虚拟机
- 创建和管理Docker容器
- 配置cgroup资源限制
- 优化虚拟化性能
最佳实践:
- VM使用VirtIO提升性能
- 启用大页内存
- CPU亲和性绑定
- 容器使用Overlay2存储驱动
- 生产环境禁用swap
- 合理设置资源限制
掌握虚拟化是理解云计算和容器化的基础!
💬 讨论
使用 GitHub 账号登录后即可参与讨论