一篇不一样的docker原理解析
转自: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是一致的,就不用做硬件输入输出的搬运工了,只需要做kernel输入输出的搬运工即可,为了有别于硬件层面的虚拟机,这种虚拟机被命名为 操作系统层虚拟化:Operating-system-level virtualization 也被叫做容器
- 让我们来回顾虚拟机的概念,在虚拟机的系统中,虚拟机认为自己有独立的文件系统,进程系统,内存系统,等等一系列,所以为了让容器接近虚拟机,也需要有独立的文件系统,进程系统,内存系统,等等一系列,为了达成这一目的,主机系统采用的办法是:只要隔离容器不让它看到主机的文件系统,进程系统,内存系统,等等一系列,那么容器系统就是一个接近虚拟机的玩意了
更多关于容器的内容可以看这份课件:https://courses.engr.illinois.edu/cs423/lectures/VirtOS.pdf
至此就可以回答引言提到的两个问题:
- Docker 容器有自己的kernel吗
- 没有,docker和宿主机共享kernel
- docker的kernel version由镜像确定还是由宿主机确定
- 由宿主机决定
3 how to learn more
- 关于操作系统层的虚拟化的概念:Operating-system-level virtualization 以及包括freebsd jail有关的一系列其他的操作系统上相似的实现
- 想要了解更多,docker具体做了什么,可以参考:一篇不一样的docker原理解析 提高篇 - uncle creepy的文章 - 知乎专栏
- 关于namespace,cgroups,aufs,deviceMapper 可以了解官方文档
- 在mac os和windows上运行docker的秘密:Boot2docker by boot2docker 就是通过这个叫做boot2docker的玩意启动了一个虚拟linux kernel,所有的docker容器都跑在这个kernel上
在开始讨论前,先抛出一个问题:
- linux启动流程 中,容器需要使用其中的几步?

