一、docker镜像
1.1 广度
一个完整的Docker镜像可以支撑一个Docker容器的运行,在 Docker容器运行过程中主要提供文件系统视角。
例如一个ubuntu的镜像,提供了一个基本的ubuntu的发行版,当然此镜像是不包含操作系统Linux内核的。
linux内核和ubuntu的Docker镜像的区别
传统虚拟机安装ubuntu会包含两部分,第一,某一个Linux内核的发行版本,比如Linux 3.8版本的内核;第二,第一个特定的Ubuntu发行版,这部分内容不包含Linux内核,但是包含Linux之外的软件管理方式,软件驱动,如 apt-get软件管理包等。
理解以上内容之后,就可以理解,为什么在一个Linux内核版本为3.8的ubuntu基础上,可以把Linux内核版本升级到3.18,而ubuntu的版本依然不变。
Linux内核+ubuntu操作系统发行版,组成一台工作的机器。
Docker很方便的利用了这一点,可以灵活替换ubuntu操作系统发行版,技术手段就是Docker镜像。
Docker的架构中,Docker镜像就是类似于“ubuntu操作系统发行版”,可以在任何满足要求的Linux内核之上运行。简单一点有“Debian操作系统发行版”Docker镜像、“Ubuntu操作系统发行版”Docker镜 像;如果在Debian镜像中安装MySQL 5.7,那我们可以将其命名为Mysql:5.7镜像;如果在Debian镜像中安装有Golang 1.3,那我们可以将其命名为golang:1.3镜像;以此类推,大家可以根据自己安装的软件,得到任何自己想要的镜像。
镜像的作用:回到Linux内核上来运行,通过镜像来运行时我们常常将提供的环境称为容器。
1.2 精度
刚才提到了“Debian镜像中安装MySQL 5.7,就成了mysql:5.7镜像”,其实在此时Docker镜像的层级概念就体现出来了。底层一个Debian操作系统镜像,上面叠加一个 mysql层,就完成了一个mysql镜像的构建。层级概念就不难理解,此时我们一般debian操作系统镜像称为mysql镜像层的父镜像。
层级管理的方式大大便捷了Docker镜像的分发与存储。说到分发,大家自然会联想到 Docker镜像的灵活性,传输的便捷性,以及高超的移植性。Docker Hub,作为全球的镜像仓库,作为Docker生态中的数据仓库,将全世界的Docker数据汇聚在一起,是Docker生态的命脉。
Docker有两方面的技术非常重要,第一是Linux 容器方面的技术,第二是Docker镜像的技术。从技术本身来讲,两者的可复制性很强,不存在绝对的技术难点,然而Docker Hub由于存在大量的数据的原因,导致Docker Hub的可复制性几乎不存在,这需要一个生态的营造。
二、docker镜像内容
初步接触Docker。相信很多爱好者都会和我一样,有这样一个认识:Docker 镜像代表一个容器的文件系统内容;
初步接触联合文件系统。联合文件系统的概念,让我意识到镜像层级管理的技术,每一层镜像都是容器文件系统内容的一部分。
镜像与容器的关系:
容器是一个动态的环境,每一层镜像中的文件属于静态内容,然而 Dockerfile 中的 ENV、VOLUME、CMD等内容最终都需要落实到容器的运行环境中,而这些内容均不可能直接坐落到每一层镜像所包含的文件系统内容中,那此时每一个Docker镜像还会包含json文件记录与容器之间的关系。
因此,Docker镜像的内容主要包含两个部分:第一,镜像层文件内容;第二,镜像json文件。
三、docker镜像存储
3.1 查看镜像层组成
我们可以通过命令 docker history issa/myubuntu:1.12 查看 issa/myubuntu:1.12,结果如下:
3.2 镜像层文件内容存储和镜像 json 文件存储
四、docker镜像的运行原理
当我们在我启动一个容器的时候,docker会加载这些只读层并在这些只读层的上面(栈顶)增加一个读写层。这时如果修改正在运行的容器中已有的文件,那么这个文件将会从只读层复制到读写层。该文件的只读版本还在,只是被上面读写层的该文件的副本隐藏。当删除docker,或者重新启动时,之前的更改将会消失。
当一个容器启动后,它将会被移到内存中,而引导文件系统则会被卸载,以留出更多的内存供initrd磁盘镜像使用。
Docker镜像是由文件系统叠加而成,最低端是一个引导文件系统,即bootfs,典型的为Linux/Unix 的引导文件系统。bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统, 在Docker镜像的最底层是bootfs。 这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。
Docker镜像的第二层是root文件系统rootfs,位于引导文件系统之上,rootfs可以是一种或多种操作系统如ubuntu文件系统。在bootfs之上 。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。
Docker镜像是由多个文件系统(只读层)叠加而成。当我们启动一个容器的时候,Docker会加载只读镜像层并在其上(即镜像栈顶部)添加一个读写层。如果运行中的容器修改了现有的一个已经存在的文件,那该文件将会从读写层下面的只读层复制到读写层,该文件的只读版本仍然存在,只是已经被读写层中该文件的副本所隐藏。当删除Docker容器,并通过该镜像重新启动时,之前的更改将会丢失。在Docker中,只读层及在顶部的读写层的组合被称为Union File System(联合文件系统)。
联合文件系统是一种轻量级的高性能分层文件系统,它支持将文件系统中的修改信息作为一次提交,并层层叠加,同时可以将不同目录挂载在同一个虚拟文件系统下,应用看到的是挂载的最终结果。
平时我们安装进虚拟机的CentOS都是好几个G,为什么docker这里才200M?
对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供 rootfs 就行了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。
四、UnionFS(联合文件系统)
UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加, 同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
特性:一次同时加载多个文件系统,但从外面看起来,只能看到一个文件系统,联合加载会把各层文件系统叠加起来,这样最终的文件系统会包含所有底层的文件和目录
五、分层的镜像
以我们的pull为例,在下载的过程中我们可以看到docker的镜像好像是在一层一层的在下载 。
六、为什么 Docker 镜像要采用这种分层结构呢?
最大的一个好处就是 - 共享资源
比如:有多个镜像都从相同的 base 镜像构建而来,那么宿主机只需在磁盘上保存一份base镜像, 同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。
七、特点
Docker镜像都是只读的
当容器启动时,一个新的可写层被加载到镜像的顶部
这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”
八、Docker镜像commit操作
docker commit -m=“提交的描述信息” -a=“作者” 容器ID 要创建的目标镜像名:[标签名]
eg-1:
1.从Hub上下载ubuntu镜像到本地并成功运行docker run -it ubuntu
2.安装vim
apt-get -y install vim
3.vim test.txt
4.docker commit -m=“add vim” -a=“issavior” d50d5a500ed0 issa/myubuntu:1.12
eg-2:
- 从Hub上下载tomcat镜像到本地并成功运行docker run -it -p 8080:8080 tomcat
- 故意删除上一步镜像生产tomcat容器的文档
- 也即当前的tomcat运行实例是一个没有文档内容的容器,以它为模板commit一个没有doc的tomcat新镜像
- 启动我们的新镜像并和原来的对比
九、QA
1.问:为什么一个ubuntu:14.04镜像的镜像层的数量是4个,前三层的内容似乎有相同的,如etc?
这一点,细心的大家肯定发现了。首先,虽然三层都有,但是会存在两种情况,etc的子目录下有相同路径的文件,那么上层的会覆盖下层的文件;如果内部的文件路径不相同,那么都会存在,都会呈现给最上 层。[可别较真,说目录也是文件哈,意会]
2.问:关于docker安全性问题,对于安全是怎样处理的,如果我从hub下载镜像,能判别是否安全么?层级之间的依赖会导致一个崩了整个docker 都崩了么?
从流程上来讲,如果一切可控的话,我认为是安全的。但是依然会存在一些隐患,比如Dockerfile中基于的base images是否完全受信;镜像的传输过程是否受信;自己的private docker resgitry的安全级别达到什么样的层次,这些都有影响。
3.问:如何保证仅有的一个deamon的稳定性健壮性?
这个问题首先需要知道docker daemon的稳定性在哪些方面,那种场景下比较差?的确,docker daemon存在弊病。比如,daemon和容器的耦合等,目前general来讲,docker daemon保证绝对的稳定应该还做不到。
4.问:生产环境中怎么用docker备份mysql数据?
数据存储上docker,我目前的建议是:三思。举个简单的例子,官方的mysql镜像运行出来的 容器,密码是明文的,明文的密码存在于:docker inspect container_name, container.json文件中,容器的环境变量中,甚至在日志文件中都会存在,just think about it。当然也有办法解决,缓解这种情况。
5.问:如果是多层构建,中间的一个层做了升级或者bugfix,会潜在影响上层吧?
这个bugfix会在上层有体现,但是使用效果是不会有影响的,还有之前的bug会永远留在下层,但是没有影响。