Docker镜像vs容器

Docker镜像和容器如何不同?

当使用docker时,我们从一个基础图像开始。 我们启动它,创build更改,并将这些更改保存在形成另一个图像的图层中。

所以最终我有一个Postgres的图像和一个我的web应用程序的图像,其中的变化持续存在。

所以问题是:什么是容器?

图像的一个实例称为容器。 你有一个图像,这是你描述的一组图层。 如果你启动这个图像,你有一个这个图像的运行容器。 您可以拥有许多相同图像的正在运行的容器。

你可以看到你所有的图像与docker images而你可以看到你的运行容器与docker ps (你可以看到所有与docker ps -a容器)。

所以一个图像的运行实例就是一个容器。

从我的关于自动化Docker部署的文章:

Docker图像与容器

在Dockerland,有图像 ,有容器 。 这两者密切相关,但截然不同。 对我来说,抓住这个二分法已经非常清楚地说明了Docker。

什么是图像?

图像是一个惰性的,不可变的文件,基本上是一个容器的快照。 图像是使用build命令创build的,并且在运行时会产生一个容器。 图像存储在Dockerregistry(如registry.hub.docker.com)中 。 因为它们可能变得相当大,所以图像被devise为由其他图像层组成,从而允许在networking上传输图像时发送相当数量的数据。

本地映像可以通过运行docker images来列出:

 REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE ubuntu 13.10 5e019ab7bf6d 2 months ago 180 MB ubuntu 14.04 99ec81b80c55 2 months ago 266 MB ubuntu latest 99ec81b80c55 2 months ago 266 MB ubuntu trusty 99ec81b80c55 2 months ago 266 MB <none> <none> 4ab0d9120985 3 months ago 486.5 MB 

有些事情要注意:

  1. 图像ID是图像真实标识符的前12个字符。 你可以创build一个给定的图像的许多标签,但他们的ID都将是相同的(如上)。
  2. VIRTUAL SIZE是虚拟的,因为它将所有不同底层的大小相加。 这意味着该列中所有值的总和可能远大于所有这些映像使用的磁盘空间。
  3. REPOSITORY列中的值来自docker build命令的-t标志,或来自docker tag现有图像。 您可以使用一个对您有意义的术语来自由标记图像,但是要知道,docker会将该标记用作docker pushdocker pull的registry位置。
  4. 标签的完整forms是[REGISTRYHOST/][USERNAME/]NAME[:TAG] 。 对于上面的ubuntu ,REGISTRYHOST被推断为registry.hub.docker.com 。 因此,如果您打算将名为my-application图像存储在docker.example.com的registry中,则应该为该图像docker.example.com/my-application标签docker.example.com/my-application
  5. TAG列只是完整标签的[:TAG]部分。 这是不幸的术语。
  6. latest标签并不神奇,只是您不指定标签时的默认标签。
  7. 您可以使用未标记的图片只能通过其图片ID进行识别。 这些将得到<none>标签和贮藏室。 忘记它们很容易。

有关图像的更多信息,请参阅Docker文档和术语表 。

什么是容器?

要使用编程隐喻,如果一个图像是一个类,那么容器就是一个类的实例 – 一个运行时对象。 容器希望你为什么使用Docker; 它们是运行应用程序的环境的轻量级和便携式封装。

使用docker ps查看本地运行容器:

 CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f2ff1af05450 samalba/docker-registry:latest /bin/sh -c 'exec doc 4 months ago Up 12 weeks 0.0.0.0:5000->5000/tcp docker-registry 

在这里,我运行dockerregistry的dockerized版本,以便我有一个私人的地方来存储我的图像。 再次,有些事情要注意:

  1. 像IMAGE ID一样,CONTAINER ID是容器的真实标识符。 它具有相同的forms,但它确定了一种不同的对象。
  2. docker ps只输出正在运行的容器。 您可以使用docker ps -a查看所有容器( 正在运行或已停止 )。
  3. 可以使用NAME标识通过--name标识来标识启动的容器。

如何避免图像和容器堆积?

Docker早期的一个挫折就是看起来不断地堆积着未标记的图像,并停止了容器 。 在less数时间,这种累积导致硬盘驱动器放慢我的笔记本电脑或停止我的自动生成pipe道。 谈论“集装箱到处”!

我们可以通过将docker rmi与最近的dangling=true查询结合来删除所有未标记的图像:

