一个镜像和一个仓库有什么区别?

69

我是全新接触Docker,并正在按照入门教程进行学习。在第7步中,它说:

输入docker images命令并按回车键。该命令列出本地系统上的所有镜像。您应该在列表中看到docker/whalesay

$ docker images
REPOSITORY           TAG         IMAGE ID            CREATED            VIRTUAL SIZE
docker/whalesay      latest      fb434121fc77        3 hours ago        247 MB
hello-world          latest      91c95931e552        5 weeks ago        910 B
但第一列清楚地显示“repository”,而不是例如“image name”。我还注意到在其他人的机器上,因为一个镜像可以有多个标签,这个列表经常包含重复的条目-每个标签都有一个。那么这是一个镜像列表,仓库列表,图像标记组合列表还是其他什么列表?镜像和仓库之间有什么区别?
另外,考虑到镜像和仓库是不同的东西,我如何只列出我的仓库?
这与容器无关。

1
可能是Docker镜像与容器的重复问题。 - Vitor
5
不要混淆“镜像”和“镜像名称”。一张图片可以有多个名称:一个(唯一的)图像ID,它是一个哈希值,以及许多不同的存储库标记组合。这很令人困惑,因为“存储库”对于镜像名称的这个第一部分来说是一个非常糟糕的命名选择。 - Lutz Prechelt
2
@LutzPrechelt 我仍然不清楚“repostiory”这个词应该是什么意思。它是一个本地的东西还是与特定的图像有关?现在我甚至可能对“image”这个词的含义都感到困惑。 - Charlie Parker
1
@CharlieParker 一个仓库是多个镜像的容器。镜像基本名称是仓库名称。镜像标签用于区分镜像的不同“版本”(docker 对“版本”的定义没有任何意见,版本可能包含完全不同的镜像)。在同一个容器中,不同的标签可以引用相同的镜像。 - Lutz Prechelt
@LutzPrechelt,您能否给我提供一个参考,证明“镜像基本名称是存储库名称”?我在Docker文档中找不到它... - nekketsuuu
显示剩余2条评论
5个回答

55

是的,这个术语非常令人困惑。

最简答案:

镜像:单个镜像。

仓库:镜像集合。

详细信息:

镜像:由12位十六进制代码(例如91c95931e552)唯一引用的Image ID标识。 [1]

仓库:包含一个或多个镜像。 因此,hello-world仓库可能包含两个不同的镜像:91c95931e5521234abcd5678

镜像别名 - 我将定义镜像别名是指引用特定镜像的别名。 镜像别名的格式是仓库:标签。 这样,您可以使用友好的别名,例如hello-world:latest而不是12位代码。

例子:

假设我有这些镜像:

REPOSITORY           TAG         IMAGE ID
docker/whalesay      latest      fb434121fc77
hello-world          latest      91c95931e552
hello-world          v1.1        91c95931e552
hello-world          v1.0        1234abcd5678

仓库是:docker/whalesayhello-world

镜像分别是 fb434121fc7791c95931e5521234abcd5678。注意第2和第3行具有相同的Image ID,因此它们是相同的镜像。

镜像别名如下:

docker/whalesay:latest
hello-world:latest
hello-world:v1.1
hello-world:v1.0

所以hello-world:latesthello-world:v1.1只是同一镜像的两个别名。

附加细节:

  • 仓库名称格式也可以在使用公共注册表(如Docker Hub)时添加可选的用户或命名空间,这很有用。例如:docker/whalesay。否则,将会出现很多仓库名称冲突。

  • 如果在引用图像别名时省略tag,它将自动添加:latest。因此,当你指定hello-world时,它将被解释为hello-world:latest。警告:其实latest并没有任何特殊含义,它只是一个默认标签。

  • [1]实际上,完整的镜像ID是一个64位十六进制代码,截断到12位数字,但你不需要关心这些。


16

在此定义几个术语,因为它们相互关联:

