Docker技术三大要点:cgroup, namespace和unionFS的理解

www.docker.com的网页有这样一张有意思的动画:

从这张gif图片,我们不难看出Docker网站想传达这样一条信息, 使用Docker加速了build,ship和run的过程。

Docker最早问世是2013年,以一个开源项目的方式被大家熟知。

Docker的奠基者是dotcloud,一家开发PaaS平台的技术公司。

不过可惜的是,这家公司把Docker开源之后,于2016年倒闭了,因为其主业务PaaS无法和微软,亚马逊等PaaS业界巨头竞争,不禁让人唏嘘。

Docker其实是容器化技术的具体技术实现之一,采用go语言开发。很多朋友刚接触Docker时,认为它就是一种更轻量级的虚拟机,这种认识其实是错误的,Docker和虚拟机有本质的区别。容器本质上讲就是运行在操作系统上的一个进程,只不过加入了对资源的隔离和限制。而Docker是基于容器的这个设计思想,基于Linux Container技术实现的核心管理引擎。

为什么资源的隔离和限制在云时代更加重要?在默认情况下,一个操作系统里所有运行的进程共享CPU和内存资源,如果程序设计不当,最极端的情况,某进程出现死循环可能会耗尽CPU资源,或者由于内存泄漏消耗掉大部分系统资源,这在企业级产品场景下是不可接受的,所以进程的资源隔离技术是非常必要的。

我当初刚接触Docker时,以为这是一项新的技术发明,后来才知道,Linux操作系统本身从操作系统层面就支持虚拟化技术,叫做Linux container,也就是大家到处能看到的LXC的全称。

LXC的三大特色:cgroup,namespace和unionFS。

cgroup:

CGroups 全称control group,用来限定一个进程的资源使用,由Linux 内核支持,可以限制和隔离Linux进程组 (process groups) 所使用的物理资源 ,比如cpu,内存,磁盘和网络IO,是Linux container技术的物理基础。

namespace:

另一个维度的资源隔离技术,大家可以把这个概念和我们熟悉的C++和Java里的namespace相对照。

如果CGroup设计出来的目的是为了隔离上面描述的物理资源,那么namespace则用来隔离PID(进程ID),IPC,Network等系统资源。

我们现在可以将它们分配给特定的Namespace,每个Namespace里面的资源对其他Namespace都是透明的。

不同container内的进程属于不同的Namespace,彼此透明,互不干扰。

我们用一个例子来理解namespace的必要。

假设多个用户购买了一台Linux服务器的Nginx服务,每个用户在该服务器上被分配了一个Linux系统的账号。我们希望每个用户只能访问分配给其的文件夹,这当然可以通过Linux文件系统本身的权限控制来实现,即一个用户只能访问属于他本身的那些文件夹。

但是有些操作仍然需要系统级别的权限,比如root,但我们肯定不可能给每个用户都分配root权限。因此我们就可以使用namespace技术:

我们能够为UID = n的用户,虚拟化一个namespace出来,在这个namespace里面,该用户具备root权限,但是在宿主机上,该UID =n的用户还是一个普通用户,也感知不到自己其实不是一个真的root用户这件事。

同样的方式可以通过namespace虚拟化进程树。

在每一个namespace内部,每一个用户都拥有一个属于自己的init进程,pid = 1,对于该用户来说,仿佛他独占一台物理的Linux服务器。

对于每一个命名空间,从用户看起来,应该像一台单独的Linux计算机一样,有自己的init进程(PID为1),其他进程的PID依次递增,A和B空间都有PID为1的init进程,子容器的进程映射到父容器的进程上,父容器可以知道每一个子容器的运行状态,而子容器与子容器之间是隔离的。从图中我们可以看到,进程3在父命名空间里面PID 为3,但是在子命名空间内,他就是1.也就是说用户从子命名空间 A 内看进程3就像 init 进程一样,以为这个进程是自己的初始化进程,但是从整个 host 来看,他其实只是3号进程虚拟化出来的一个空间而已。

看下面的图加深理解。

父容器有两个子容器,父容器的命名空间里有两个进程,id分别为3和4, 映射到两个子命名空间后,分别成为其init进程,这样命名空间A和B的用户都认为自己独占整台服务器。

Linux操作系统到目前为止支持的六种namespace:

unionFS:

顾名思义,unionFS可以把文件系统上多个目录(也叫分支)内容联合挂载到同一个目录下,而目录的物理位置是分开的。