docker images -q --filter "dangling=true" | xargs docker rmi

Docker将无法移除现有容器背后的图像,因此您可能必须先使用docker rm移除停止的容器:

 docker rm `docker ps --no-trunc -aq` 

这些是Docker 已知的难点,可能在未来的版本中得到解决。 但是,在对图像和容器有清晰的了解的情况下,可以通过一些实践来避免这些情况:

  1. 总是用docker rm [CONTAINER_ID]移除一个无用的停止的容器。
  2. 始终使用docker rmi [IMAGE_ID]删除无用的已停止容器后面的图像。

尽pipe将容器想象成运行图像是最简单的,但这并不准确。

图像实际上是一个可以变成容器的模板。 为了把一个镜像转换成一个容器,Docker引擎将获取镜像,在其上添加一个读写文件系统,并初始化各种设置,包括networking端口,容器名称,ID和资源限制。 正在运行的容器有一个当前正在执行的进程,但容器也可以被停止(或以Docker的术语退出 )。 退出的容器与图像不同,因为它可以重新启动并保留其设置和任何文件系统更改。

也许解释整个工作stream程可以帮助。

一切都从Dockerfile开始。 Dockerfile是图像的源代码。

一旦Dockerfile被创build,你就build立它来创build容器的图像 。 该图像就是Dockerfile的“源代码”的“编译版本”。

一旦你有容器的图像,你应该使用registry重新分配它。 registry就像一个git仓库 – 你可以推拉图像。

接下来,您可以使用图像来运行容器 。 正在运行的容器在很多方面与虚拟机非常相似(但没有虚拟机pipe理程序 )。

这篇文章解释了许多有关Docker容器的基本知识(它是在谈论Docker和Puppet,但是有许多概念可以在任何情况下使用)

docker工人的核心概念是使创build“机器”变得容易,在这种情况下,可以将其视为容器。 容器有助于重复使用,让您轻松创build和放置容器。

图像描绘了每个时间点的容器状态。 所以基本的工作stream程是:

  1. 创build一个图像
  2. 启动一个容器
  3. 对容器进行更改
  4. 将容器保存为图像

一个容器只是一个可执行的二进制文件,由主机操作系统在一组限制条件下运行,这些限制条件是通过一个应用程序(例如docker)预先知道如何告诉操作系统应用哪些限制。

典型的限制是与进程隔离相关的,与安全相关的(如使用SELinux保护)和与系统资源相关的(内存,磁盘,CPU,networking)。

直到最近,只有基于Unix系统的内核才支持在严格限制下运行可执行文件的能力。 这就是为什么今天大多数容器谈话主要涉及Linux或其他Unix发行版。

Docker是知道如何告诉操作系统(主要是Linux)运行一个可执行文件的限制的应用程序之一。 可执行文件包含在Docker镜像中,它只是一个tar文件。 该可执行文件通常是一个精简版的Linux发行版(Ubuntu,Centos,Debian等),预先configuration为在其中运行一个或多个应用程序。

尽pipe大多数人使用Linux基础作为可执行文件,但只要主机操作系统可以运行,它也可以是任何其他二进制应用程序。 (请参阅使用scratch创build一个简单的基本图像 )。 docker映像中的二进制文件是操作系统还是简单的应用程序,到OS主机,这只是另一个进程,一个包含预设操作系统边界的进程。

像Docker这样的其他应用程序可以告诉主机操作系统在运行时应用哪个边界包括LXC , libvirt和systemd 。 Docker曾经使用这些应用程序间接地与Linux操作系统进行交互,但是现在Docker使用自己的名为“ libcontainer ”的库直接与Linux进行交互。

所以容器只是一个运行在限制模式下的进程,类似于chroot所做的。

IMO将Docker与其他容器技术区别开来是它的存储库(Docker Hub)和它们的pipe理工具,这使得容器工作非常容易。

请参阅https://en.m.wikipedia.org/wiki/Docker_(Linux_container_engine);

我不明白图像和图层的概念,尽pipe在这里阅读所有的问题,然后最终偶然发现了这个优秀的文件从docker (杜!)。

这个例子实际上是理解整个概念的关键。 这是一个冗长的文章,所以我总结了需要真正掌握的关键点,以便弄清楚。

  • 图片 :Docker镜像是由一系列只读图层构build而成的

  • 图层 :每个图层代表图像的Dockerfile中的指令。

