Docker映像和容器之间有什么区别?


921

使用Docker时,我们从基础映像开始。我们启动它,创建更改,然后将这些更改保存在形成另一个映像的层中。

因此,最终我为自己的PostgreSQL实例提供了一个映像,为我的Web应用程序提供了一个映像,对这些更改的更改将继续保留。

什么是容器?

Answers:


1239

图像的实例称为容器。您有一张图像,该图像是您描述的一组图层。如果启动此映像,则该映像具有正在运行的容器。您可以有多个运行相同图像的容器。

您可以使用来查看所有图像,docker images而可以使用来查看正在运行的容器docker ps(并且可以使用来查看所有容器docker ps -a)。

因此,映像的运行实例是一个容器。


106
那么,图像和停止的容器之间有什么区别?
Victor Dombrovsky

341
图像是食谱,容器是蛋糕;-)您可以使用给定的食谱制作任意数量的蛋糕
Julien

142
@VictorDombrovsky停止的容器是冰箱中的一块蛋糕。
雅各布·福特

44
@Julien如果图像是配方,那么Doc​​kerfile呢?:)
约翰尼·威勒

71
@JohnnyWiller类比有其局限性,但也许我们可以看到Dockerfile是您的购物清单;-)。否则将Dockerfile称为配方,图像模具,容器仍是美味蛋糕
朱利安

585

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

Docker映像与容器

在Dockerland中,有图像并且有容器。两者密切相关,但又截然不同。对我而言,掌握这一二分法极大地阐明了Docker。

什么是图片?

图像是惰性的,不可变的文件,本质上是容器的快照。图像是使用build命令创建的,并且从run开始会生成一个容器。图像存储在Docker注册表中,例如Registry.hub.docker.com。由于图像可能会变得很大,因此图像被设计为由其他图像层组成,从而在通过网络传输图像时允许发送最少量的数据。

可以通过运行列出本地图像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. IMAGE ID是图像的真实标识符的前12个字符。您可以为给定图像创建许多标签,但它们的ID都相同(如上所述)。
  2. 虚拟尺寸为 虚拟的,因为它累加了所有不同底层的大小。这意味着该列中所有值的总和可能比所有这些映像使用的磁盘空间大得多。
  3. REPOSITORY列中的值来自命令的-t标志docker build,或来自docker tag-ing现有图像。您可以使用对您有意义的命名法来随意标记图像,但是您知道Docker将在服务器中使用标记作为注册表位置。docker push或中docker pull
  4. 标签的完整格式为[REGISTRYHOST/][USERNAME/]NAME[:TAG]。对于ubuntu上述情况,REGISTRYHOST推断为registry.hub.docker.com。因此,如果您打算将映像存储my-application在注册表中docker.example.com,则应标记该映像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

在这里,我正在运行docker注册表的dockerized版本,以便我有一个私人位置来存储我的图像。同样,需要注意一些事项:

  1. 与IMAGE ID相似,CONTAINER ID是容器的真实标识符。它具有相同的形式,但是它标识不同种类的对象。
  2. docker ps仅输出运行中的容器。您可以使用来查看所有容器(正在运行或已停止docker ps -a
  3. NAMES可以通过该--name标志用于标识已启动的容器。

如何避免图像和容器堆积

我对Docker的早期挫败之一是看似不间断的未标记映像和停止的容器的堆积。在少数情况下,这种堆积会导致硬盘驱动器用尽,从而减慢我的笔记本电脑速度或停止自动构建流程。谈论“无处不在的容器”!

我们可以结合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]

5
良好的区分图像和容器。对像我这样的初学者有很大帮助。
Gibbs 2014年

2
我猜我坚持的是图像的运行方式(我在Windows上使用boot2docker)。为什么我们要为应用程序创建映像,例如mysql?此时,mysql甚至如何运行?我不需要Linux映像才能在上面运行mysql吗?
肯尼·沃登

实际上,这是不正确的:“泊坞窗拉出一个图像的:latest标签会将至少两个图像添加到本地图像列表中:一个带有最新标签,一个用于最新图像的每个原始标签,例如14.04。并尝试以上。” 只会添加一张带有最新标签的图像。如果映像ID相同,则稍后再拉14.04可能是禁止操作,但仍然需要单独拉。
阿德里安·穆阿特

4
在较新版本的Docker中,您可以docker image prune用来清理悬空的图像。修剪未使用的Docker对象
Dario Seidl

