当使用Docker时,我们从一个基础镜像开始。我们启动它,创建变化,这些变化被保存在层中形成另一个镜像。
因此,最终我有一个用于PostgreSQL实例的镜像和一个用于Web应用程序的镜像,它们的变化一直被保存下来。
什么是容器?
一个图像的实例被称为一个容器。你有一个镜像,正如你所描述的,它是一组层。如果你启动这个镜像,你就有一个这个镜像的运行容器。你可以有许多同一镜像的运行容器。
你可以用docker images
看到你的所有镜像,而你可以用docker ps
看到你正在运行的容器(你也可以用docker ps -a
看到所有容器)。
所以一个镜像的运行实例就是一个容器。
摘自我的文章《自动化Docker部署》1。
在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.2.VIRTUAL SIZE是_虚拟的,因为它是将所有不同底层的尺寸相加。这意味着该列中所有数值的总和可能远远大于所有这些图像所使用的磁盘空间。
3.3. REPOSITORY列中的值来自于 "docker build "命令的 "t "标志,或来自于 "docker tag "对一个现有图像的标记。你可以自由地使用对你有意义的术语来标记镜像,但要知道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列只是_full_标签的[:TAG]部分。这是很不幸的术语。
6.6. "latest "标签并不神奇,它只是在你不指定标签时的默认标签。
7.7.你可以有未标记的图像,但只能通过其IMAGE ID来识别。这些图片将获得<none>
标签和REPOSITORY。这很容易让人忘记它们。
用一个编程的比喻来说,如果一个镜像是一个类,那么一个容器就是一个类的实例--运行时对象。容器有望成为你使用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化版本,这样我就有一个私人的地方来存储我的图像。同样,有些事情需要注意。
1.像图像ID一样,CONTAINER ID是容器的真正标识符。它有相同的形式,但它标识的是不同类型的对象。
2.2. docker ps
只输出_运行中_的容器。你可以用docker ps -a
查看所有的容器(_running_或stopped)。
3.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.2. 总是用 "docker rmi [IMAGE_ID]"来删除一个无用的、停止的容器背后的镜像。
虽然把容器看作是一个正在运行的镜像是最简单的,但这并不**准确。
镜像实际上是一个可以被转化为容器的模板。要把一个镜像变成一个容器,Docker引擎需要这个镜像,在上面添加一个可读写的文件系统,并初始化各种设置,包括网络端口、容器名称、ID和资源限制。一个正在运行的容器有一个当前正在执行的进程,但是一个容器也可以被停止(或者用Docker的术语说是exited)。一个退出的容器不等同于一个镜像,因为它可以被重新启动,并将保留其设置和任何文件系统的变化。