@maorongrong
2017-06-27T06:29:08.000000Z
字数 2393
阅读 511
实习
容器(container)是一种轻量级的虚拟化技术, 用于生成一个独立的标准运行环境而不需要多个内核实例. 容器技术的隔离性稍逊于Xen/KVM等虚拟机技术, 但胜在轻巧部署便捷
优势和劣势
开源社区趋向于将LXC视为一种与虚拟机技术对等的虚拟化技术, 比如libvirt库已经为LXC抽象了类似Xen/KVM的虚拟机操作接口. 容器与虚拟机的主要区别在于同一宿主机内的多个容器共享一个Linux内核实例; 而每个虚拟机都有自己独享的内核, 能运行完整的不作修改的操作系统.
相比虚拟机技术, 容器技术有以下优势:
快速部署(秒级), 启动一个容器只需要派生一个进程并完成OS启动的用户态部分; 而启动一个虚拟机需要执行额外的BIOS和内核代码.
容器几乎没有额外的IO性能开销; 如果没有完善的硬件虚拟化支持, 虚拟机会引入显著的IO性能开销.
容器的内存开销较小: 启动一个没有任何负载的容器仅需要几十MB的内存. 而虚拟机由于包含完整的内核, 内存开销要大得多. 另外如果使用Union FS来构造容器的文件系统, 能减少page cache带来的内存开销.
较小的磁盘空间占用: 构造容器的文件系统时, 静态文件可以使用bind-mount或者Union FS方式从宿主机加载, 可以节省大量磁盘空间.
在宿主机中可以实现更高的密度.
相对于虚拟机技术, 容器技术有以下劣势:
资源隔离效果逊于虚拟机; 对于虚拟机技术, 由于有Hypervisor的存在, 资源的隔离实现非常完整; 而容器技术还处于开发阶段, 资源隔离的效果要逊于虚拟机.
内核的修改会影响所有的容器, 而虚拟机因为Hypervisor的存在, 内核的更新只会影响一个应用.
缺少动态迁移的支持, 目前OpenVZ的CRIU项目提供了初步的checkpointing和restore支持, 但完整的动态迁移仍需时日. 虚拟机的动态迁移方案相对比较完整.
核心技术
LXC所用到的核心技术包括control groups (cgroup) , namespace以及Union文件系统.
cgroup
容器运行时可以表示为一个具有父子关系的进程组. 而Linux内核中cgroup技术支持对多种系统资源以进程组为粒度进行限制, 从而保证不会因为一个容器占用过多资源影响整个系统的性能和稳定性.
关于cgroup的技术细节, 参见cgroup内核文档[3].
容器对于cgroup技术的应用非常简单, 容器的所有进程都属于一个进程组, 这个进程组被一个cgroup管理. 正确的配置该cgroup即可达到限制容器资源使用的目的. 虽然cgroup支持多级hierarchy, 容器一般只使用一级, 如下图所示:
namespace
namespace机制为系统资源创建多个实例并分配给一组进程, 使得这些进程看起来好像独占全部的系统资源.
在LXC中, 创建namespace的时机是调用clone()来派生容器进程:
clone_flags = CLONE_NEWUTS CLONE_NEWPID CLONE_NEWIPC CLONE_NEWNS CLONE_NEWNET;
clone(func, arg, clone_flags);
clone()调用将派生一个新的进程, 并为这个进程生成新的namespace. 这些namespace包括:
pid namespace: 容器拥有一个独立的pid空间, 在容器内部, init进程拥有pid 1.
net namespace: 容器拥有自己的网络协议栈, 包括TCP/IP端口, 路由规则, 网卡命名空间, iptables规则集等.
ipc namespace: 容器拥有自己的IPC对象空间.
mnt namespace: 容器拥有自己的mount point集合和文件系统视图.
uts namespace: 容器拥有自己的主机名 (uname命令有不同于宿主机的输出)
使用这些namespace相关的flag需要进程拥有CAP_SYS_ADMIN的capability.
受限于我们使用的内核版本(2.6.32), user namespace还未支持, 所以不同容器中的具有相同UID的用户实际是是同一个用户.
union file system
Union FS是一类虚拟文件系统, 用于将多个处于文件系统不同位置的目录合并显示, 比如Docker使用的AUFS和 AI使用的overlayfs. 下面以overlayfs为例说明Union FS的原理.
加载一个overlayfs目录的命令如下:
mount -t overlayfs none -olowerdir=/common,upperdir=/priv /dir
其中涉及到三个目录:
dir: 用户最终看见的目录, 由lowerdir和uppper合并显示.
common(lowerdir): 底层目录, 只读部分, 在容器应用中可以视为所有容器共享的目录.
priv(upperdir): 顶层目录, 可以视为容器的私有目录. 对dir目录所做的任何修改实际都反映在该目录中.
合并显示遵循下面几个原则:
对于common和priv中同名文件, dir中显示priv中的那个;
在dir中新建的文件, 实际存储于priv目录中;
从dir中删除的文件如果存储于common目录中, 仅仅隐藏该文件不作实际删除;
修改dir中一个文件, 如果该文件存储于common目录中, 则将该文件拷贝入priv目录然后修改之.
如图, 在dir目录中创建文件f3, 实际内容存储在priv目录中; 在dir目录中修改文件f1, 会在priv目录中生成拷贝然后修改, 而common目录中的f1则被隐藏.
在容器中使用overlayfs有以下优点:
容器之间共享了大量系统文件, 节省了磁盘空间;
容器对共享目录的修改不会影响其他容器和宿主机, 达到隔离效果;
对于共享文件只存在一份page cache, 节省了内存.
关于Overlayfs的技术细节, 参见三百详细的介绍[13].