Container内核原理介绍 邱模炯 @ UCloud
虚拟化技术:VM与Container App App App Binaries/ Libraries Binaries/ Libraries Guest Kernel Guest Kernel Guest Kernel Binaries/ Libraries Binaries/ Libraries Binaries/ Libraries 轻量:高比例部署,秒级启动 Hypervisor(VMM) Host Kernel Host Kernel Hardware Hardware System Virtualization Container Virtualization
虚拟化技术:VM与Container 内容: namespace cgroup aufs 两者对比 App App App Binaries/ Libraries Binaries/ Libraries Binaries/ Libraries App App App Binaries/ Libraries Guest Kernel Guest Kernel Guest Kernel Binaries/ Libraries Binaries/ Libraries namespace+cgroup相当于hypervisor,都提供了虚拟化环境以及资源隔离功能 aufs是个联合文件系统,同一个机器上的container往往是同质或者同一个基础镜像的。aufs使得一个container的镜像非常小,相对于基础镜像的增量部分。这是docker非常依赖的 Hypervisor(VMM) namespace & cgroup Host Kernel Host Kernel Hardware Hardware System Virtualization Container Virtualization
namespace:进程组虚拟化的手段 进程运行环境有哪些? 进程虚拟化/隔离 已有ns VFS mount, 即文件系统rootfs uid, gid network,即独立的网络设备和tcpip pid, 父pid devices, hostinfo, IPC, /proc, /sys等 进程虚拟化/隔离 已有ns pid:进程ID mnt:文件系统挂载点 net:网络栈 uts:主机名 ipc:进程间通信 user:用户ID, 组ID,capabilities 子进程自动继承父的ns 进程运行环境有哪些 namespace提供了一组进程的虚拟运行环境以及隔离手段 已有的ns对应我们刚才所讲的运行环境 子进程自动继承父进程的ns
nsproxy相当于运行环境 UTS0 struct nsproxy: struct task_struct{ uts_namespace ipc_namespace pid_namespace mnt_namespace net struct task_struct{ struct nsproxy *nsproxy ... } IPC0 PID0 MNT0 struct task_struct{ struct nsproxy *nsproxy ... } NET0 struct nsproxy: uts_namespace ipc_namespace pid_namespace mnt_namespace net 多个ns包含在一个nsproxy,相当于提供了一个运行环境 UTS1 struct task_struct{ struct nsproxy *nsproxy ... } PID1 NET1
mnt ns提供私有的rootfs 每个mnt ns有自己的rootfs,相对于host的根目录 struct mnt_namespace{ struct mount * root; ... } 每个mnt ns有自己的rootfs,相对于host的根目录
pid ns映射后的pid空间 struct pid_namespace{ struct pidmap pidmap[PIDMAP_ENTRIES]; ... } 内核维护一个PID之间的映射表 PID级别可以多级 每个PID NS都有init进程1,进程回收、僵尸进程规则等
net ns提供独立的网络栈 每一个ns 私有的网络设备 独立的协议栈 lo, veth等虚设备 物理网卡 ipv4, ipv6(含IP地址和路由表) tcp, sctp, dccp iptables规则 ipvs等
其他ns uts, ipc user ns 还有什么namespace没有实现? C1的1001 id和C2的1001不是同一 主要处理uid, gid, capabilities的虚拟化 3.8版本提交;需要文件系统配合,目前不完善 还有什么namespace没有实现? time, device, security keys, security
namespace能做到什么? 虚拟机,但资源无保证 独立的mnt (chroot) 独立的pid空间 独立的网络协议栈 uts uid, gid ipc App App App Binaries/ Libraries Binaries/ Libraries Binaries/ Libraries namespace Host Kernel Hardware
cgroup: 资源隔离和统计 创建控制组,放入进程: limit & isolate account ulimit的群体版 /cgroup 哪些控制组 memory usage_in_bytes limit_in_bytes stat kmem... kmem.tcp... memsw... cpu blkio cpuset, freezer, net_cls, net_prio, devices, perf, cpuacct, hugetlb mount –t cgroup none /cgroup /cgroup cont1 cont2 apache mysql ftp group1: 内存上限3072M, group2: 内存上限1024M, Google 2006年 目前Maintainer: Zefan Li(华为), Tejun Heo 和ulimit类比 创建控制组,放入进程: limit & isolate account 一套cgroup基础设施,不同用途的cgroup插件,代码散落在内核各个地方 开销很小,通常情况下不到1%
cgroup: 内存子系统接口 总体内存 kmem内存 kmem.tcp内存 memory.limit_in_bytes memory.soft_limit_in_bytes memory.usage_in_bytes memory.failcnt memory.max_usage_in_bytes memory.stat memory.kmem.limit_in_bytes memory.kmem.usage_in_bytes memory.kmem.failcnt memory.kmem.max_usage_in_bytes memory.kmem.tcp.xxx 总体内存 kmem内存 kmem.tcp内存
cgroup: 内存子系统原理 mem_cgroup包含该group允许使用内存上限,当前使用量,LRU等信息 每个进程task_struct知道自己属于哪个group 每个页面page有对应的page_cgroup信息,从page_cgroup可知道该页面属于哪个group 在page fault或分配page cache页面时,系统会设置page_cgroup属于哪个mem_cgroup mem_cgroup mm_struct task_struct page page_cgroup memory.usage_in_bytes memory.max_usage_in_bytes memory.limit_in_bytes memory.soft_limit_in_bytes memory.failcnt memory.stat memory.force_empty memory.use_hierarchy memory.swappiness memory.move_charge_at_immigrate memory.oom_control memory.numa_stat (only if CONFIG_NUMA is set) memory.kmem.limit_in_bytes (only if CONFIG_MEMCG_KMEM is set) memory.kmem.usage_in_bytes (only if CONFIG_MEMCG_KMEM is set) memory.kmem.failcnt (only if CONFIG_MEMCG_KMEM is set) memory.kmem.max_usage_in_bytes (only if CONFIG_MEMCG_KMEM is set) memory.kmem.tcp.limit_in_bytes (only if CONFIG_MEMCG_KMEM is set) memory.kmem.tcp.usage_in_bytes (only if CONFIG_MEMCG_KMEM is set) memory.kmem.tcp.failcnt (only if CONFIG_MEMCG_KMEM is set) memory.kmem.tcp.max_usage_in_bytes (only if CONFIG_MEMCG_KMEM is set) memory.kmem.slabinfo (only if CONFIG_SLABINFO is set) memory.memsw.usage_in_bytes (only if CONFIG_MEMCG_SWAP is set) memory.memsw.max_usage_in_bytes (only if CONFIG_MEMCG_SWAP is set) memory.memsw.limit_in_bytes (only if CONFIG_MEMCG_SWAP is set) memory.memsw.failcnt
cgroup: CPU子系统接口 cpu.shares group间CPU调度权重 cpu.stat cpu.cfs_period_us cpu.cfs_quota_us cpu.rt_runtime_us cpu.rt_period_us cpu.share默认1024
cgroup: CPU子系统原理 p4 group1 group2 p2 p6 p2 p5 p1 p3 p5 p1 p3 p4 p6 Complete Faire Scheduling调度的基础是red-black tree,二叉排序树。 启用cgroup前,所有可运行进程都被排序 启用cgroup后,变为两级调度! 第一级:container间 第二级:container内 root p4 group1 group2 这是近似做法。实际上调度的设计更加通用,是一种层次化允许嵌套的模式。每个调度实体可以是进程,也可以是一个组。如果是组,则继续CFS,直到找出进程 p2 p6 p2 p5 p1 p3 p5 p1 p3 p4 p6
cgroup: 其它子系统 blkio cpuset, freezer, net_cls, net_prio, devices, perf, cpuacct, hugetlb
namespace + cgroup能做到? App App App 虚拟机且资源有保证 但,如何使得container精简? Binaries/ Libraries Binaries/ Libraries Binaries/ Libraries namespace & cgroup 如果一个container的rootfs大小是100M,1000个container要100G?而且传输起来费事 Host Kernel Hardware
aufs overview Another Union File System 同类:Overlayfs /base boot bin lib lib64 usr sbin /union boot bin lib lib64 usr sbin data 原理和目标均相同,不同的是代码实现。均未进upstream aufs约20K行有效代码 用途:livecd, 嵌入式设备的factory reset 节省空间,节省pagecache,体积小 /c1 data mount -t aufs -o br=/base=ro:/c1=rw none /union
aufs: 原理 aufs AUFS是个中转器 从图上可以看出: 1)aufs支持联合多种格式的文件系统 2)共用page cache,省内存
aufs: 有待完善 一个写操作导致整个文件的拷贝 branch文件重名时的处理 如何确保可预测可推理的行为 “下层”文件被绕开修改 /rw (none) /union fileA /ro fileA /union打开fileA,这时/new加入,那么后面的read返回谁的fileA? 文件系统有大量的细节 各种网络文件系统、内存文件系统 软链、硬链 xattr属性 aufs on NFS server umount再remount /new fileA
Container VS VM: 内核是运行环境的一部分 内核版本与libc有一定耦合 内核特性 系统调用,/proc, /sys 磁盘设备名 系统配置文件 程序 用户态环境 Container 内核 Container要处理更为复杂的运行环境兼容性。几个例子: 1)一个container在RHEL host运行良好,若部署在Debian可能会有问题。(docker base image能解决之) 2)内核版本对部分用户态库和工具有要求,如libc, perf系统工具等 3)磁盘设备名甚至影响到程序(vda -> sda) 4)系统配置文件不能修改 5)内核版本有要求,如果要userns,需3.8+ 除了内核裁剪和容器内调用库的权限限制,另外很多c++程序还需要带着系统库打包,docker跟host共享内核,那意味着还是host决定了程序运行环境而不是docker虚拟出的container。coreos的超精简Linux host自然满足不了很多软件的要求。多个container如果有不同版本的库需求也会是有问题的,就像不同系统软件可能对Linux内核都有不同版本的要求 VM 硬件
Container VS VM:应用场景 性能和大小 迁移 隔离和安全 适用场景? 运行开销、部署速度、启动速度 适用场景(大公司内部,PaaS云,IaaS云,测试部署) 参考观点: 1)docker帮助加速应用部署和扩容,方便devops 2)container无法迁移 3)公有云卖资源不合适,而公司内部使用合适。想想安全性,软件bug fix的困难;没有彻底的隔离
Thank You