【发布时间】:2014-07-07 06:14:28
【问题描述】:
使用 Docker 时,我们从基础镜像开始。我们启动它,创建更改,这些更改保存在层中,形成另一个图像。
所以最终我有一张用于我的 PostgreSQL 实例的图像和一张用于我的 Web 应用程序的图像,对它们的更改会继续保持不变。
什么是容器?
【问题讨论】:
标签: docker docker-container docker-image
使用 Docker 时,我们从基础镜像开始。我们启动它,创建更改,这些更改保存在层中,形成另一个图像。
所以最终我有一张用于我的 PostgreSQL 实例的图像和一张用于我的 Web 应用程序的图像,对它们的更改会继续保持不变。
什么是容器?
【问题讨论】:
标签: docker docker-container docker-image
图像的实例称为容器。您有一个图像,它是您描述的一组图层。如果你启动这个镜像,你就有了这个镜像的运行容器。您可以拥有多个运行同一映像的容器。
您可以使用docker images 查看所有图像,而使用docker ps 可以查看正在运行的容器(您可以使用docker ps -a 查看所有容器)。
所以一个图像的运行实例是一个容器。
【讨论】:
来自我在Automating Docker Deployments 上的文章(已存档):
在 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
注意事项:
docker build 命令的-t 标志,或来自docker tag-ing 现有图像。您可以使用对您有意义的命名法来标记图像,但要知道 docker 将使用标记作为 docker push 或 docker pull 中的注册表位置。[REGISTRYHOST/][USERNAME/]NAME[:TAG]。对于上面的ubuntu,REGISTRYHOST 被推断为registry.hub.docker.com。因此,如果您打算将名为my-application 的图像存储在docker.example.com 的注册表中,则应标记该图像docker.example.com/my-application。latest 标签并不神奇,它只是您不指定标签时的默认标签。<none> TAG 和REPOSITORY。很容易忘记它们。有关图像的更多信息,请访问Docker documentation 和glossary。
使用编程比喻,如果图像是一个类,那么容器就是一个类的实例——一个运行时对象。希望容器是您使用 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 注册表的 docker 化版本,这样我就有了一个私密的地方来存储我的图像。再次,有几点需要注意:
docker ps 只输出 running 容器。您可以使用docker ps -a查看所有容器(正在运行或已停止)。--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,可能会在未来的版本中得到解决。但是,如果对图像和容器有清晰的了解,则可以通过以下几种做法来避免这些情况:
docker rm [CONTAINER_ID] 删除无用、已停止的容器。docker rmi [IMAGE_ID] 删除无用、已停止容器后面的图像。【讨论】:
docker image prune 来清理悬空图像。 Prune unused Docker objects
docker system prune 来清理所有东西
简单来说。
图片 -
文件系统和配置(只读)应用程序,用于 创建容器。 More detail.
容器 -
容器和图像之间的主要区别在于 顶层可写层。容器正在运行 Docker 映像的实例 具有顶部可写层。容器运行实际 应用程序。一个容器包括一个应用程序及其所有 依赖关系。当容器被删除时,可写层也被删除。底层图像保持不变。 More detail.
需要注意的其他重要条款:
Docker 守护进程 -
在管理建筑物的主机上运行的后台服务, 运行和分发 Docker 容器。
Docker 客户端 -
允许用户与 Docker 交互的命令行工具 守护进程。
Docker 商店 -
Store 是 Docker 镜像的注册表。你可以 将注册表视为所有可用 Docker 映像的目录。
this blog post 的一张图片值一千字。
(更深入的了解请阅读this。)
总结:
docker run image_name:tag_name) => 提供运行镜像,即容器(可编辑)【讨论】:
虽然将容器视为运行映像最简单,但这并不完全准确。
图像实际上是可以变成容器的模板。为了将镜像变成容器,Docker 引擎获取镜像,在顶部添加一个读写文件系统,并初始化各种设置,包括网络端口、容器名称、ID 和资源限制。正在运行的容器有一个当前正在执行的进程,但容器也可以停止(或 Docker 术语中的 exited)。退出的容器不与图像相同,因为它可以重新启动并保留其设置和任何文件系统更改。
【讨论】:
docker create。
也许解释整个工作流程会有所帮助。
一切都从 Dockerfile 开始。 Dockerfile就是镜像的源代码。
创建 Dockerfile 后,您可以构建它以创建容器的 映像。该图像只是“源代码”的“编译版本”,即 Dockerfile。
获得容器的映像后,您应该使用注册表重新分发它。注册表就像一个 Git 存储库——您可以推送和拉取图像。
接下来,您可以使用该映像来运行容器。运行中的容器在很多方面都与虚拟机非常相似(但没有hypervisor)。
【讨论】:
Dockerfile → (Build) → Image → (Run) → Container.
Dockerfile:包含一组 Docker 指令,以您喜欢的方式配置您的操作系统,并安装/配置您的所有软件。
镜像:编译后的 Dockerfile。节省您每次需要运行容器时重新构建 Dockerfile 的时间。这是一种隐藏您的供应代码的方法。
Container:虚拟操作系统本身。您可以 ssh 进入它并运行您希望的任何命令,就好像它是一个真实的环境一样。您可以从同一个映像运行 1000 多个容器。
【讨论】:
这是显示各种命令及其相关输入和输出的端到端工作流程。这应该阐明图像和容器之间的关系。
+------------+ docker build +--------------+ docker run -dt +-----------+ docker exec -it +------+
| Dockerfile | --------------> | Image | ---------------> | Container | -----------------> | Bash |
+------------+ +--------------+ +-----------+ +------+
^
| docker pull
|
+--------------+
| Registry |
+--------------+
要列出您可以运行的图像,请执行:
docker image ls
列出可以执行命令的容器:
docker ps
【讨论】:
尽管阅读了这里的所有问题,但我还是无法理解 image 和 layer 的概念,然后最终偶然发现了这个excellent documentation from Docker(呃!)。
那里的示例确实是理解整个概念的关键。这是一篇很长的帖子,所以我总结了需要真正掌握才能清晰的关键点。
镜像:Docker镜像由一系列只读层
层:每一层代表图像的 Dockerfile 中的一条指令。
Example:下面的 Dockerfile 包含四个命令,每个命令创建一个层。
来自 ubuntu:15.04
复制。 /应用程序
运行 make /app
CMD python /app/app.py
重要的是,每一层只是与前一层的一组差异。
因此,容器和图像之间的主要区别是 顶部可写层。对容器的所有写入添加新的或 修改现有数据存储在这个可写层中。当。。。的时候 容器被删除,可写层也被删除。这 底层图像保持不变。
从磁盘大小的角度理解图像和容器
要查看正在运行的容器的大致大小,可以使用docker ps -s 命令。你得到size 和virtual size 作为两个输出:
大小:用于每个容器的可写层的数据量(在磁盘上)
虚拟大小:容器使用的只读图像数据的数据量。多个容器可能共享部分或全部只读图像数据。 因此这些不是附加的。 IE。您无法添加所有虚拟大小来计算映像使用了多少磁盘大小
另一个重要的概念是写时复制策略
如果一个文件或目录存在于图像中的较低层,并且另一个层(包括可写层)需要对其进行读取访问,则它只使用现有文件。其他层第一次需要修改文件时(构建镜像或运行容器时),将文件复制到该层并修改。
我希望这可以帮助像我这样的其他人。
【讨论】:
简单地说,如果一个图像是一个类,那么一个容器就是一个类的实例就是一个运行时对象。
【讨论】:
容器只是一个可执行二进制文件,由主机操作系统在一组限制下运行,这些限制使用知道如何告诉操作系统应用哪些限制的应用程序(例如,Docker)预设。
典型的限制是进程隔离相关、安全相关(如使用SELinux 保护)和系统资源相关(内存、磁盘、CPU 和网络)。
直到最近,只有基于 Unix 的系统中的内核才支持在严格限制下运行可执行文件的能力。这就是为什么今天大多数容器讨论主要涉及 Linux 或其他 Unix 发行版。
Docker 是那些知道如何告诉操作系统(主要是 Linux)在哪些限制下运行可执行文件的应用程序之一。可执行文件包含在 Docker 映像中,它只是一个 tar 文件。该可执行文件通常是 Linux 发行版用户空间(Ubuntu、CentOS、Debian 等)的精简版本,预先配置为在其中运行一个或多个应用程序。
尽管大多数人使用 Linux 基础作为可执行文件,但它可以是任何其他二进制应用程序,只要主机操作系统的内核可以运行它(请参阅creating a simple base image using scratch)。无论 Docker 镜像中的二进制文件是 OS 用户空间还是简单的应用程序,对于 OS 主机来说,它都只是另一个进程,一个由预设 OS 边界支配的包含进程。
其他应用程序,如 Docker,可以告诉主机操作系统在进程运行时应用哪些边界,包括 LXC、libvirt 和 systemd。 Docker 过去使用这些应用程序间接与 Linux 操作系统交互,但现在 Docker 使用自己的名为“libcontainer”的库直接与 Linux 交互。
所以容器只是在受限模式下运行的进程,类似于 chroot 过去所做的。
IMO,Docker 与任何其他容器技术的不同之处在于其存储库 (Docker Hub) 及其管理工具,这使得使用容器变得非常容易。
【讨论】:
Docker 的核心概念是让创建“机器”变得容易,在这种情况下可以将其视为容器。容器有助于可重用性,让您可以轻松创建和删除容器。
图像描述了容器在每个时间点的状态。所以基本的工作流程是:
【讨论】:
正如许多答案指出的那样:您 构建 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
你可以看到它非常像一个操作系统。
【讨论】:
Image 相当于 OOP 中的类定义,层是该类的不同方法和属性。
Container 是图像的实际实例化,就像对象是实例化或类的实例一样。
【讨论】:
将图像视为容器的“快照”可能会有所帮助。
您可以从容器制作图像(新“快照”),也可以从图像启动新容器(实例化“快照”)。例如,您可以从基础镜像实例化一个新容器,在容器中运行一些命令,然后将其“快照”为新镜像。然后,您可以从该新映像中实例化 100 个容器。
其他需要考虑的事项:
docker images时会显示多次。【讨论】:
一个Docker镜像打包了应用运行所需要的应用和环境,一个容器就是镜像的一个运行实例。
图像是 Docker 的打包部分,类似于“源代码”或“程序”。容器是 Docker 的执行部分,类似于“进程”。
在问题中,仅提及“程序”部分,即图像。 Docker 的“运行”部分是容器。当容器运行并进行更改时,就好像进程在自己的源代码中进行了更改并将其保存为新图像。
【讨论】:
在编程方面,
图片是源代码。
当源代码被编译和构建时,它被称为应用程序。
类似于“为图像创建实例时”,它被称为“容器”。
【讨论】:
我觉得最好在开头解释一下。
假设您运行命令docker run hello-world。会发生什么?
它调用Docker CLI,它负责接受Docker命令并转换为调用Docker server命令。一旦 Docker 服务器 收到运行 图像 的命令,它就会检查 图像缓存 是否保存 图像有这样的名字。
假设 hello-world 不存在。 Docker 服务器 转到 Docker Hub(Docker Hub 只是一个免费的图像存储库)并询问,嘿 Hub,你有一个名为的 图像 hello-world?
集线器响应 - 是的,我愿意。那么请给我。下载过程开始。 Docker 映像 下载后,Docker 服务器 会将其放入映像缓存。
所以在我们解释什么是 Docker 镜像和 Docker 容器之前,让我们先介绍一下您计算机上的操作系统以及它是如何运行软件的。
例如,当您在计算机上运行 Chrome 时,它会调用操作系统,操作系统本身会调用内核并询问,嘿,我想运行这个程序。内核设法从您的硬盘运行文件。
现在假设您有两个程序,Chrome 和 Node.js。 Chrome 需要 Python 版本 2 才能运行,而 Node.js 需要 Python 版本 3 才能运行。如果您的计算机上只安装了 Python v2,则只会运行 Chrome。
要使这两种情况都能正常工作,您需要以某种方式使用称为命名空间的操作系统功能。命名空间是一项功能,可让您有机会隔离进程、硬盘驱动器、网络、用户、主机名等。
所以,当我们谈论 图像 时,我们实际上是在谈论文件系统快照。 图像是一个物理文件,其中包含用于构建特定容器的说明和元数据。 容器本身就是一个图像的实例;它使用仅适用于此容器的命名空间来隔离硬盘驱动器。因此,容器是一个进程或一组进程,它将分配给它的不同资源分组。
【讨论】:
我想填补docker images 和containers 之间的缺失部分。 Docker 为容器使用 联合文件系统 (UFS),它允许多个文件系统以层次结构挂载并显示为单个文件系统.映像中的文件系统已挂载为read-only 层,并且对运行容器的任何更改都会对挂载在此之上的read-write 层进行。正因为如此,Docker 只需要查看最顶层的读写层就可以找到对运行系统所做的更改。
【讨论】:
我会用下面的比喻来说明:
+-----------------------------+-------+-----------+
| Domain | Meta | Concrete |
+-----------------------------+-------+-----------+
| Docker | Image | Container |
| Object oriented programming | Class | Object |
+-----------------------------+-------+-----------+
【讨论】:
Docker Client、Server、Machine、Images、Hub、Compose 都是项目工具和软件,它们结合在一起形成一个平台,在这个平台上,生态系统围绕创建和运行称为容器的东西,现在如果你运行命令 docker run redis 一个叫做 docker CLI 的东西连接到一个叫做 Docker Hub 的东西,它下载了一个叫做图像的文件。
Docker 镜像:
镜像是一个包含所有依赖项和运行非常特定程序所需的所有配置的单个文件,例如 redis 是您刚刚下载的镜像(通过运行命令 docker run redis) 应该运行。
这是存储在您的硬盘上的单个文件,在某些时候您可以使用此映像来创建称为容器的东西。
容器是图像的一个实例,您可以将它想象成一个正在运行的程序,具有自己独立的一组硬件资源,因此它有自己的小集合,或者它自己的小内存空间有它自己的自己的网络技术空间小,硬盘空间也小。
现在让我们检查一下您何时发出以下命令: sudo docker run hello-world
上面的命令将启动 docker 客户端或 docker CLI,Docker CLI 负责从您那里获取命令,对它们进行一些处理,然后将命令传送到称为 docker 服务器的东西,然后 docker当我们运行命令 Docker run hello-world 时,服务器负责繁重的工作, 这意味着我们想使用名称为 hello world 的图像启动一个新容器,hello world 图像内部有一个小程序,其唯一目的或唯一工作是打印出您在终端。
现在,当我们运行该命令并将其发送到 docker 服务器时,后台很快就会发生一系列操作。 Docker 服务器看到我们正在尝试使用名为 hello world 的映像启动一个新容器。
docker 服务器做的第一件事是检查它是否已经有一个本地副本,比如你个人机器上的 hello world 镜像或那个 hello world 文件的副本。所以 docker 服务器查看了一个叫做镜像的东西缓存。
现在因为你和我刚刚在我们的个人计算机上安装了 Docker,图像缓存当前是空的,所以我们没有之前已经下载过的图像。
因此,由于图像缓存为空,docker 服务器决定使用名为 Docker hub 的免费服务。 Docker Hub 是一个免费的公共镜像存储库,您可以免费下载并在您的个人计算机上运行。因此 Docker 服务器联系了 Docker Hub 并下载了 hello world 文件并将其存储在您的计算机上的图像缓存中,现在它可以在未来的某个时候非常快速地重新运行,而无需从码头工人枢纽。
之后 docker 服务器会使用它来创建一个容器的实例,而我们知道容器是一个镜像的实例,它的唯一目的就是运行一个非常具体的程序。因此,docker 服务器基本上从图像缓存中获取该图像文件并将其加载到内存中以从中创建一个容器,然后在其中运行一个程序。单个程序的目的是打印出您看到的消息。
什么是容器: 首先,图像是如何创建容器的蓝图。
容器是一个进程或一组进程,它们具有专门分配给它的一组资源,在下面的图表中,无论何时我们想到一个容器,我们都有一些正在运行的进程,它向内核发送系统调用,内核将查看传入的系统调用并将其定向到硬盘驱动器的非常特定的部分、RAM、CPU 或它可能需要的任何其他东西,并且这些资源中的一部分可供该单一资源使用过程。
【讨论】:
图像之于类就像容器之于对象。
容器是图像的实例,就像对象是类的实例一样。
【讨论】:
*在 docker 中,an image is an immutable file 包含运行 docker 应用程序所需的源代码和信息。它可以独立于容器而存在。
*Docker 容器是virtualized environments created during runtime,需要镜像才能运行。 docker 网站上有一张图片显示了这种关系:
【讨论】:
对于一个虚拟的编程类比,您可以认为 Docker 有一个抽象的 ImageFactory,其中包含它们来自 store 的 ImageFactories。
然后,一旦您想从该 ImageFactory 创建应用程序,您将拥有一个新容器,您可以根据需要对其进行修改。 DotNetImageFactory 将是不可变的,因为它充当抽象工厂类,只提供您想要的实例。
IContainer newDotNetApp = ImageFactory.DotNetImageFactory.CreateNew(appOptions);
newDotNetApp.ChangeDescription("I am making changes on this instance");
newDotNetApp.Run();
【讨论】:
简而言之:
容器是内核中的一个分区(虚拟),它共享一个通用操作系统并运行一个映像(Docker 映像)。
容器是一个自我维持的应用程序,它将包含包和所有必要的依赖项来运行代码。
【讨论】:
Docker 容器正在运行映像的实例。您可以将图像与程序相关联,将容器与进程相关联:)
【讨论】:
Dockerfile 就像您的 Bash 脚本,它生成一个 tarball(Docker 映像)。
Docker 容器就像是压缩包的提取版本。您可以在不同的文件夹(容器)中拥有任意数量的副本。
【讨论】:
镜像是构建容器(运行实例)的蓝图。
【讨论】:
正如对象是面向对象编程语言中类的实例一样,Docker 容器也是 Docker 映像的实例。
一个图像就像一个类,而容器就像一个类的对象,因此您可以拥有无限数量的容器,其行为类似于图像。一个类是一个蓝图,它自己不做任何事情。您必须在程序中创建对象的实例才能做任何有意义的事情。图像和容器的情况也是如此。您定义映像,然后创建运行该映像的容器。它不完全相似,因为对象是一个类的实例,而容器就像一个空洞的地方,你可以使用图像来构建一个运行中的主机,与图像所说的完全一样
【讨论】:
映像或容器映像是一个文件,其中包含您的应用程序代码、应用程序运行时、配置、依赖库。该图像基本上将所有这些包装到一个单一的、安全的不可变单元中。使用适当的 docker 命令来构建映像。图像具有图像 ID 和图像标签。标签的格式通常为
当您开始使用映像运行应用程序时,您实际上启动了一个容器。因此,您的容器是一个沙箱,您可以在其中运行映像。 Docker 软件用于管理镜像和容器。
Image 是一个安全包,其中包含您的应用程序工件、库、配置和应用程序运行时。容器是图像的运行时表示。
【讨论】: