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

mo49yndu  于 2022-09-19  发布在  Docker
关注(0)|答案(30)|浏览(174)

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

因此,最终我有了一个用于我的PostgreSQL示例的图像和一个用于我的Web应用程序的图像,对其所做的更改将被持续保存。

什么是集装箱?

pgccezyw

pgccezyw1#

图像的示例称为容器。您有一个图像,它是您所描述的一组层。如果启动该映像,您就拥有了该映像的运行容器。您可以拥有同一映像的多个运行容器。

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

因此,图像的运行示例就是一个容器。

ogsagwnx

ogsagwnx2#

摘自我关于Automating Docker Deployments的文章(已存档):

码头人员镜像与集装箱

在Dockerland,有镜像,也有容器。两者密切相关,但又截然不同。对我来说,对这种二分法的理解让多克得到了极大的澄清。

什么是镜像?

图像是一个惰性的、不变的文件,本质上是容器的快照。映像是使用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.镜像ID为镜像真实标识的前12个字符。您可以为给定图像创建多个标记,但它们的ID都是相同的(如上所述)。
1.虚拟大小是“虚拟”的,因为它将所有不同底层的大小相加。这意味着该列中所有值的总和可能比所有这些图像使用的磁盘空间大得多。
1.存储库列中的值来自docker build命令的-t标志,或来自现有映像的docker tag。您可以自由地使用对您有意义的命名法来标记图像,但要知道docker将使用该标记作为docker pushdocker pull中的注册表位置。
1.标签的完整形式为[REGISTRYHOST/][USERNAME/]NAME[:TAG]。对于上面的ubuntu,REGISTRYHOST被推断为registry.hub.docker.com。因此,如果您计划将名为my-application的映像存储在位于docker.example.com的注册表中,则应该将该映像标记为docker.example.com/my-application
1.Tag列只是Full标签的[:Tag]部分。这是一个不合时宜的术语。
1.latest标签并不神奇,它只是您没有指定标签时的默认标签。
1.您可以拥有只能通过其镜像ID识别的未标记镜像。它们将获得<none>标签和存储库。人们很容易忘记它们。

有关图像的更多信息,请参阅Docker documentation和词汇表。

什么是容器?

用编程的比喻来说,如果图像是一个类,那么容器就是一个类的示例--一个运行时对象。容器有望成为您使用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注册表的停靠版本,这样我就有了一个私人的地方来存储我的图像。再说一次,有一些事情需要注意:

1.容器ID和镜像ID一样,是容器的真实标识。它具有相同的形式,但它标识了不同类型的对象。
1.docker ps只输出运行容器。您可以使用docker ps -a查看所有容器(正在运行已停止)。
1.名称可以通过--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的known pain points,可能会在未来的版本中解决。但是,在对图像和容器有了清楚的了解后,可以通过以下几种做法来避免这些情况:

1.一定要取出装有docker rm [CONTAINER_ID]的无用的、已停止的容器。
1.始终使用docker rmi [IMAGE_ID]移除无用的、已停止的容器后面的镜像。

ldxq2e6h

ldxq2e6h3#

尽管将容器视为运行的映像是最简单的做法,但这并不“十分”准确。

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

mxg2im7a

mxg2im7a4#

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

所有内容都以Dockerfile开头。Dockerfile是图片的源代码。

Dockerfile创建完成后,您可以构建它来创建容器的镜像。该图像只是Dockerfile的“源代码”的“编译版本”。

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

接下来,您可以使用该镜像运行容器。在许多方面,运行的容器非常类似于虚拟机(但没有hypervisor)。

uqdfh47h

uqdfh47h5#

Dockerfile→(Build)→镜像→(Run)→容器

  • Dockerfile**:包含一套Docker说明,可以随心所欲地配置您的操作系统,并安装/配置您的所有软件。
  • 镜像**:编译后的Dockerfile。为您节省每次需要运行容器时重新构建Dockerfile的时间。这是隐藏你的条款代码的一种方式。
  • 容器**:虚拟操作系统本身。您可以ssh进入它并运行任何您想要的命令,就像它是一个真实的环境一样。您可以从同一映像运行1000多个容器。
izj3ouym

izj3ouym6#

工作流程

以下是端到端工作流,显示了各种命令及其关联的输入和输出。这应该会澄清图像和容器之间的关系。

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

要列出可以运行的映像,请执行以下命令:

docker image ls

要列出可以对其执行命令的容器,请执行以下操作:

docker ps
ruyhziif

ruyhziif7#

尽管我读了这里的所有问题,但我还是无法理解图像的概念,最后偶然发现了Docker提供的这份出色的文档(DUH!)

这里的例子确实是理解整个概念的关键。这是一篇很长的文章,所以我总结了需要真正掌握的关键点,以使其变得清晰。

  • 镜像**:Docker镜像由一系列只读层构建而成
  • 层**:每一层代表镜像的Dockerfile中的一条指令。