3
我只是docker system prune用来清洁一切
拉米·阿洛什

137

简单来说。

图片 -

用于创建容器的文件系统和配置(只读)应用程序。更多细节

容器 -

这些正在运行的Docker映像实例。容器运行实际的应用程序。容器包含一个应用程序及其所有依赖项。它与其他容器共享内核,并在主机OS上的用户空间中作为隔离进程运行。更多细节


其他重要注意事项:


Docker守护程序 -

在管理构建,运行和分发Docker容器的主机上运行的后台服务。

Docker客户端 -

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

Docker商店 -

除其他事项外,Store是Docker映像的注册表。您可以将注册表视为所有可用Docker映像的目录。

这篇博客文章的图片值得一千个字。

在此处输入图片说明

(如需进一步了解,请阅读此内容。)

摘要:

  • 从Docker集线器拉映像或从Dockerfile构建=>提供Docker映像(不可编辑)。
  • 运行图像(docker run image_name:tag_name)=>给出运行的图像,即容器(可编辑)

1
谢谢。图的来源是什么?是来自Docker的官方文件吗?

发布的图像太棒了。我关心的一个问题是:您说“在阅读某篇文章时发现了它”-如果不是您的图表,则在道德上重要[并且在法律上必须]注明应有的信誉(“属性”):原始图像作者是WHO?最初在什么URL找到?
制造商

@ToolmakerSteve感谢您的提示,我会紧记并在找到源后立即更新答案。
Imran Ahmad

126

虽然将容器视为运行中的映像是最简单的,但这并不完全准确。

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


如何在不运行图像的情况下将其转换为容器?
Janus Troelsen

12
@JanusTroelsen使用docker create
阿德里安·穆阿特

这有点令人困惑。我们说图像是不可变的,但是当作为容器运行时,它会将您所做的任何更改存储到可变的顶层。但是当停止时,这些更改是否会另存为图像中的新层?如果是,那么由于原始图像应该是不变的,那怎么可能呢?
Dchucks

4
OK,做了一些阅读,并在此线程本身中得到了答案。“当删除容器时,可写层也会被删除。基础图像保持不变。”
Dchucks

很有帮助的答复。我以前很困惑。如果我对图像进行DL处理,则将其作为容器运行,在该容器中放置一个随机文本文件,然后停止该容器,该文本文件位于已停止的容器中,而不是我下载的基本图像。
詹姆斯·艾伦

89

也许解释整个工作流程会有所帮助。

一切都始于Dockerfile。Dockerfile是映像的源代码。

创建Dockerfile后,您将其构建以创建映像容器。该图像只是“源代码”(即Dockerfile)的“编译版本”。

有了容器的映像后,应使用注册表重新分配它。注册表就像一个Git存储库-您可以推送和拉取图像。

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


44

工作流程

这是显示各种命令及其相关输入和输出的端到端工作流程。那应该阐明图像和容器之间的关系。

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

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

docker image ls

要列出容器,您可以在以下位置执行命令:

docker ps

1
有关更全面的工作流图,请参见:stackoverflow.com/a/46528745/714112
Sridhar Sarnobat

1
但是在ASCII语言中所需的滚动是一个问题。
彼得·莫滕森

可以改用Unicode来获得更好看的框。在线工具是Javascript Box Drawing Demo
彼得·莫滕森

40

尽管阅读了这里的所有问题,但我还是无法理解图像图层的概念,然后最终偶然发现了Docker的出色文档documentation!)。

这个例子确实是理解整个概念的关键。这是一篇冗长的文章,所以我在总结一些要清楚地理解的关键点。

  • 图像:Docker图像由一系列只读层构建而成

  • :每层代表映像的Dockerfile中的一条指令。

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

来自ubuntu:15.04

复制。/ app

运行make / app

CMD python /app/app.py

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

  • 货柜。创建新容器时,可以在基础层之上添加新的可写层。该层通常称为“容器层”。对运行中的容器所做的所有更改(例如写入新文件,修改现有文件和删除文件)都将写入此可写容器层。

因此,容器和图像之间的主要区别是可写顶层。在容器中添加新数据或修改现有数据的所有写操作都存储在此可写层中。删除容器后,可写层也会被删除。基础图像保持不变。

从磁盘大小的角度了解映像cnd容器

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

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

  • 虚拟大小:用于容器使用的只读图像数据的数据量。多个容器可以共享部分或全部只读图像数据。因此,这些不是累加的。也就是说,您无法添加所有虚拟大小来计算映像使用了多少磁盘空间

