docker是包含三个重要概念的:
- 镜像(image)
- 容器(Container)
- Repository(仓库)
下面就分别说说这三个概念
镜像 Image
Docker的镜像是只读的模版,是由文件系统叠加而成的,最底端是一个引导文件系统,即bootfs,这很像典型的Linux、unix的因为文件系统。Docker用户几乎永远不会和引导文件系统有什么交互。实际上,当一个容器启动后,它将会被移植到内存中,而引导文件系统则会被卸载(umount),以留出更多的内存供initrd磁盘镜像使用。
so far,Docker看起来还像一个典型的Linux虚拟化栈。实际上,docker镜像的第二层是root文件系统rootfs,它位于引导文件系统纸上,rootfs可以是一种或者多种操作系统,如ubuntu。
在传统的linux引导过程中,root文件系统会最先以只读的方式挂载,当引导结束并完成了完整性检验后,它才会切换为读写模式。但是在Docker里面,root文件系统永远只读的,并且被Docker利用联合加载(union mount)技术又会在root文件系统层上加载更多的只读文件系统。联合加载指的是一次同时加载多个文件系统,但是外面看起来只能看到一个文件系统。联合加载会将各层文件系统叠加到一起,这样最终的文件系统会包含所有底层的文件和目录。
Docker将这样的文件系统成为镜像。一个镜像可以放到另一个镜像的顶部。位于下面的镜像称为父镜像(parent image),可以依此类推,直到镜像栈的最底部,最底部的镜像称为基础镜像(base Image)。最后,当从一个镜像启动容器时,Docker会在镜像的最顶层加载一个读写文件系统。我们想在docker中运行的程序就是在这个读写层中执行的。
如下图所示:
当Docker第一次启动一个容器的时候,初始的读写层是空的。当文件系统发生变化时,这些变化都会应用到这一层上。比如,如果想修改一个文件,这个文件首先会从读写层下面的只读层复制到该读写层。该文件的只读版本依然存在,但是已经被读写层中的该文件副本所隐藏。
通常这种机制称为写时复制(copy on write),这也是Docker如此强大的技术之一。每个只读镜像层都是只读的,并且以后永远不会变化。当创建一个新的容器,docker会构建出一个镜像栈,并在栈的最顶端添加一个读写层。这个读写层再加上其下面的镜像层以及一些配置数据,就构成了一个容器。每个容器是可以修改的,他们都有自己的状态,并且是可以启动和停止的。容器这种特点加上镜像分层框架(image-layering framework),使我们可以快速构建并运行包含我们自己的应用程序和服务的容器。
例如:一个镜像可以包含完整的ubuntu系统,里面仅安装了Apache或者其他的应用。
镜像可以用来创建 Docker 容器。
Docker 提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用。
容器Container
容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。
*注:镜像是只读的,容器在启动的时候创建一层可写层作为最上层。
仓库repository
仓库是集中存放镜像文件的场所。有时候会把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。
仓库分为公开仓库(Public)和私有仓库(Private)两种形式。
最大的公开仓库是 Docker Hub,存放了数量庞大的镜像供用户下载。 国内的公开仓库包括 Docker Pool等,可以提供大陆用户更稳定快速的访问。
当然,用户也可以在本地网络内创建一个私有仓库。
当用户创建了自己的镜像之后就可以使用 push 命令将它上传到公有或者私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上 pull 下来就可以了。
*注:Docker 仓库的概念跟 Git 类似,注册服务器可以理解为 GitHub 这样的托管服务。
镜像是构建Docker世界的基石,用户基于镜像来运行自己的容器。
镜像是基于联合文件系统的一种层式的结构,由一系统指令一步一步构建出来的。例如:
添加一个文件,执行一个命令,打开一个端口。
镜像是Docker 生命周期中的构建或打包阶段,而容器是启动或者执行阶段的。