本博客为个人学习极客时间中张磊课程时所作的笔记,仅作交流,不得作为商用
目录
容器的脚下是什么
Namespace的“隔离”让容器进程看到伪装过的世界,而Cgroups则给这个世界打造了一堵无形的墙——emm,怎么有点楚门的世界既视感,哈哈哈,如果容器进程(楚门)低头看看自己的脚下(文件系统),他会看到什么景象呢?之前提到Namespace的时候有介绍六种技术,其中有个mount:
Mount |
CLONE_NEWNS |
挂载点(文件系统) |
Mount Namespace修改的是容器进程对文件系统“挂载点”的认知。Mount Namespace跟其他Namespace的使用略有不同的地方在于它对容器进程视图的修改一定是伴随着挂载操作才能生效,C语言中有专门的mount函数执行挂载命令:
#include <sys/mount.h>
int mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data);
参数:
source:将要挂上的文件系统,通常是一个设备名。
target:文件系统所要挂在的目标目录。
filesystemtype:文件系统的类型,可以是"ext2","msdos","proc","nfs","iso9660" 。。。
mountflags:指定文件系统的读写访问标志
更改根目录的chroot
我们都希望在容器进程启动后看到整个根目录“/”,而chroot命令就是shell中专门完成该功能的,它能够改变进程的根目录到你指定的位置,用法简单:
# chroot $HOME/test /bin/bash
以上命令告诉操作系统使用$HOME/test目录为/bin/bash进程的根目录。实际上,Mount Namespace正是基于对chroot的不断改良才被发明出来的,他也是Linux操作系统里面的第一个Namespace。
可以认为,Docker容器启动后主要执行了三个操作:
启用 Linux Namespace 配置;
设置指定的 Cgroups 参数;
切换进程的根目录(Change Root)
关于第三个操作,Docker容器会优先调用pivot_root进行切换,系统不允许时才会使用chroot。其区别主要为:
pivot_root和chroot的主要区别是,pivot_root主要是把整个系统切换到一个新的root目录,而移除对之前root文件系统的依赖,这样你就能够umount原先的root文件系统。而chroot是针对某个进程,而系统的其它部分依旧运行于老的root目录。
在Linux中,这种挂载在容器根目录上、用来为容器进程提供隔离后执行环境的文件系统即“容器镜像”,更专业的名字叫rootfs(根文件系统)。
容器镜像rootfs
rootfs只是一个操作系统所包含的文件、配置和目录,并不包括操作系统内核,所以说,rootfs只包括了操作系统的躯壳,没有包括操作系统的灵魂——哈哈哈哈!容器共享的还是宿主机的操作系统内核。
rootfs最重要的作用,是为容器提供了一致性的特性。
很多应用打包发布的时候,程序员只看到其编程语言层面的依赖,导致在新的环境打开应用时面临各种异常。殊不知,整个操作系统的文件和目录本身才是应用最需要的、最完整的依赖,而rootfs就提供了这种深入到操作系统级别的运行环境一致性,优雅的解决了应用的环境依赖问题。
容器镜像的层(layer)
我们知道一个项目的代码经常使用git等代码仓库进行管理,每一次修改和commit都会在仓库中生成一个镜像记录。
容器镜像借鉴了git的思想,用户制作镜像的每一个操作都会生成一个层,也就是一个增量rootfs。而实现这一想法的技术是联合文件系统UnionFS。