转自:https://zhuanlan.zhihu.com/p/22382728

   https://zhuanlan.zhihu.com/p/22403015

在学习docker的过程中,我发现目前docker学习最大的障碍,不是网上的资源太少,而是网上的资源太多,资源太多带来的噪声让学习效率降低不少。而在讲解docker原理上,所有的讲解都是关于cgroups,namespace,aufs以及deviceMapper,这对于一个初学者来说,就是用一堆名词替换另一堆名词,所以我打算写一篇不涉及太多api的原理解析,在这篇解析中,将不会讨论:

  • 一堆堆砌在一起的专有名词,让阅读者云里雾里
  • 一大堆写满了专有名词的图,但是不给太多解释

这篇解析将会涉及:

  • 虚拟机的实现原理
  • 虚拟机和容器的区别

在开始讨论前,先抛出一些问题,可先别急着查看答案,讨论的过程可以让答案更有趣,问题如下:

1 虚拟机

先来理解一下虚拟机概念,广义来说,虚拟机是一种模拟系统,即在软件层面上通过模拟硬件的输入和输出,让虚拟机的操作系统得以运行在没有物理硬件的环境中(也就是宿主机的操作系统上),其中能够模拟出硬件输入输出,让虚拟机的操作系统可以启动起来的程序,被叫做hypervisor。用一张图来说明这个关系就是:

在这张图中:

  • 物理机被称为宿主机
  • 虚拟机也被称为guest OS
  • 而被hypervisor虚拟出来的硬件被称为虚拟硬件

比如,举一个大家都很熟悉的例子,在编写android程序时,调试和测试运行都可以在X86架构的台式机或笔记本进行,这就是一个典型的虚拟机例子,在这之中:

  • 宿主机就是台式机或笔记本
  • 虚拟机就是虚拟出来的android
  • 而模拟android的软件就是android box

当然android模拟机一个大问题就是:启动速度非常慢,最长可达10分钟或以上,这是因为单纯模拟硬件的输入输出,效率是很差的,所以这样的虚拟机如果真部署在服务器上,速度是感人的。

假如我们不模拟硬件输入输出,宿主机的硬件架构和虚拟硬件架构一致,只做下真实硬件输入输出的搬运工,那么虚拟机的指令执行速度,就可以和宿主机一致了。比如,

  • 我们可以在linux的台式机上轻松模拟windows,而且这个windows的运行速度基本上和原生装一个windows速度差不多,因为windows也能被直接安装在这台台式机上。
  • 这个思路对于在windows系统中运行android系统不管用,因为android系统的运行硬件一般是手机(arm系统,可以理解为不同的硬件架构体系和cpu指令集),所以android模拟机还是一样的慢。

由于本篇并不是主要关于虚拟机的内容,所以这些点就点到而止,更多详细内容可以参阅:Hypervisor

2 容器的概念

虚拟机启动的时候需要先做开机自检,启动kernel,启动用户进程等一系列行为,虽然现在电脑运行速度挺快,但是这一系列检查做下来,也要几十秒,也就是虚拟机需要几十秒来启动。

  • 重新来理解虚拟机的概念,计算机科学家发现其实我们创建虚拟机也不一定需要模拟硬件的输入和输出,假如宿主机和虚拟机他们的kernel是一致的,就不用做硬件输入输出的搬运工了,只需要做kernel输入输出的搬运工即可,为了有别于硬件层面的虚拟机,这种虚拟机被命名为 操作系统层虚拟化:Operating-system-level virtualization 也被叫做容器
  • 让我们来回顾虚拟机的概念,在虚拟机的系统中,虚拟机认为自己有独立的文件系统,进程系统,内存系统,等等一系列,所以为了让容器接近虚拟机,也需要有独立的文件系统,进程系统,内存系统,等等一系列,为了达成这一目的,主机系统采用的办法是:只要隔离容器不让它看到主机的文件系统,进程系统,内存系统,等等一系列,那么容器系统就是一个接近虚拟机的玩意了

更多关于容器的内容可以看这份课件:https://courses.engr.illinois.edu/cs423/lectures/VirtOS.pdf

至此就可以回答引言提到的两个问题:

3 how to learn more

在上一篇 一篇不一样的docker原理解析 - uncle creepy的文章 - 知乎专栏 中,主要讨论了容器和虚拟机的区别,在实现细节上并没有深入,只是点到即止,在这篇提高篇中,将详细讨论容器的实现细节,当然我不希望把文章写成对于kernel man page的简单翻译,所以不熟悉内核和linux api的读者可以不急着点叉,这会是一篇不一样的讨论容器实现的提高篇。

在开始讨论前,先抛出一个问题:

如图,linux的启动流程

