Docker镜像和容器有什么区别?

1230

使用Docker时,我们从一个基础镜像开始。我们启动它,进行更改,这些更改会被保存在不同的层中,形成另一个镜像。

因此,我最终拥有一个用于PostgreSQL实例的镜像和一个用于Web应用程序的镜像,对其进行的更改将继续存在。

什么是容器?


截至2022年,Docker已经几乎“死亡”。因此,问题和答案应该转化为更通用的形式,以符合OCI规范/镜像和容器定义。 - user3192295
9
比起OCI,更多的人知道什么是Docker。那么是否每个macOS相关问题都应该标记为“Darwin”呢? - btraas
32个回答

8
许多答案都指出了:你需要构建Dockerfile来获取一个镜像,然后你需要运行镜像来获取一个容器
然而,以下步骤帮助我更好地理解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 你会发现它非常类似于一个操作系统。

7

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

假设你运行命令docker run hello-world。会发生什么?

它调用Docker CLI,负责接收Docker指令并将其转换为调用Docker服务器指令。一旦Docker服务器收到运行镜像的指令,它就会检查镜像缓存是否拥有该名称的镜像

假设hello-world不存在。 Docker服务器Docker Hub(Docker Hub只是一个免费的图像库)询问,嘿Hub,你是否有名为hello-world镜像?Hub回答-是的,我有。那请给我它。下载过程开始。一旦Docker镜像下载完成,Docker服务器将其放入镜像缓存中。

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

当您在计算机上运行Chrome等应用程序时,它会调用操作系统,操作系统本身会调用内核,并询问,嘿,我想运行这个程序。内核可以管理来自硬盘的文件。

现在想象一下,您有两个程序:Chrome和Node.js。 Chrome需要Python版本2才能运行,Node.js需要Python版本3才能运行。如果您只在计算机上安装了Python v2,则只会运行Chrome。

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

因此,当我们谈论镜像时,我们实际上是在谈论文件系统快照。 镜像是一个物理文件,其中包含构建特定容器的指令和元数据。容器本身是镜像的实例;它使用命名空间来隔离硬盘,该命名空间仅适用于此容器。因此,容器是一组资源的进程或集合。


7

你可以将镜像看作是一个容器的"快照"。

你可以从一个容器中制作镜像(新的"快照"),也可以从镜像中启动新的容器(实例化"快照")。例如,你可以从基础镜像中实例化一个新容器,在容器中运行一些命令,然后将其"快照"为一个新镜像。然后,你可以从该新镜像实例化100个容器。

其他需要考虑的事项:

  • 镜像由层构成,而层是"快照差异";当你推送一个镜像时,只会发送"差异"到注册表。
  • Dockerfile在基础镜像上定义了一些命令,创建新的层("差异"),导致形成新的镜像("快照")。
  • 容器总是从镜像中实例化而来。
  • 镜像标签不仅仅是标签。它们是镜像的"完整名称"("存储库:标签")。如果同一镜像具有多个名称,则在执行docker images时会显示多次。

这个回答是错误的。容器是镜像的一个实例,或者说是镜像的可执行快照。镜像本身不会直接被执行,因为它是实例的父类。实例(容器)是父类(用于创建实例的配方或模板)的子类。 - Rich Lysakowski PhD
1
这个答案从过程的最后开始。可以将一个新的镜像制作为容器的快照,但所有的容器都必须有一个父镜像。在这种情况下,不存在先有鸡还是先有蛋的问题,因为必须首先从 Dockerfile 构建第一个原始镜像。先有 Dockerfile,然后是镜像,再是容器。容器可以用作新镜像的基础,但该容器必须有一个“父镜像”。 - Rich Lysakowski PhD
谢谢!我稍微编辑了一下答案,以明确这种推理的观点,并且容器始终是从镜像实例化的(而不是相反)。 - tothemario

6
一个Docker镜像打包了应用程序和运行所需的环境,容器是镜像的运行实例。
镜像是Docker的打包部分,类似于“源代码”或“程序”。容器是Docker的执行部分,类似于“进程”。
在问题中,只提到了“程序”部分,也就是镜像。 Docker的“运行”部分是容器。当一个容器被运行并且更改被进行时,就好像进程更改了自己的源代码并将其保存为新的镜像。

6

图像相当于面向对象编程中的类定义,而图层则是该类的不同方法和属性。