另一个重要概念是写时复制策略

如果文件或目录位于映像的较低层中,而另一层(包括可写层)需要对其进行读取访问,则它仅使用现有文件。另一层第一次需要修改文件时(在构建映像或运行容器时),将文件复制到该层并进行修改。

希望对我这样的人有帮助。


1
感谢您的评论,它确认了大小和虚拟大小之间的区别,并且对于共享相同只读数据的多个容器来说,这非常令人着迷,并且可以增加磁盘空间。
user1842947

34

Dockerfile →(构建)→ 图像 →(运行)→ 容器

  • Dockerfile:包含一组Docker指令,它们以您喜欢的方式配置您的操作系统,并安装/配置所有软件。

  • 图片:已编译的Dockerfile。每次需要运行容器时,都可以节省重建Dockerfile的时间。这是一种隐藏您的供应代码的方法。

  • 容器:虚拟操作系统本身。您可以将其放入ssh并运行所需的任何命令,就好像它是一个真实的环境一样。您可以从同一映像运行1000多个容器。


打个比方。如果我能给你1000个大拇指,我会的。
Rich Lysakowski博士

16

简而言之,如果图像,则容器是类的实例,是运行时对象


13

容器只是可执行的二进制文件,将由主机OS在一组限制下运行,这些限制是使用应用程序(例如Docker)预先设置的,该应用程序知道如何告诉OS应用哪些限制。

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

直到最近,只有基于Unix的系统中的内核才支持在严格限制下运行可执行文件的功能。这就是为什么当今大多数容器讨论都涉及Linux或其他Unix发行版的原因。

Docker是知道如何告诉OS(主要是Linux)如何在其下运行可执行文件的限制的那些应用程序之一。可执行文件包含在Docker映像中,它只是一个tarfile。该可执行文件通常是Linux发行版(Ubuntu,CentOS,Debian等)的精简版,已预先配置为在其中运行一个或多个应用程序。

尽管大多数人使用Linux基础作为可执行文件,但只要主机OS可以运行它,它就可以是任何其他二进制应用程序(请参阅使用草稿创建简单的基础映像)。Docker映像中的二进制文件是操作系统还是简单的应用程序,对于OS主机而言,它只是另一个进程,其中包含的进程由预设的OS边界决定。

诸如Docker之类的其他应用程序可以告诉主机OS在其运行时将哪些边界应用于该进程,包括LXClibvirtsystemd。Docker曾经使用这些应用程序与Linux OS进行间接交互,但是现在Docker使用自己的名为“ libcontainer ” 的库直接与Linux交互。

因此,容器只是在受限模式下运行的进程,类似于chroot过去所做的事情。

IMO,使Docker与任何其他容器技术区分开来的是它的存储库(Docker Hub)及其管理工具,这使使用容器变得非常容易。

请参阅Docker(软件)


12

Docker的核心概念是简化创建“机器”的过程,在这种情况下可以将其视为容器。容器有助于重用性,使您可以轻松地创建和删除容器。

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

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

8

许多答案指出了这一点:您构建 Dockerfile来获取映像,然后运行 image来获取容器

但是,以下步骤有助于我更好地了解什么是Docker映像和容器:

1)构建Dockerfile:

docker build -t my_image dir_with_dockerfile

2)将图像保存到.tar文件

docker save -o my_file.tar my_image_id

my_file.tar将存储图像。使用打开它tar -xvf my_file.tar,您将看到所有图层。如果您更深入地研究每一层,则可以看到在每一层中添加了哪些更改。(它们应该非常接近Dockerfile中的命令)。

3)要查看容器内部,您可以执行以下操作:

sudo docker run -it my_image bash

您会发现它非常像一个操作系统。



4

我认为最好在开始时进行解释。

假设您运行命令docker run hello-world。怎么了?

它调用Docker CLI,后者负责接收Docker命令并转换为调用Docker服务器命令。Docker服务器一旦获得运行映像的命令,就会检查映像缓存中是否包含具有该名称的映像

假设hello-world不存在。Docker服务器转到Docker Hub(Docker Hub只是一个免费的映像存储库),问,嘿,Hub,您是否有一个名为的映像hello-world?集线器响应-是的,我愿意。然后把它给我。然后下载过程开始。一旦泊坞窗图像被下载,在泊坞服务器把它的图像缓存

