Docker的核心知识只有3个:镜像、容器、仓库
掌握了这3个铁三角,也就掌握了Docker的核心,看似高深,读到最后它们三兄弟也就豪横不起来了。
Docker 镜像 Image
Docker镜像就相当于是一个 root 文件系统。比如官方镜像 ubuntu:18.04 就包含了完整的一套Ubuntu 18.04 最小系统的 root 文件系统。
Docker 镜像是一个特殊的文件系统,除了提供容器运行时所需的程序、库、资源、配置等文件外,还包含了一些为运行时准备的一些配置参数(如匿名卷、环境变量、用户等)。镜像不包含任何动态数据,其内容在构建之后也不会被改变。
Docker镜像的分层构建示意图
镜像构建时,采用分层存储,会一层层构建,前一层是后一层的基础。每一层构建完就不会再发生改变,后一层上的任何改变只发生在自己这一层。
举例解析(参照上图)
- 1层的centos是独立的镜像A
- 在A镜像的基础之上又要安装个JDK,因此叠加了2层镜像,那么1+2就形成了新的镜像B
- 在B镜像的基础之上又要安装个Tomcat,因此叠加了3层镜像,那么1+2+3就形成了新的镜像C
- 以此类推,所以镜像构建就像搭积木一样,底层是上层的基础
分层存储的特征还使得镜像的复用、定制变得更为容易。甚至可以用之前构建好的镜像作为基础层,然后进一步添加新的层,以定制自己所需的内容,构建新的镜像。
举例解析(参照上图)
- 将第1层的centos拿出来,再叠加一个nodejs,那么就形成了nodjs的运行环境镜像
- 将第1层的centos和第2层的jdk拿出来,再叠加上一个ActiveMQ镜像,就形成了全新的消息队列镜像。
- 这就是镜像分层的复用能力
Docker 容器 Container
镜像和容器的关系,就像是面向对象程序设计中的类和实例 一样,镜像是静态的定义,容器是镜像运行时的实体。容器可以被创建、启动、停止、删除等。
镜像和容器的关系,就好像类和实例之间的关系
如上图所示:一个镜像类可以new出来多个容器实例,容器实例可以创建、可以销毁。
容器的隔离运行机制,在沙箱里运行
容器的实质是进程,但与直接在宿主执行的进程不同,容器进程运行于属于自己的独立的命名空间(沙箱)。因此容器可以拥有自己的 root 文件系统、自己的网络配置、自己的进程空间,甚至自己的用户 ID 空间,达到极强的隔离性。
容器内的进程是运行在一个隔离的环境里,使用起来,就好像是在一个独立于宿主的系统下操作一样。这种特性使得容器封装的应用比直接在宿主运行更加安全。
Docker 仓库 Repository
一个集中的存储、分发镜像的服务。
Docker仓库的存储结构示意图
一个 Docker Registry(私服) 中可以包含多个仓库Repository;每个仓库可以包含多个标签Tag;每个标签对应一个镜像。
私服的概念在下一篇文章讲解,现在可以先不用理解
一个仓库会包含同一个软件不同版本的镜像,而标签就常用于对应该软件的各个版本。我们可以通过 : 的格式来指定具体是这个软件哪个版本的镜像。如果不给出标签,将以 latest 作为默认标签
举例解析(参照上图)
- jdk、kafka、mysql都存储在不同的仓库(Repository)中
- 每个仓库都有不同的版本(TAG),一个TAG对应一个真实的镜像
- 例如JDK有7、8版本,latest代表最新版本,对应的是3个镜像。
- 例如MySQL有6.0.1和7.0.9两个版本,对应的也是2个镜像。
Docker仓库-实例
举例解析(参照上图: 真实服务器截图)
使用docker images命令可以列出服务器上的所有镜像信息
java仓库有两个TAG,分别是7和8。代表着java7、java8两个版本的JDK镜像。
IMAGE_ID代表镜像的唯一ID,我们可以使用此ID将镜像从我们的本地仓库中删除(docker rmi IMAGE_ID命令)。
CREATED代表镜像的创建时间是在3年前
SIZE代表镜像的大小