使用Docker时,我们从基本映像开始。我们启动它,创建更改并将这些更改保存在层中,形成另一个图像。
所以我最终得到了一个用于我的PostgreSQL实例的图像和一个用于我的Web应用程序的图像,这些图像继续保持不变。
所以问题是:什么是容器?
图像的实例称为容器。你有一个图像,这是你描述的一组图层。如果您启动此图像,则您拥有此图像的运行容器。您可以拥有许多相同图像的运行容器。
您可以使用docker images
查看所有图像,而您可以使用docker ps
查看正在运行的容器(您可以使用docker ps -a
查看所有容器)。
因此,图像的运行实例是容器。
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
你可以看到它非常像操作系统。
Docker镜像打包应用程序运行所需的应用程序和环境,容器是图像的运行实例。
图像是docker的包装部分,类似于“源代码”或“程序”。容器是docker的执行部分,类似于“进程”。
在这个问题中,只有“程序”部分被引用,那就是图像。 docker的“运行”部分是容器。当一个容器运行并进行更改时,就好像该进程对其自己的源代码进行了更改并将其另存为新映像。
在编程方面,
图像是源代码。
编译和构建源代码时,它被称为应用程序。
类似于“为图像创建实例时”,它被称为“容器”
Image与OOP中的类定义等效,层是该类的不同方法和属性。
容器是图像的实际实例化,就像对象是实例化或类的实例一样。
简而言之:
容器是内核中的一个分区(虚拟),它共享一个公共操作系统并运行一个映像(Docker映像)。
容器是一个自我可持续的应用程序,它将包和所有必需的依赖项一起运行代码。
Docker容器正在运行映像的实例。您可以将图像与程序和带有进程的容器相关联:)
图像是作为对象的容器的类。
容器是图像的实例,因为对象是类的实例。
Dockerfile就像你的bash脚本一样产生tarball(Docker镜像)。
Docker容器就像tarball的提取版本。您可以在不同的文件夹(容器)中拥有任意数量的副本
从我关于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
有些事情需要注意:
-t
命令的docker build
标志,或来自docker tag
现有图像。您可以使用对您有意义的命名法自由标记图像,但是知道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 docs和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注册表的dockerized版本,因此我有一个私有的地方来存储我的图像。同样,有些事情需要注意:
docker ps
只输出运行容器。您可以使用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有一个抽象的ImageFactory,它包含来自store的ImageFactories。
然后,一旦您想要从该ImageFactory创建一个应用程序,您将拥有一个新容器,您可以根据需要进行修改。 DotNetImageFactory将是不可变的,因为它充当抽象工厂类,它只提供您想要的实例。
IContainer newDotNetApp = ImageFactory.DotNetImageFactory.CreateNew(appOptions);
newDotNetApp.ChangeDescription("I am making changes on this instance");
newDotNetApp.Run();
虽然将容器视为运行图像是最简单的,但这并不准确。
图像实际上是可以转换为容器的模板。要将图像转换为容器,Docker引擎会获取图像,在顶部添加读写文件系统并初始化各种设置,包括网络端口,容器名称,ID和资源限制。正在运行的容器具有当前正在执行的进程,但也可以停止容器(或以Docker的术语退出)。退出的容器与图像不同,因为它可以重新启动并保留其设置和任何文件系统更改。
用简单的话说。
图片 -
用于创建容器的文件系统和配置(只读)应用程序。 More detail。
容器 -
这些是Docker镜像的运行实例。容器运行实际的应用程序。容器包括应用程序及其所有依赖项。它与其他容器共享内核,并作为主机操作系统上用户空间中的独立进程运行。 More detail。
其他需要注意的重要条款:
Docker守护程序 -
在管理构建,运行和分发Docker容器的主机上运行的后台服务。
Docker客户端 -
命令行工具,允许用户与Docker守护程序进行交互。
Docker商店 -
除其他外,Store是Docker镜像的注册表。您可以将注册表视为所有可用Docker镜像的目录。
来自this博客的图片胜过千言万语。
(有关更深入的理解,请阅读this。)
摘要:
docker run image_name:tag_name
)=>给出一个正在运行的图像即容器(可编辑)也许解释整个工作流程可以帮助。
一切都从Dockerfile开始。 Dockerfile是Image的源代码。
创建Dockerfile后,您可以构建它以创建容器的映像。图像只是“源代码”的“编译版本”,即Dockerfile。
获得容器的映像后,应使用注册表重新分发容器。注册表就像一个git存储库 - 你可以推送和拉取图像。
接下来,您可以使用该图像来运行容器。在许多方面,正在运行的容器与虚拟机(但没有hypervisor)非常相似。
This post解释了很多关于docker容器的基本知识(它讨论的是Docker和Puppet,但是有很多概念可以在任何上下文中使用)
这是端到端工作流程,显示各种命令及其相关的输入和输出。这应该澄清图像和容器之间的关系。
+------------+ docker build +--------------+ docker run -dt +-----------+ docker exec -it +------+
| Dockerfile | --------------> | Image | ---------------> | Container | -----------------> | Bash |
+------------+ +--------------+ +-----------+ +------+
^
| docker pull
|
+--------------+
| Registry |
+--------------+
要列出您可以运行的图像,请执行:
docker image ls
要列出容器,您可以执行以下命令:
docker ps
尽管在这里阅读了所有问题然后最终偶然发现了这个excellent documentation from Docker(呃!),我无法理解图像和图层的概念。
这个例子确实是理解整个概念的关键。这是一个冗长的帖子,所以我总结了需要真正掌握以获得清晰度的关键点。
Example
:下面的Dockerfile包含四个命令,每个命令都创建一个图层。
来自ubuntu:15.04
复制。 /应用
运行make / app
CMD python /app/app.py
重要的是,每个图层只是与之前图层的一组差异。
因此,容器和图像之间的主要区别是顶部可写层。对添加新数据或修改现有数据的容器的所有写入都存储在此可写层中。删除容器时,也会删除可写层。基础图像保持不变。
从磁盘大小的角度理解图像cnd容器
要查看正在运行的容器的大致大小,可以使用docker ps -s
命令。你得到size
和virtual size
作为两个输出:
另一个重要的概念是写时复制策略
如果文件或目录存在于图像中的较低层,而另一层(包括可写层)需要对其进行读访问,则它只使用现有文件。第一次另一个图层需要修改文件时(构建图像或运行容器时),文件将被复制到该图层并进行修改。
我希望能帮助别人喜欢我。
Dockerfile>(构建)>图像>(运行)>容器。
容器只是一个可执行的二进制文件,它将由主机OS在一组限制下运行,这些限制是使用知道如何告诉OS应用哪些限制的应用程序(例如,docker)预设的。
典型的限制是与进程隔离相关,与安全相关(如使用SELinux保护)和与系统资源相关(内存,磁盘,CPU,网络)。
直到最近,只有基于Unix的系统中的内核才支持在严格限制下运行可执行文件的能力。这就是今天大多数容器谈话主要涉及Linux或其他Unix发行版的原因。
Docker是那些知道如何告诉操作系统(主要是Linux)运行可执行文件的限制的应用程序之一。可执行文件包含在Docker镜像中,它只是一个tarfile。该可执行文件通常是预先配置为在其中运行一个或多个应用程序的Linux发行版(Ubuntu,centos,Debian等)的精简版本。
虽然大多数人使用Linux基础作为可执行文件,但只要主机操作系统可以运行它,它就可以是任何其他二进制应用程序。 (见creating a simple base image using scratch)。无论Docker镜像中的二进制文件是操作系统还是仅仅是应用程序,对于OS主机而言,它只是另一个进程,由预设的操作系统边界控制的包含进程。
其他应用程序,如Docker,可以告诉主机操作系统在运行时应用于哪个边界,包括LXC,libvirt和systemd。 Docker曾经使用这些应用程序间接与Linux操作系统交互,但现在Docker使用自己的名为“libcontainer”的库直接与Linux交互。
所以容器只是在限制模式下运行的进程,类似于chroot过去做的事情。
IMO将Docker与其他任何容器技术区别开来的是它的存储库(Docker Hub)及其管理工具,这使得使用容器非常容易。
见https://en.m.wikipedia.org/wiki/Docker_(Linux_container_engine)