首先要说明的是,标签(tag)是指向镜像(image)的指针,镜像是配置和层的 sha256 引用,Docker 使用它们来创建容器。这意味着 `friendlyhello` 不是一个镜像的名称,它是指向镜像的标签。镜像是 id,就像 `c75bebcdd211...`。
其次,每个镜像可以有零个、一个或多个标签与之对应。当没有任何标签指向它时,称之为悬挂式镜像(dangling image)。如果您使用标签构建镜像,然后重新构建它,就会发生这种情况。以前的镜像现在已经取消了标记,因为标签指向新的镜像。同样地,您可以将标签 `image:latest`、`image:v1`、`image:1.0.1` 和 `myrepo:5000/image:1.0` 都指向相同的镜像 ID。
标签具有双重用途。它们可供方便使用。但它们也被 `docker push` 和 `docker pull` 用于查找要发送或检索包的位置。如果您不进行推送或拉取操作,那么您可以随意命名它,别人也不会知道任何区别。但是,如果您想将它存储到注册表中,则标签需要标识出哪个注册表(或默认的 Docker Hub)。该标签还需要标识出存储库后面的版本号。
令人困惑的一点是,存储库名称末尾的短名称通常称为“镜像名称”,冒号后面的版本控制通常称为“标签”。如果忘记这些术语曾经被重载,我认为这样理解会更容易些。
现在有了所有这些背景知识(抱歉,内容有点多),下面是对问题的一些纠正:
docker tag <image> <username>/<repository>:<tag>
把语法看作是:
docker tag <source> <tag>
其中<source>
可以是图像ID,也可以是另一个标签名称。这意味着以下命令将毫无意义:
docker tag <username>/<repository>:<tag>
因为
docker tag
需要指定一个源来打标签,而且它无法确定你当前正在使用的镜像的上下文环境。
最后,为什么要使用除仓库名称之外的名称来命名镜像呢?以下是我遇到的一些原因:
该镜像不会被推送到仓库。这可能是本地测试、工作流程中的中间步骤,或者您在同一系统上构建和运行镜像。
您可能有多个名称指向同一个镜像。 registry/repo/image:v1
和 registry/repo/image:v1.0.1
是一个常见的例子。我还会使用 registry/repo/image:STAGE
来标记特定环境中的当前镜像,以表示它已经通过了开发和CI,并且现在处于暂存环境中。
您可能正在将镜像从一个仓库移动到另一个仓库。我们从 hub.docker.com 拉取镜像,并在本地注册表中重新标记它们。这不仅给我们提供了本地缓存,还让我们能够控制何时将基础镜像更新到下一个版本。这比在生产升级过程中更新的镜像更可取。
我还使用标签来覆盖上游镜像。因此,如果我遇到与上游镜像相关的问题,不必更改所有构建脚本,只需更改并使用上游名称标记即可。只要我不在该 docker 主机上运行拉取操作,就可以使用修改后的基础镜像运行构建。