如图,linux的启动流程
0 从fork说起
在讲解容器之前,先来谈谈linux实现进程的原理,linux实现进程的方法为fork,实现的方式分为两个步骤:
- 在内存中复制一个父进程,得到“子进程”,此时子进程就是父进程上下文的简单克隆,内容完全一致
- 设置子进程的 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() 本质上它们是差不多的。
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之类的步骤,所以答案是一步都不用。
5 how to learn more
- 比较除docker外其他的容器类产品,如coreOS,LXC
- 了解linux如何做隔离,请参考:namespaces(7)
- 了解freebsd如何做隔离,请参考:freebsd jail
- docker 其实真正想做的事情是把资源隔离的接口标准化(最新的版本里windows的接口也被抽象到了docker自己的体系),严格说它是所有相似资源隔离的一层抽象和搬运工
- docker 镜像很小的优势,主要是靠AUFS实现的,本篇不详细说明,因为AUFS在docker原理介绍的口水文里被用滥了,随便搜搜到处都是,而且我很不喜欢官方用的集装箱比喻
一篇不一样的docker原理解析的更多相关文章
- Android中插件开发篇之----应用换肤原理解析
一.前言 今天又到周末了,感觉时间过的很快呀.又要写blog了.那么今天就来看看应用的换肤原理解析.在之前的一篇博客中我说道了Android中的插件开发篇的基础:类加载器的相关知识.没看过的同学可以转 ...
- 「进阶篇」Vue Router 核心原理解析
前言 此篇为进阶篇,希望读者有 Vue.js,Vue Router 的使用经验,并对 Vue.js 核心原理有简单了解: 不会大篇幅手撕源码,会贴最核心的源码,对应的官方仓库源码地址会放到超上,可以配 ...
- Docker原理探究
问题思考:-------------------------------------Docker浅显原理理解-------------------------------------P1. ubunt ...
- docker原理(转)
转自:https://zhuanlan.zhihu.com/p/22382728 https://zhuanlan.zhihu.com/p/22403015 在学习docker的过程中,我发现目前do ...
- [原][Docker]特性与原理解析
Docker特性与原理解析 文章假设你已经熟悉了Docker的基本命令和基本知识 首先看看Docker提供了哪些特性: 交互式Shell:Docker可以分配一个虚拟终端并关联到任何容器的标准输入上, ...
- 3D游戏常用技巧Normal Mapping (法线贴图)原理解析——高级篇
1.概述 上一篇博客,3D游戏常用技巧Normal Mapping (法线贴图)原理解析——基础篇,讲了法线贴图的基本概念和使用方法.而法线贴图和一般的纹理贴图一样,都需要进行压缩,也需要生成mipm ...
- 秋色园QBlog技术原理解析:性能优化篇:缓存总有失效时,构造持续的缓存方案(十四)
转载自:http://www.cyqdata.com/qblog/article-detail-38993 文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文 ...
- python实现布隆过滤器及原理解析
python实现布隆过滤器及原理解析 布隆过滤器( BloomFilter )是一种数据结构,比较巧妙的概率型数据结构(probabilistic data structure),特点是高效地 ...
- Request 接收参数乱码原理解析三:实例分析
通过前面两篇<Request 接收参数乱码原理解析一:服务器端解码原理>和<Request 接收参数乱码原理解析二:浏览器端编码原理>,了解了服务器和浏览器编码解码的原理,接下 ...
随机推荐
- UOJ182 a^-1 + b problem 解题报告
题目描述 有一个长度为\(n(n\le 10^5)\)的数列,在模\(M\)意义下进行\(m(m \le50000)\)次操作,每次操作形如以下两种形式: 1 \(x\) 表示每个数加\(x(0 \l ...
- [转]现代Linux系统上的栈溢出攻击
1. 基本内容 这个教程试着向读者展示最基本的栈溢出攻击和现代Linux发行版中针对这种攻击的防御机制.为此我选择了最新版本的Ubuntu系统(12.10),因为它默认集成了几个安全防御机制,而且它也 ...
- eclipse中去掉py文件中烦人的黄色弹框
eclipse中写py文件,当鼠标点击在参数上时总是出现黄线的弹框,影响人操作,感觉特别烦,如下: 解决方案: windows--preferences--hover--pydev--hover取消选 ...
- 深度学习之卷积神经网络(CNN)
卷积神经网络(CNN)因为在图像识别任务中大放异彩,而广为人知,近几年卷积神经网络在文本处理中也有了比较好的应用.我用TextCnn来做文本分类的任务,相比TextRnn,训练速度要快非常多,准确性也 ...
- Android缓存机制——LruCache
概述 LruCache的核心原理就是对LinkedHashMap的有效利用,它的内部存在一个LinkedHashMap成员变量,值得注意的4个方法:构造方法.get.put.trimToSize LR ...
- TIMO后台管理系统-基于SpringBoot开发
项目介绍 TIMO后台管理系统,基于SpringBoot2.0 + Spring Data Jpa + Thymeleaf + Shiro 开发的后台管理系统,采用分模块的方式便于开发和维护,支持前后 ...
- itest 开源测试管理项目中封装的下拉列表小组件:实现下拉列表使用者前后端0行代码
导读: 主要从4个方面来阐述,1:背景:2:思路:3:代码实现:4:使用 一:封装背景 像easy ui 之类的纯前端组件,也有下拉列表组件,但是使用的时候,每个下拉列表,要配一个URL ...
- Android之Material Dialogs详解
文章大纲 一.什么是Material Dialogs二.Material Dialogs实战三.项目源码下载 一.什么是Material Dialogs Material Dialogs是一个 ...
- windows本地安全策略实验-远程桌面连接锁定账户
windows本地安全策略实验-远程桌面连接锁定账户 实验环境: 服务端:Win7-1:10.10.10.136,开启远程桌面服务 客户端:win7-2:10.10.10.153 确保客户端和服务端能 ...
- Intellij Idea 无法启动项目的配置坑
1. run/debug configuration里面,tomcat的deployment点击添加不能自动创建war-explorded包: 方案:删除project libraries,重新mav ...