Example :下面的Dockerfile包含四个命令,每个命令创build一个图层。

从ubuntu:15.04

COPY。 /应用

RUN make / app

CMD python /app/app.py

重要的是 ,每一层只是一个与之前的层的差异。

  • 容器 。 当你创build一个新的容器时, 你在底层上添加一个新的可写层 。 这个层通常被称为“容器层”。 对正在运行的容器所做的所有更改(如写入新文件,修改现有文件和删除文件)都将写入此可写容器层。

因此,容器和图像之间的主要区别是最高的可写层 。 所有写入到添加新的或修改现有数据的容器的操作都存储在这个可写入的层中。 当容器被删除时,可写层也被删除。 底层的图像保持不变。

从磁盘透视图的大小了解图像和容器

要查看正在运行的容器的大小,可以使用docker ps -s命令。 你得到sizevirtual size作为两个输出

  • 大小:用于每个容器的可写层的数据量(在磁盘上)

  • 虚拟大小:用于容器使用的只读图像数据的数据量。 多个容器可能共享部分或全部只读图像数据。 因此这些不是附加的。 即不能添加所有虚拟大小来计算图像使用的磁盘大小

另一个重要的概念是写入策略复制(Copy on Write Strategy)如果文件或目录存在于映像中的较低层,而另一层(包括可写入层)需要对其进行读取访问,则只使用现有文件。 第一次需要修改文件(当构build图像或运行容器时),文件被复制到该图层并修改。

希望能帮助像我这样的其他人。

这是端到端的工作stream程,显示各种命令及其相关的input和输出。 这应该澄清图像和容器之间的关系。

 +------------+ docker build +--------------+ docker run -dt +-----------+ docker exec -it +------+ | Dockerfile | --------------> | Image | ---------------> | Container | -----------------> | Bash | +------------+ +--------------+ +-----------+ +------+ ^ | docker pull | +--------------+ | Registry | +--------------+ 

要列出您可以运行的图像,请执行:

 docker image ls 

要列出容器,您可以在其上执行命令:

 docker ps 

Dockerfile >(Build)> Image >(Run)> Container

  • Dockerfile :包含一套docker指令,可以按照自己喜欢的方式configuration您的操作系统,并安装/configuration您的所有软件。

  • Image :编译Dockerfile。 每次需要运行容器时,都可以节省重buildDockerfile的时间。 这是隐藏您的预设代码的一种方法。

  • 容器 :虚拟操作系统本身,你可以ssh进入它并运行任何你想要的命令,就好像它是一个真实的环境。 您可以从相同的图像运行1000多个容器。

这很直。

(为了更深的理解,请阅读。 )

图像

用于创build容器的我们的应用程序的文件系统和configuration。

集装箱

运行Docker镜像的实例 – 容器运行实际的应用程序。 一个容器包含一个应用程序及其所有依赖项。 它与其他容器共享内核,并在主机操作系统的用户空间中作为隔离进程运行。

Docker守护进程

运行在主机上的后台服务,用于pipe理构build,运行和分发Docker容器。

Docker客户端

命令行工具,允许用户与Docker守护进程进行交互。

Docker商店

除其他外,Store是Docker映像的registry。 您可以将registry视为所有可用Docker镜像的目录。

这个stream程将帮助你更好地理解它。 在这里输入图像说明

Docker镜像打包了应用程序运行所需的应用程序和环境,一个容器是图像的运行实例。

图像是docker的包装部分,类似于“源代码”或“程序”。 容器是docker的执行部分,类似于“过程”。

在这个问题中,只有“程序”部分被引用,这就是图像。 docker的“运行”部分是容器。 当容器运行并进行更改时,就好像该进程对自己的源代码进行更改并将其另存为新映像。

简单地说,如果Image是一个Class ,那么Container就是一个Class的实例 – 一个运行时对象。

就像在编程方面一样,

图像是一个源代码。

源代码被编译和构build时,它被称为应用程序。

Simillar对“为图像创build实例时”,它被称为“ Container

Dockerfile就像你的bash脚本,它产生了一个tarball(Docker镜像)。

Docker容器就像tarball的提取版本。 您可以在不同的文件夹(容器)中拥有尽可能多的副本,

简而言之:

容器是内核中的一个部门(虚拟),共享公共操作系统并运行映像(Docker映像)。

一个容器是一个自我可持续的应用程序,将有包和所有必要的依赖关系一起运行的代码。