深入分析 Docker 镜像原理
摘要:近日, DaoCloud 软件工程师孙宏亮在 CSDN Container 微信群为大家带来了 Docker 镜像原理的深度分享,本次分享的重点是 Docker 镜像,分享的内容主要包含两个部分:1)Docker 镜像的基本知识;2)Dockerfile,Docker 镜像与 Docker 容器的关系。
嘉宾介绍:孙宏亮,硕士,浙江大学毕业,现为 DaoCloud 软件工程师,出版有《Docker 源码分析》,目前主要负责企业级容器云平台的研发工作。数年来一直从事云计算、PaaS 领域的研究与实践,是国内较早一批接触 Docker 的先行者,同时也是 Docker 技术的推广者。
第一部分:Docker 镜像的基本知识
1.1 什么是 Docker 镜像
从整体的角度来讲,一个完整的 Docker 镜像可以支撑一个 Docker 容器的运行,在 Docker 容器运行过程中主要提供文件系统视角。例如一个 ubuntu:14.04 的镜像,提供了一个基本的 ubuntu:14.04 的发行版,当然此镜像是不包含操作系统 Linux 内核的。
说到此,可能就需要注意一下,linux 内核和 ubuntu:14.04 Docker 镜像的区别了。传统虚拟机安装 ubuntu:14.04 会包含两部分,第一,某一个 Linux 内核的发行版本,比如 Linux 3.8 版本的内核;第二,第一个特定的 Ubuntu 发行版,这部分内容不包含 Linux 内核,但是包含 Linux 之外的软件管理方式,软件驱动,如 apt-get 软件管理包等。
理解以上内容之后,就可以理解,为什么在一个 Linux 内核版本为 3.8 的 ubuntu:14.04 基础上,可以把 Linux 内核版本升级到 3.18,而 ubuntu 的版本依然是 14.04。最主要的就是:Linux 内核版本与 ubuntu 操作系统发行版之间的区别。
Linux 内核+ubuntu 操作系统发行版,组成一台工作的机器让用户体验。那么灵活替换 ubuntu 操作系统发行版,那是不是也可以实现呢。那么 Docker 很方便的利用了这一点,技术手段就是 Docker 镜像。
Docker 的架构中,Docker 镜像就是类似于 “ubuntu 操作系统发行版”,可以在任何满足要求的 Linux 内核之上运行。简单一点有 “Debian 操作系统发行版” Docker 镜像、“Ubuntu 操作系统发行版” Docker镜像;如果在 Debian 镜像中安装 MySQL 5.6,那我们可以将其命名为 Mysql:5.6 镜像;如果在 Debian 镜像中安装有 Golang 1.3,那我们可以将其命名为 golang:1.3 镜像;以此类推,大家可以根据自己安装的软件,得到任何自己想要的镜像。
那么镜像最后的作用是什么呢?很好理解,回到 Linux 内核上来运行,通过镜像来运行时我们常常将提供的环境称为容器。
以上内容是从宏观的角度看看 Docker 镜像是什么,我们再从微观的角度进一步深入 Docker 镜像。刚才提到了“Debian 镜像中安装 MySQL 5.6,就成了 mysql:5.6 镜像”,其实在此时 Docker 镜像的层级概念就体现出来了。底层一个 Debian 操作系统镜像,上面叠加一个 mysql 层,就完成了一个 mysql 镜像的构建。层级概念就不难理解,此时我们一般 debian 操作系统镜像称为 mysql 镜像层的父镜像。
层级管理的方式大大便捷了 Docker 镜像的分发与存储。说到分发,大家自然会联想到 Docker 镜像的灵活性,传输的便捷性,以及高超的移植性。Docker Hub,作为全球的镜像仓库,作为 Docker 生态中的数据仓库,将全世界的 Docker 数据汇聚在一起,是 Docker 生态的命脉。
Docker 有两方面的技术非常重要,第一是 Linux 容器方面的技术,第二是 Docker 镜像的技术。从技术本身来讲,两者的可复制性很强,不存在绝对的技术难点,然而 Docker Hub 由于存在大量的数据的原因,导致 Docker Hub 的可复制性几乎不存在,这需要一个生态的营造。
1.2 Docker 镜像的内容
大致介绍了 Docker 镜像是什么,我们来看看 Docker 镜像中有哪些内容?
介绍之前,我先分享一下,我个人在接触 Docker 的两年时间中,对 Docker 镜像内容认识的变化。
第一阶段:初步接触 Docker。相信很多爱好者都会和我一样,有这样一个认识: Docker 镜像代表一个容器的文件系统内容。
第二阶段:初步接触联合文件系统。联合文件系统的概念,让我意识到镜像层级管理的技术,每一层镜像都是容器文件系统内容的一部分。
第三阶段:研究镜像与容器的关系:容器是一个动态的环境,每一层镜像中的文件属于静态内容,然而 Dockerfile 中的 ENV、VOLUME、CMD 等内容最终都需要落实到容器的运行环境中,而这些内容均不可能直接坐落到每一层镜像所包含的文件系统内容中,那此时每一个 Docker 镜像还会包含 json 文件记录与容器之间的关系。
因此,Docker 镜像的内容主要包含两个部分:第一,镜像层文件内容;第二,镜像 json 文件。
1.3 Docker 镜像存储位置
既然是说镜像存储的位置,那么应该包含:镜像层文件和镜像 json 文件。如一个 ubuntu:14.04 镜像,包含 4 个镜像层,在 aufs 存储驱动的情况下,在磁盘上的情况可以如以下图所示:
1.3.1 查看镜像层组成:
我们可以通过命令 docker history ubuntu:14.04 查看 ubuntu:14.04,结果如下:
1.3 Docker 镜像存储位置
既然是说镜像存储的位置,那么应该包含:镜像层文件和镜像 json 文件。如一个 ubuntu:14.04 镜像,包含 4 个镜像层,在 aufs 存储驱动的情况下,在磁盘上的情况可以如以下图所示:
1.3.1 查看镜像层组成:
我们可以通过命令 docker history ubuntu:14.04 查看 ubuntu:14.04,结果如下:
1.3.2 镜像层文件内容存储
Docker 镜像层的内容一般在 Docker 根目录的 aufs 路径下,为 /var/lib/docker/aufs/diff/,具体情况如下:
图中显示了镜像 ubuntu:14.04 的 4 个镜像层内容,以及每个镜像层内的一级目录情况。需要额外注意的是:镜像层 d2a0ecffe6fa 中没有任何内容,也就是所谓的空镜像。
1.3.3 镜像 json 文件存储
对于每一个镜像层,Docker 都会保存一份相应的 json 文件,json 文件的存储路径为 /var/lib/docker/graph,ubuntu:14.04 所有镜像层的 json 文件存储路径展示如下:
除了 json 文件,大家还看到每一个镜像层还包含一个 layersize 文件,该文件主要记录镜像层内部文件内容的总大小。既然谈到了镜像 json 文件,为了给下文铺垫,以下贴出 ubuntu:14.04 中空镜像层 d2a0ecffe6fa 的 json 文件:
Docker 镜像存储,就和大家一起先看到这。同时介绍 Docker 镜像的基本知识也告一段落。以下我们进入此次分享的第二部分。
第二部分 Dockerfile、Docker 镜像和 Docker 容器的关系
Dockerfile 是软件的原材料,Docker 镜像是软件的交付品,而 Docker 容器则可以认为是软件的运行态。从应用软件的角度来看,Dockerfile、Docker 镜像与 Docker 容器分别代表软件的三个不同阶段,Dockerfile 面向开发,Docker 镜像成为交付标准,Docker 容器则涉及部署与运维,三者缺一不可,合力充当 Docker 体系的基石。
简单来讲,Dockerfile构建出Docker镜像,通过Docker镜像运行Docker容器。
我们可以从Docker容器的角度,来反推三者的关系。首先可以来看下图:
我们假设这个容器的镜像通过以下 Dockerfile 构建而得:
FROM ubuntu:14.04
ADD run.sh /
VOLUME /data
CMD ["./run.sh"]
2.1 Dockerfile 与 Docker 镜像
首先,我们结合上图来看看 Dockerfile 与 Docker 镜像之间的关系。
FROM ubuntu:14.04:设置基础镜像,此时会使用基础镜像 ubuntu:14.04 的所有镜像层,为简单起见,图中将其作为一个整体展示。
ADD run.sh /:将 Dockerfile 所在目录的文件 run.sh 加至镜像的根目录,此时新一层的镜像只有一项内容,即根目录下的 run.sh。
VOLUME /data:设定镜像的 VOLUME,此 VOLUME 在容器内部的路径为 /data。需要注意的是,此时并未在新一层的镜像中添加任何文件,即构建出的磁层镜像中文件为空,但更新了镜像的 json 文件,以便通过此镜像启动容器时获取这方面的信息。
CMD [“./run.sh”]:设置镜像的默认执行入口,此命令同样不会在新建镜像中添加任何文件,仅仅在上一层镜像 json 文件的基础上更新新建镜像的 json 文件。
因此,通过以上分析,以上的Dockerfile可以构建出一个新的镜像,包含4个镜像层,每一条命令会和一个镜像层对应,镜像之间会存在父子关系。
图中很清楚的表明了这些关系。
2.2 Docker 镜像与 Docker 容器的关系
Docker 镜像是 Docker 容器运行的基础,没有 Docker 镜像,就不可能有 Docker 容器,这也是 Docker 的设计原则之一。
可以理解的是:Docker 镜像毕竟是镜像,属于静态的内容;而 Docker 容器就不一样了,容器属于动态的内容。动态的内容,大家很容易联想到进程,内存,CPU 等之类的东西。的确,Docker 容器作为动态的内容,都会包含这些。
为了便于理解,大家可以把 Docker 容器,理解为一个或多个运行进程,而这些运行进程将占有相应的内存,相应的 CPU 计算资源,相应的虚拟网络设备以及相应的文件系统资源。而 Docker 容器所占用的文件系统资源,则通过 Docker 镜像的镜像层文件来提供。
那么作为静态的镜像,如何才有能力转化为一个动态的 Docker 容器呢?此时,我们可以想象:第一,转化的依据是什么;第二,由谁来执行这个转化操作。
其实,转化的依据是每个镜像的 json 文件,Docker 可以通过解析 Docker 镜像的 json 的文件,获知应该在这个镜像之上运行什样的进程,应该为进程配置怎么样的环境变量,此时也就实现了静态向动态的转变。
谁来执行这个转化工作?答案是 Docker 守护进程。也许大家早就理解这样一句话: Docker 容器实质上就是一个或者多个进程,而容器的父进程就是 Docker 守护进程。这样的,转化工作的执行就不难理解了:Docker 守护进程手握 Docker 镜像的 json 文件,为容器配置相应的环境,并真正运行 Docker 镜像所指定的进程,完成 Docker 容器的真正创建。
Docker 容器运行起来之后,Docker 镜像 json 文件就失去作用了。此时 Docker 镜像的绝大部分作用就是:为 Docker 容器提供一个文件系统的视角,供容器内部的进程访问文件资源。
再次回到上图,我们再来看看容器和镜像之间的一些特殊关系。
首先,之前已经提及 Docker 镜像是分层管理的,管理 Docker 容器的时候,Docker 镜像仍然是分层管理的。由于此时动态的容器中已经存在进程,进程就会对文件系统视角内的文件进行读写操作,因此,就会涉及一个问题:容器是否会篡改 Docker 镜像的内容?
答案自然是不会的。统一来讲,正如上图,所有的Docker镜像层对于容器来说,都是只读的,容器对于文件的写操作绝对不会作用在镜像中。
既然如此,实现的原理就很重要,究其根本:Docker 守护进程会在 Docker 镜像的最上层之上,再添加一个可读写层,容器所有的写操作都会作用到这一层中。而如果 Docker 容器需要写底层 Docker 镜像中的文件,那么此时就会涉及一个叫 Copy-on-Write 的机制,即 aufs 等联合文件系统保证:首先将此文件从 Docker 镜像层中拷贝至最上层的可读写层,然后容器进程再对读写层中的副本进行写操纵。对于容器进程来讲,它只能看到最上层的文件。
那最后我们再来说说:Docker 容器的文件系统视角中,到底是不是存在一些内容,不是存储于 Docker 镜像中的?
这次的答案依旧是肯定的。
再次重申一点,Docker 镜像中存储的都是一些静态文件。这些文件原则上应该和容器具体信息以及主机信息完全解藕。那么 Docker 容器中不存在 Docker 镜像中的内容主要有以下几点:
- /proc 以及 /sys 等虚拟文件系统的内容
- 容器的 hosts 文件,hostname 文件以及 resolv.conf 文件,这些事具体环境的信息,原则上的确不应该被打入镜像。
- 容器的 Volume 路径,这部分的视角来源于从宿主机上挂载到容器内部的路径
- 部分的设备文件
更多阅读:
Docker镜像结构原理:https://blog.51cto.com/liuleis/2070461
Docker 创建镜像、修改、上传镜像:https://www.cnblogs.com/lsgxeva/p/8746644.html
深入分析 Docker 镜像原理的更多相关文章
- Docker镜像原理
⒈是什么? 镜像是一种轻量级.可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件,它包含运行某个软件所需的所有内容,包括代码.运行时.库.环境变量以及配置文件等. 引用 UnionFs( ...
- Docker镜像原理和最佳实践
https://yq.aliyun.com/articles/68477 https://yq.aliyun.com/articles/57126 DockerCon 2016 深度解读: Dock ...
- Docker基础修炼2--Docker镜像原理及常用命令
通过前文的讲解对Docker有了基本认识之后,我们开始进入实战操作,本文先演示Docker三要素之镜像原理和相关命令. 本文的演示环境仍然沿用上一篇文章在本地Centos7中安装的环境,如果你本地没有 ...
- Docker 学习3 Docker镜像管理基础
一.docker 常用操作及原理 1.docker 常用操作 2.docker 机制 1.docker client端是通过http或者https与server端通信的.个 2.docker 镜像可以 ...
- 004.Docker镜像管理
一 镜像基本操作 镜像是一个包含程序运行必要依赖环境和代码的只读文件,其本质是磁盘上一系列文件的集合.它采用分层的文件系统,将每一次改变以读写层的形式增加到原来的只读文件上.镜像是容器运行的基石. 1 ...
- docker运行原理与使用总结
docker运行原理概述 Client-Server架构 docker守护进程运行在宿主机上systemctl start docker daemon进程通过socket从客户端(docker命令)接 ...
- Docker镜像的实现原理
Docker 镜像是怎么实现增量的修改和维护的? 每个镜像都由很多层次构成,Docker 使用 Union FS 将这些不同的层结合到一个镜像中去. 通常 Union FS 有两个用途, 一方面可以实 ...
- docker 10 docker的镜像原理
镜像是什么? 镜像是一个轻量级,可执行的软件包,用来打包运行环境和基于运行环境开发的软件包,它包含某个软件运行环境的所有内容.包括代码,运行时的库,配置文件和环境变量 UnionFs(联合文件系统) ...
- docker学习笔记-03:docker的镜像原理
镜像是一种轻量级.可执行的独立软件包,用来打包软件运行环境和基于运行环境开发的软件.它包含运行某个环境所需的所有内容,包括代码.库.环境变量和配置文件. 一.镜像是什么 (一).联合文件系统(Unio ...
随机推荐
- 运行python程序不显示cmd方法
运行python程序不显示cmd方法 Pythonw xxx.py 将*.py改成*.pyw,然后执行*.pyw Python.exe和pythonw.exe不同: 执行时没有控制台窗口 所有向原有的 ...
- xiaopiu产品原型设计与团队实时协作平台
PRD文档创作 全新的文档创作模式,让交互原型与产品文档完美结合: 四大专业模板,满足多场景使用,快速输出专业规范的文档 PRD文档搜索 更专业.更精准的PRD文档垂直搜索服务,包含功能流程.协议条款 ...
- centos 设置dns
- Gitlab-Runner基础教程
一.Intro jenkins和runner,作为主流自动化运维工具来说,两者的大思路其实是一样的,就是将我们提交到代码仓库的代码拉到jenkins或者runner运行的机器里,然后执行一系列的命令( ...
- D3学习之坐标系绘制
坐标轴的绘制我们需要搞清楚以下三个要点: 1).axis函数 2)..call()函数用于组合 3).坐标轴的平移旋转 关于第三点其实就是"transform","tra ...
- babel-plugin-equire - 一个按需加载 echarts 模块的 babel 插件
参考链接:https://juejin.im/entry/5a1c1bc9f265da430d57bd3f?utm_medium=hao.caibaojian.com&utm_source=h ...
- Nginx的负载均衡和项目部署
nginx的作用 Nginx是一款自由的.开源的.高性能的HTTP服务器和反向代理服务器:同时也是一个IMAP.POP3.SMTP代理服务器:Nginx可以作为一个HTTP服务器进行网站的发布处理,另 ...
- JavaSE基础(三)--Java基础语法
Java 基础语法 一个 Java 程序可以认为是一系列对象的集合,而这些对象通过调用彼此的方法来协同工作.下面简要介绍下类.对象.方法和实例变量的概念. 对象:对象是类的一个实例,有状态和行为.例如 ...
- linux网络route
一.网络基础知识: 设备端获取的IP路由表 [root@HKVS /] # route –n Kernel IP routing table Destination Gateway ...
- java知识随笔整理-Oracle存储过程优缺点
优点: 1.存储过程可以使得程序执行效率更高.安全性更好. 2.建立过程不会很耗系统资源,因为过程只是在调用才执行. 3.存储过程可以用于降低网络流量,存储过程代码直接存储于数据库中,所以不会产生大量 ...