镜像: 这是用于以容器方式运行应用程序的文件系统层和元数据。每个镜像必须在Docker引擎上有一个ID。

引用: 这是指向镜像的指针。有不同类型的引用,可能是仅镜像ID,通常是存储库和标记,有时您将使用sha256哈希而不是可更改的标记来固定到特定检验和。重要的是,您可以对同一镜像具有多个指针,并且除了镜像ID之外,没有必要拥有任何对镜像的引用。当您删除引用时,Docker将仅删除该指针,除非它是该镜像ID的最后一个指针。

注册表: 这是保存镜像的服务器。与Git服务器保存源代码或二进制文件的构件服务器类似,注册表是您推送和拉取镜像的地方。

存储库: 在注册表服务器上,映像目录的路径就是存储库。如果您未使用默认的Docker Hub注册表,则包括注册表主机名和端口。在镜像引用中,此存储库是冒号和标记之前的部分。

标记: 存储库中的特定镜像。如果未指定标记,Docker将默认使用标记名称“latest”。这是冒号后面的部分,并且通常用于版本编号。


以一个引用示例为例:

registry-server:5000/team/service-a:build-42
  • "registry-server:5000" 是注册表服务器名称(和端口),您将推送/拉取此镜像的地方。

  • "registry-server:5000/team/service-a" 是存储库。

  • "build-42" 是标签。

  • "registry-server:5000/team/service-a:build-42" 是引用。

与其他系统不同,您将docker镜像推送和拉取到注册表服务器时,使用包含存储库和标签的引用来定义镜像的目标和源,而不是特定的文件。因此,要将镜像推送到不同的位置,您需要使用docker tag命令创建一个新的引用,将相同的镜像指向新的存储库和标签,然后对该引用运行推送命令。

通常,当有人提到“图像名称”时,他们指的是存储库名称(如果您想单独指定标记)或完整引用,您可以使用它来拉取或推送镜像。


如何列出我的存储库?

docker image ls --format '{{.Repository}}' | sort -u

我加入了sort -u来去重输出,因为您可能有多个具有相同仓库但不同标签的镜像。


“镜像仓库服务器上存储图像的目录路径被称为仓库。这是一个很好的解释。+1。我认为它是给要在仓库中定位的镜像命名的。” - Dexter

15

引用自官方 Docker 文档:

一个仓库可以存储多个镜像的变体。