Example:下面的Dockerfile包含四个命令,每个命令创建一个层。
来自ubuntu:15.04

收到。/APP

运行Make/APP

CMD python/app/app.py

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

  • 容器**。当您创建新的容器时,您需要在底层之上添加一个新的可写层。这一层通常称为“容器层”。对正在运行的容器所做的所有更改,如写入新文件、修改现有文件和删除文件,都会写入这个可写容器层。

因此,容器和镜像的主要区别是顶部可写层。添加新数据或修改现有数据的对容器的所有写入都存储在此可写层中。当容器被删除时,可写层也被删除。基本图像保持不变。

从磁盘大小Angular 了解镜像CND容器

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

  • Size:用于每个容器的可写层的数据量(在磁盘上)
  • 虚拟大小:容器使用的只读镜像数据使用的数据量。多个容器可以共享部分或全部只读图像数据。因此,这些不是相加的。即,您不能将所有虚拟大小相加来计算镜像使用了多少磁盘大小

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

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

我希望这对其他像我一样的人有帮助。

enyaitl3

enyaitl38#

简单地说,如果镜像,那么容器是类的示例就是运行时对象

bis0qfac

bis0qfac9#

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

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

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

Docker是知道如何告诉操作系统(主要是Linux)在什么限制下运行可执行文件的应用程序之一。可执行文件包含在Docker映像中,它只是一个tarfile。该可执行文件通常是Linux发行版用户空间(Ubuntu、CentOS、Debian等)的精简版本。预配置为在中运行一个或多个应用程序。

尽管大多数人使用Linux基本文件作为可执行文件,但它可以是任何其他二进制应用程序,只要主机操作系统的内核可以运行它(请参见使用Scratch创建简单的基本映像)。无论Docker镜像中的二进制文件是操作系统用户空间还是简单的应用程序,对于操作系统主机来说,它只是另一个进程,一个由预设的操作系统边界控制的包含进程。

与Docker一样,其他应用程序可以在进程运行时告诉主机操作系统应用于该进程的边界,包括LXClibvirtsystemd。Docker过去常常使用这些应用程序来间接与Linux OS交互,但现在Docker使用其自有的名为“libcontainer”的库直接与Linux交互。

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

在国际海事组织,使Docker有别于任何其他容器技术的是它的存储库(Docker Hub)及其管理工具,这使得使用容器变得非常容易。

见*Docker (software)*。

f3temu5u

f3temu5u10#

Docker的核心概念是使创建“机器”变得容易,在这种情况下,机器可以被认为是容器。容器有助于重复使用,使您可以轻松地创建和放置容器。

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

1.创建镜像
1.启动一个容器
1.对容器进行更改
1.将容器保存为图像

ulydmbyx

ulydmbyx11#

正如许多答案指出的那样:您构建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

你可以看到这非常像一个操作系统。

ujv3wf0j

ujv3wf0j12#

镜像视为容器的“快照”可能会有所帮助。

您可以从容器制作镜像(新的“快照”),也可以从镜像启动新容器(示例化“快照”)。例如,您可以从基本映像示例化一个新容器,在该容器中运行一些命令,然后将其作为新映像进行“快照”。然后,您可以从该新映像示例化100个容器。

其他需要考虑的事情:

  • 图片是由层组成的,层是快照的差异;推送图片时,只会将差异发送到注册表。
    Dockerfile在基础图像上定义了一些命令,这些命令创建新的层(Diffs),从而产生新的图像(快照)。
  • 容器始终从镜像示例化。
  • 图像标签不仅仅是标签。它们是镜像的“全名”(“store:tag”)。如果同一图像有多个名称,则在执行docker images时会多次显示。
nhjlsmyf

nhjlsmyf13#

图像相当于OOP中的类定义,层是该类的不同方法和属性。

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

uyhoqukh

uyhoqukh14#

我觉得还是从一开始就解释比较好。

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

它调用Docker CLI,负责获取Docker命令并转换为调用Docker服务器命令。当Docker服务器收到运行镜像的命令后,它会立即检查镜像缓存中是否有同名的镜像

假设问候世界不存在。Docker服务器转到Docker Hub(Docker Hub只是一个免费的图片库),问道,嘿Hub,你们有镜像hello-world吗?集线器回应--是的,我有。那就请把它给我。下载过程开始。下载完Docker镜像后,Docker服务器会将其放入镜像缓存

所以在我们解释什么是Docker镜像和Docker容器之前,让我们首先介绍一下您计算机上的操作系统以及它是如何运行软件的。

例如,当你在电脑上运行Chrome时,它会调用操作系统,操作系统本身也会调用内核,并询问,嘿,我想运行这个程序。内核设法运行您硬盘上的文件。

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

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

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

eoxn13cs

eoxn13cs15#

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

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

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

相关问题