容器就像对象是类的实例化或实例一样,是图像的实际实例化。


5
我将在docker imagescontainers之间填补缺失的部分。Docker使用联合文件系统(UFS)来为容器提供支持,它允许多个文件系统被挂载到一个层次结构中并表现为单个文件系统。图像中的文件系统已经被挂载为只读层,对于正在运行的容器进行的任何更改都会被应用于此之上挂载的读写层。因此,Docker只需查看最顶层的读写层以查找对运行系统所做的更改。

5

就像在编程方面一样,

图像就是源代码。

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

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


5
Dockerfile 就像源代码。 镜像则是在源代码编译/构建后生成的可执行文件。 容器就像是从可执行文件中启动的应用程序。 - ejlp12
1
图像不是容器的源代码。Dockerfile 是类的元类或规范。镜像是容器的类或模板,而容器是类的实例。容器是运行的实例。您可以拥有一个类的1000个实例。镜像就像编译后的目标代码,可以链接到另一个程序中,并作为该程序的一部分运行。 - Rich Lysakowski PhD

5
Docke客户端、服务器、机器、镜像、中心和组合是一些工具软件项目,它们共同组成一个平台,用于创建和运行所谓的容器生态系统。如果您运行命令 docker run redis ,则称为Docker CLI的东西将会访问称为Docker Hub的东西,并下载一个名为镜像的单个文件。 enter image description here Docker镜像: 镜像是一个包含运行特定程序所需的所有依赖项和配置的单个文件。例如,redis是您刚才下载(通过运行命令docker run redis)的镜像,旨在运行。
这是一个存储在硬盘上的单个文件,在某个时间点,您可以使用此镜像创建所谓的容器。 enter image description here

一个容器是一个镜像的实例,你可以把它看作是一个运行中的程序,拥有自己独立的硬件资源,因此它有自己的一小部分内存空间、网络技术和硬盘空间。

现在让我们来看一下当您输入以下命令时会发生什么: sudo docker run hello-world

上述命令将启动Docker客户端或Docker CLI。Docker CLI负责接收您的命令,对其进行一些处理,然后将命令发送到称为Docker服务器的东西上。Docker服务器负责处理重要任务。当我们运行Docker run hello-world命令时, enter image description here 这意味着我们想使用名称为hello world的镜像启动一个新的容器,hello world镜像中有一个微小的程序,其唯一目的是打印出您在终端中看到的消息。

当我们运行该命令并将其发送到Docker服务器时,一系列操作会在后台迅速发生。Docker服务器看到我们正在尝试使用名为“hello world”的映像启动一个新容器。

Docker服务器要做的第一件事是检查它是否已经有本地副本,例如个人计算机上的hello world图像或hello world文件。因此,Docker服务器查看了称为镜像缓存的东西。 enter image description here

现在,由于您和我刚刚在个人计算机上安装了Docker,所以镜像缓存当前为空,我们没有已经下载过的映像。

因此,由于镜像缓存为空,Docker服务器决定向一个名为Docker Hub的免费服务请求。Docker Hub是一个可供您自由下载和在个人计算机上运行的免费公共映像的存储库。因此,Docker服务器联系Docker Hub并下载了hello world文件,并将其存储在图像缓存中,以便在将来某个时间点可以快速重新运行而无需从Docker Hub重新下载它。

接下来,docker服务器将使用它来创建一个容器实例。我们知道,容器是镜像的一个实例,它的唯一目的是运行一个非常特定的程序。因此,docker服务器从镜像缓存中获取了该镜像文件,并将其加载到内存中,创建了一个容器,然后在其中运行了一个单独的程序。这个单独的程序的目的是打印出你看到的消息。
什么是容器: 首先,镜像是创建容器的蓝图。
容器是一个进程或一组进程,具有专门分配给它的资源组合。下面是一个图表,每当我们考虑容器时,都有一些正在运行的进程发送系统调用到内核,内核会查看传入的系统调用并将其指向硬盘、RAM、CPU或其他可能需要的特定部分,同时这些资源的一部分被分配给单个进程。

非常好的解释,谢谢! - Juanma Menendez

5

我会用以下类比来阐述:

+-----------------------------+-------+-----------+
|             Domain          | Meta  | Concrete  |
+-----------------------------+-------+-----------+
| Docker                      | Image | Container |
| Object oriented programming | Class | Object    |
+-----------------------------+-------+-----------+

3

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接