(参见:https://docs.docker.com/userguide/dockerimages)

这意味着:一个 Docker 镜像可以属于一个仓库,例如当它被推送到 Docker 注册表时(使用 docker push my/reporitory:version1)。而一个仓库则包含了一个镜像的多个版本(即不同的标签)。因此,当你构建镜像的一个新版本时,你可以给它打上一个标签(docker tag 518a41981a6a my/reporitory:version2),并将其作为下一个版本推送到你的仓库中(docker push my/reporitory:version2)。

以下是 Docker 文档中的例子(请参阅上面的链接)。你可以看到,它展示了一个名为 ouruser/sinatra 的仓库,其中包含同一镜像的各种版本(latestdevelv2):

$ docker images ouruser/sinatra
REPOSITORY          TAG     IMAGE ID      CREATED        VIRTUAL SIZE
ouruser/sinatra     latest  5db5f8471261  11 hours ago   446.7 MB
ouruser/sinatra     devel   5db5f8471261  11 hours ago   446.7 MB
ouruser/sinatra     v2      5db5f8471261  11 hours ago   446.7 MB

在你的例子中,你有两个仓库(docker/whalesayhello-world),每个仓库只包含一个已标记的镜像(称为latest,实际上这意味着没有标签,最新的镜像将被显示)。


那么,即使它们具有相同的ID,这三个图像是否可能不同? - qntm
是的,你可以这样做:你有一个ID为5db5f8471261的图像。现在你可以使用一些新版本标记这个图像:docker tag 5db5f8471261 ouruser/sinatra:myversion。这将向现有仓库(ouruser/sinatra)添加一个新版本(myversion)。如果你调用docker images,你会看到一个更多的条目,然而图像ID将是相同的(5db5f8471261),因为图像没有改变,它只是“一个新名字”。 - Thomas Uhrig
版本和标签有什么区别? - qntm
4
“Repository”这个术语是什么意思?我很困惑。 - Charlie Parker
4
Docker仓库是一组具有相同名称但具有不同标签的Docker镜像集合。标签是存储库中映像的字母数字标识符。 - Dennis
显示剩余3条评论

7
我会尝试以非常明确和清晰的方式解释这个问题。 Docker镜像名称
实际上,Docker镜像本身没有一个固定的名称。它有一个ID仓库和一个标签(根据Docker文档,标签代表的是“目标镜像”,而不是英语单词“tag”)。因此,每次我们提到Docker镜像名称(无论是创建、运行、删除、拉取还是其他操作),我们实际上是在提到镜像仓库:标签(目标镜像)。
我们经常会省略标签部分(只写仓库名称,将其视为镜像名称),这时Docker会默认使用:latest标签(即目标镜像的最新版本)。 Docker仓库
在构建/创建镜像时,Docker会为该镜像创建仓库镜像本身,并将当前(:latest标签)的镜像添加到该仓库中。根据Kubernetes in Action一书作者Marko Luksa所说,镜像标签使我们可以在同一个镜像名称下拥有同一个镜像的多个版本(标签)。因此,我们可以在同一个标识符下拥有myapp:latestmyapp:v1myapp:v2等多个标签,每个标签都将指向特定的目标镜像,即同一应用程序的特定快照/版本。
这就是为什么Docker命名镜像仓库并将区分工作留给标签,因为一个仓库可能(必须)包含不同版本的同一应用程序
因此,如果我们运行docker build -t A .,docker实际上将创建一个Image Repository A和镜像本身(带有:latest标签)。然后,它将把该镜像添加到存储库A中。稍后,我们将能够推送/拉取该镜像的特定快照。
附注: 我们通常称呼Docker镜像名称的方式是(并且可以假定为)Docker镜像仓库[:tagname],后者是可选的,默认为:latest 您可以通过尝试删除没有指定标签的镜像,并且当该镜像仓库中没有默认的:latest镜像时进行测试并证明自己。只需运行docker rmi myimage,您会看到docker会抱怨说Error: No such image: myiamge,因为默认情况下(当您不提供标签时),它会假定并暗示:latest标签。
希望这能更好地解释这个主题。

1
不错的增强,你成功地提供了一些新信息 ;-) - GhostCat
你在哪里看到“tag”代表“目标图像”?能提供一个链接吗? - BMitch

4

镜像是通过使用给定的Dockerfile运行docker build构建的,并且通过其ID进行标识。

仓库和标签只是为了以有意义的层次结构/架构命名和组织您的镜像。

  • 一个仓库通常包含多个相关的镜像

  • 一张图片可以进入多个仓库

下面来自此SO答案,详细解释了docker images输出(这可能是他们应该放在文档中的内容):

  1. IMAGE ID是图像的真实标识符的前12个字符。您可以创建给定图像的许多标记,但它们的ID将都相同(如上所述)。

  2. REPOSITORY列中的值来自docker build命令的-t标志,或者从现有镜像中的docker tag。您可以使用适合您的命名约定对图像进行标记,但是请注意,docker将使用标记作为docker pushdocker pull中的注册表位置。

  3. 标记的完整形式为[REGISTRYHOST/][USERNAME/]NAME[:TAG]。对于上面的ubuntu,REGISTRYHOST被推断为registry.hub.docker.com。因此,如果您计划在docker.example.com上存储名为my-application的图像,则应将该图像标记为docker.example.com/my-application
  4. TAG列只是full标记的[:TAG]部分。这是不幸的术语。

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