0 从fork说起

在讲解容器之前,先来谈谈linux实现进程的原理,linux实现进程的方法为fork,实现的方式分为两个步骤:

    1. 在内存中复制一个父进程,得到“子进程”,此时子进程就是父进程上下文的简单克隆,内容完全一致
    2. 设置子进程的 pid,parent_pid,以及其他和父进程不一致的内容

1 namespace让进程隔离更灵活

从进程被制造的步骤可以看出,进程大部分资源和父进程共享,如果需要制造一个看起来像虚拟机的进程,我们需要比普通的进程多做几步。

  • 可以自定义rootfs,比如我们把整个ubuntu发行版的可执行文件以及其他文件系统都放在目录/home/admin/ubuntu/ 下,当我们重定义rootfs = /home/admin/ubuntu 后,则该文件地址被印射为 "/"
  • 把自身pid 印射为0,并看不到其他任何的pid,这样自身的pid成为系统内唯一存在pid,看起来就像新启动了系统
  • 用户名隔离,可以把用户名设置为“root”
  • hostname隔离,可以另取一个hostname,成为新启动进程的hostname
  • IPC隔离,隔离掉进程之间的互相通信
  • 网络隔离,隔离掉进程和主机之间的网络

如果做完这几步,至少在进程自身看来,和虚拟机执行环境上已经区别不大了,对应到linux系统中,这几个隔离需要的方法:clone(2) - Linux manual page

而clone方法和fork方法,在复制上下文的时候,调用的都是syscall_clone() 本质上它们是差不多的。

1 namespace让进程隔离更灵活

从进程被制造的步骤可以看出,进程大部分资源和父进程共享,如果需要制造一个看起来像虚拟机的进程,我们需要比普通的进程多做几步。

  • 可以自定义rootfs,比如我们把整个ubuntu发行版的可执行文件以及其他文件系统都放在目录/home/admin/ubuntu/ 下,当我们重定义rootfs = /home/admin/ubuntu 后,则该文件地址被印射为 "/"
  • 把自身pid 印射为0,并看不到其他任何的pid,这样自身的pid成为系统内唯一存在pid,看起来就像新启动了系统
  • 用户名隔离,可以把用户名设置为“root”
  • hostname隔离,可以另取一个hostname,成为新启动进程的hostname
  • IPC隔离,隔离掉进程之间的互相通信
  • 网络隔离,隔离掉进程和主机之间的网络

如果做完这几步,至少在进程自身看来,和虚拟机执行环境上已经区别不大了,对应到linux系统中,这几个隔离需要的方法:clone(2) - Linux manual page

而clone方法和fork方法,在复制上下文的时候,调用的都是syscall_clone() 本质上它们是差不多的。

2 其实docker是一个内核的搬运工

所以虽然docker帮助我们准备好了rootfs地址,镜像里面的文件,以及各种资源隔离的配置,但是在启动一个容器的时候,它只是调用系统中早已内置的可以隔离资源的方法,而kernel支持这些方法,也是在创建进程的方法上做了一层资源隔离的扩展而已。

这就解释了docker两个特性:

  • 启动速度快,因为本质来说容器和进程差别没有想象中的大,共享了很多代码,流程也差的不多
  • linux内核版本有最低的要求,因为linux是在某个版本后开始支持隔离特性

3 容器内创建进程 --- Think a step further

这是我认为整个容器实现里面最优美的一点:

  • 内核开发者实现了容器的资源隔离一系列隔离后,内核开发者就不需要为容器内创建进程单独再做任何多余的工作了。
  • 在fork方法中,第一步就是继承父进程的一切,而这一切包含了父进程已有的资源隔离,所以容器进程创建的进程天然继承容器所有的一切资源隔离 ------ 就和虚拟机的pid = 0 的进程创建子进程所拥有的一样

4 One more thing

让我们再来看看开篇提出的问题:

linux启动流程 中,容器需要使用其中的几步?

看完了fork,clone以及一大堆隔离后,相信读者很容易有答案了,这中间容器做完了隔离之后就算启动完毕,根本就不会来做kernel init之类的步骤,所以答案是一步都不用。(这里的意思是不用从头引导,docker只是一个内核的搬运工,docker是一个进程..)

5 how to learn more

  • 比较除docker外其他的容器类产品,如coreOS,LXC
  • 了解linux如何做隔离,请参考:namespaces(7)
  • 了解freebsd如何做隔离,请参考:freebsd jail
  • docker 其实真正想做的事情是把资源隔离的接口标准化(最新的版本里windows的接口也被抽象到了docker自己的体系),严格说它是所有相似资源隔离的一层抽象和搬运工
  • docker 镜像很小的优势,主要是靠AUFS实现的,本篇不详细说明,因为AUFS在docker原理介绍的口水文里被用滥了,随便搜搜到处都是,而且我很不喜欢官方用的集装箱比喻