因此,在解释什么是Docker映像和Docker容器之前,我们先介绍一下计算机上的操作系统及其运行软件的方式。

例如,当您在计算机上运行Chrome时,它会调用操作系统,操作系统本身会调用内核并询问,嘿,我想运行此程序。内核设法从硬盘上运行文件。

现在,假设您有两个程序,Chrome和Node.js。Chrome需要运行Python 2版本,而Node.js需要运行Python 3版本。如果您仅在计算机上安装了Python v2,则将仅运行Chrome。

为了使两种情况都起作用,您需要以某种方式使用称为命名空间的操作系统功能。命名空间是一项功能,使您有机会隔离进程,硬盘驱动器,网络,用户,主机名等。

因此,当我们谈论映像时,实际上是在谈论文件系统快照。的图像是包含方向和元数据,以建立一个特定的物理文件容器。的容器本身是一个实例图像 ; 它使用命名空间隔离硬盘驱动器,该命名空间仅可用于此容器。因此,容器是对分配给它的不同资源进行分组的一个或一组过程。


3

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

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

在问题中,仅提及“程序”部分,这就是图像。Docker的“运行”部分是容器。运行容器并进行更改时,就好像该过程在其自己的源代码中进行了更改并将其保存为新映像一样。


3

与编程方面一样,

图像是源代码。

源代码被编译和构建,它被称为一个应用程序。

类似于“为图像创建实例时”,它称为“ 容器 ”。


1
Dockerfile就像源代码一样。源代码经过编译/构建后,图像就像可执行文件。容器就像从可执行文件运行的应用程序。
ejlp12

图片不是容器的源代码。dockerfile是该类的元类或规范。图像是容器的类或模板,而容器是该类的实例。容器是运行的实例。您可以拥有一个类的1000个实例。映像就像已编译的目标代码,可以链接到另一个程序并作为该程序的一部分运行。
Rich Lysakowski博士

3

一个图像是一个的“快照” 容器。您可以从容器制作图像(新的“快照”),也可以从图像启动新容器(实例化“快照”)。

例如,您可以从基础映像实例化一个新容器,在容器中运行一些命令,然后将其快照为新映像。然后,您可以从该新映像运行100个容器。

要考虑的其他事项:

  • 图像由图层组成,并且图层是快照“差异”(因此,当您推送图像时,只需将“差异”发送到注册表)。
  • Dockerfile在基本映像的顶部定义了一些命令,这些命令创建了新层(“差异”),从而产生了新映像(“快照”)。
  • 图像标签不仅是标签。它们是图像的“全名”(“ repository:tag”)。如果同一张图片有多个名称,则在执行时会显示多次docker images

这个答案倒退了。容器是图像的实例或图像的可执行快照。由于图像是实例的父类,因此不会直接执行。实例(容器)是父母的孩子(配方或模板制作的实例。)
富Lysakowski博士

该答案在流程结束时开始。可以将新图像作为容器的快照,但是所有容器都必须具有父图像。在这种情况下,这里没有鸡和蛋的问题,因为必须首先从Dockerfile构建第一个原始映像。首先是Dockerfile,然后是Image,然后是Container。容器可以用作新图像的基础,但是该容器必须具有“父图像”。
Rich Lysakowski博士

3

我想填充介于docker images和之间的缺失部分containersDocker对容器使用联合文件系统UFS),该文件系统允许将多个文件系统安装在层次结构中并显示为单个文件系统。映像中的文件系统已作为一个read-only层安装,对运行中的容器所做的任何更改都将read-write安装在此之上。因此,Docker只需查看最顶层的读写层即可找到对运行中的系统所做的更改。


1

对于虚拟编程类比,您可以想到Docker有一个抽象的ImageFactory,其中包含来自商店的 ImageFactory 。

然后,一旦您要使用该ImageFactory创建应用程序,您将拥有一个新容器,您可以根据需要对其进行修改。DotNetImageFactory将是不可变的,因为它充当抽象工厂类,仅在其中提供您所需的实例。

IContainer newDotNetApp = ImageFactory.DotNetImageFactory.CreateNew(appOptions);
newDotNetApp.ChangeDescription("I am making changes on this instance");
newDotNetApp.Run();



1

图像是作为对象容器的类。

容器是图像的实例,而对象是类的实例。


1

Dockerfile就像您的Bash脚本一样,生成一个tarball(Docker映像)。

Docker容器就像压缩包的解压缩版本。您可以在不同的文件夹(容器)中拥有任意数量的副本。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.