要理解unionFS,我们首先要认识bootfs和rootfs。

1. boot file system (bootfs):包含操作系统boot loader 和 kernel。用户不会修改这个文件系统。

一旦启动完成后,整个Linux内核加载进内存,之后bootfs会被卸载掉,从而释放出内存。

同样内核版本的不同的 Linux 发行版,其bootfs都是一致的。

2. root file system (rootfs):包含典型的目录结构,包括 /dev, /proc, /bin, /etc, /lib, /usr, and /tmp

就是我下面这张图里的这些文件夹:

等再加上要运行用户应用所需要的所有配置文件,二进制文件和库文件。这个文件系统在不同的Linux 发行版中是不同的。而且用户可以对这个文件进行修改。

Linux 系统在启动时,roofs 首先会被挂载为只读模式,然后在启动完成后被修改为读写模式,随后它们就可以被修改了。

不同的Linux版本,实现unionFS的技术可能不一样,使用命令docker info查看,比如我的机器上实现技术是overlay2:

看个实际的例子。

新建两个文件夹abap和java,在里面用touch命名分别创建两个空文件:

新建一个mnt文件夹,用mount命令把abap和java文件夹merge到mnt文件夹下,-t执行文件系统类型为aufs:

sudo mount -t aufs -o dirs=./abap:./java none ./mnt

mount完成后,到mnt文件夹下查看,发现了来自abap和java文件夹里总共4个文件:

现在我到java文件夹里修改spring,比如加上一行spring is awesome, 然后到mnt文件夹下查看,发现mnt下面的文件内容也自动被更新了。

那么反过来会如何呢?比如我修改mnt文件夹下的aop文件:

而java文件夹下的原始文件没有受到影响:

实际上这就是Docker容器镜像分层实现的技术基础。如果我们浏览Docker hub,能发现大多数镜像都不是从头开始制作,而是从一些base镜像基础上创建,比如debian基础镜像。

而新镜像就是从基础镜像上一层层叠加新的逻辑构成的。这种分层设计,一个优点就是资源共享。

想象这样一个场景,一台宿主机上运行了100个基于debian base镜像的容器,难道每个容器里都有一份重复的debian拷贝呢?这显然不合理;借助Linux的unionFS,宿主机只需要在磁盘上保存一份base镜像,内存中也只需要加载一份,就能被所有基于这个镜像的容器共享。

当某个容器修改了基础镜像的内容,比如 /bin文件夹下的文件,这时其他容器的/bin文件夹是否会发生变化呢?

根据容器镜像的写时拷贝技术,某个容器对基础镜像的修改会被限制在单个容器内。

这就是我们接下来要学习的容器 Copy-on-Write 特性。

容器镜像由多个镜像层组成,所有镜像层会联合在一起组成一个统一的文件系统。如果不同层中有一个相同路径的文件,比如 /text,上层的 /text 会覆盖下层的 /text,也就是说用户只能访问到上层中的文件 /text。

假设我有如下这个dockerfile:

FROM debian

RUN apt-get install emacs

RUN apt-get install apache2

CMD ["/bin/bash"]

执行docker build .看看发生了什么。

生成的容器镜像如下:

当用docker run启动这个容器时,实际上在镜像的顶部添加了一个新的可写层。这个可写层也叫容器层。

容器启动后,其内的应用所有对容器的改动,文件的增删改操作都只会发生在容器层中,对容器层下面的所有只读镜像层没有影响。

要获取更多Jerry的原创文章,请关注公众号"汪子熙":

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容

  • Docker容器技术已经发展了好些年,在很多项目都有应用,线上运行也很稳定。整理了部分Docker的学习笔记以及新...
    __七把刀__阅读 11,327评论 0 59
  • 一、Docker 简介 Docker 两个主要部件:Docker: 开源的容器虚拟化平台Docker Hub: 用...
    R_X阅读 4,342评论 0 27
  • docker常用命令原理图概览: 按照docker官网上的说法,docker的文件系统分为两层:bootfs和ro...
    燕京博士阅读 2,901评论 2 32
  • 1. 容器 1.1 定义 一种沙盒技术,可以将应用运行在其中,与外界隔离这个沙盒可以被方便地“转移”。 本质上,他...
    小刘要学习阅读 3,996评论 0 1
  • 别人都说高中认识的朋友是一辈子的朋友,结果呢 千错万错都是你的错 不肯借钱是你的错 说话扭捏是你的错 不好好说话想...
    泠鸢i阅读 575评论 0 0