docker原理(转)的更多相关文章

  1. 一篇不一样的docker原理解析

    转自:https://zhuanlan.zhihu.com/p/22382728 https://zhuanlan.zhihu.com/p/22403015 在学习docker的过程中,我发现目前do ...

  2. docker原理与上帝进程

    做个笔记, 先水一会. 虚拟机指的是: 在软件的层面上通过模拟硬件进行的输入输出. docker原理:docker就是一个linux系统的进程, 它通过 Linux 的 namespaces 对不同的 ...

  3. Docker原理探究

    问题思考:-------------------------------------Docker浅显原理理解-------------------------------------P1. ubunt ...

  4. docker原理

    Docker原理11 Linux Namespace 11 AUFS文件系统17 重新理解Docker的各种命令18 Docker原理 Linux Namespace docker是一个容器引擎,容器 ...

  5. Docker原理(开发技术分享转发)

    Docker原理Docker是啥Docker是一个程序运行.测试.交付的开放平台,Docker被设计为能够使你快速地交付应用.在Docker中,你可以将你的程序分为不同的 基础部分,对于每一个基础部分 ...

  6. 一篇文章带你吃透 Docker 原理

    容器的实现原理 从本质上,容器其实就是一种沙盒技术.就好像把应用隔离在一个盒子内,使其运行.因为有了盒子边界的存在,应用于应用之间不会相互干扰.并且像集装箱一样,拿来就走,随处运行.其实这就是 Paa ...

  7. Docker系列(4)- run的流程和docker原理

    回顾HelloWorld流程 底层工作原理 Docker是怎么工作的? Docker是一个Client-Server结构的系统,Docker的守护进程运行在宿主机上.通过Socket从客户端访问 Do ...

  8. docker原理(转)

    可能是把Docker的概念讲的最清楚的一篇文章 [编者的话]本文只是对Docker的概念做了较为详细的介绍,并不涉及一些像Docker环境的安装以及Docker的一些常见操作和命令. Docker是世 ...

  9. docker 原理

    docker项目的目标是实现轻量级的操作系统虚拟化,Docker的基础是Linux容器(LXC)等技术. 在LXC的基础上,Docker做了进一步的封装,让用户不关心容器的管理,使得操作更为简单.用户 ...

随机推荐

  1. 启动VMware出现报错:The VMware Authorization Service is not running

    出现The VMware Authorization Service is not running.报错的根本原因是开机没有启动"VMware Authorization Service&q ...

  2. TensorFlow——LSTM长短期记忆神经网络处理Mnist数据集

    1.RNN(Recurrent Neural Network)循环神经网络模型 详见RNN循环神经网络:https://www.cnblogs.com/pinard/p/6509630.html 2. ...

  3. ACM常用之 异或运算的性质。

  4. 3.4 jmu-java-随机数-使用蒙特卡罗法计算圆周率的值 (10 分)

    import java.util.Scanner; import java.util.Random; public class Main {         public static void ma ...

  5. 公司内网机器vm ubuntu proxy 设置

    解决浏览器上网问题: System Setting -> Network -> Network Proxy设置公司的代理 解决apt联网问题: 在/etc/apt/apt.conf文件里加 ...

  6. 【HDU4276】The Ghost Blows Light

    题目大意:给定一棵有根树,1 号节点为根节点,点有点权,边有边权,初始给定一个价值,每经过一条边都会减少该价值,每经过一个点都会增加相应的答案贡献值,求如何在给定价值的情况下最大化答案贡献,并要求最后 ...

  7. 【洛谷P3723】礼物

    题目大意:给定两个序列 A.B,现可以将 A 序列的每一个元素的值增加或减少 C,求 \(\sum\limits_{i=0}^{n-1}(a_i-b_{i+k})^2\) 的最小值是多少. 题解:先不 ...

  8. 前端每日实战:158# 视频演示如何用纯 CSS 创作一个雨伞 toggle 控件

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/pxLbjv 可交互视频 此视频是可 ...

  9. python大佬养成计划----HTML网页设计(表格)

    制作网页时,要合理规划网页布局.比如,在网页中添加一个表格,可分为上.中.下三部分,上部存放网页标题或LOGO图片,中间部分是整个网页的主体内容,底部就是相关制作信息.此外,单元格里还可再添加单元格, ...

  10. java课堂动手测试2

    测试一 编写一个方法,使用以上算法生成指定数目(比如1000个)的随机整数. 程序源代码 import java.util.Random;import java.util.Scanner; publi ...