docker图像名称是如何分析的?

在执行Docker docker push或拉取图像时,Docker如何确定映像名称中是否存在registry服务器,或者如果它是默认registry(例如Docker Hub)上的path/用户名?

我从1.1映像规格中看到以下内容:

标签

标签用于将描述性的用户给定名称映射到任何单个图像ID。 标签值限于字符集[a-zA-Z_0-9]。

知识库

在一个公共前缀下分组的标签集合(之前的名称组件:)。 例如,在名为my-app:3.1.4的图像中,my-app是名称的Repository组件。 存储库名称由斜杠分隔的名称组件组成,可以select以DNS主机名作为前缀。 主机名必须遵守标准DNS规则,但不能包含_字符。 如果存在主机名,则可以select使用8080格式的端口号。 名称组件可能包含小写字符,数字和分隔符。 分隔符被定义为句点,一个或两个下划线或一个或多个破折号。 名称组件不能以分隔符开始或结束。

对于DNS主机名,它是否需要用点来完全限定,或者是“my-local-server”是一个有效的registry主机名? 对于名称组件,我看到有效期,这意味着“team.user / appserver”是一个有效的图像名称。 如果registry服务器在端口80上运行,并且因此图像名称中的主机名不需要端口号,则主机名与registry服务器上的path之间似乎会有歧义。 我很好奇Docker如何解决这个模糊问题。

TL; DR:主机名必须包含一个. dns分隔符或第一个/之前的a : port分隔符,否则代码假定您需要默认registry。


通过代码挖掘后,我遇到了分布/参考/ reference.go与以下内容:

 // Grammar // // reference := name [ ":" tag ] [ "@" digest ] // name := [hostname '/'] component ['/' component]* // hostname := hostcomponent ['.' hostcomponent]* [':' port-number] // hostcomponent := /([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])/ // port-number := /[0-9]+/ // component := alpha-numeric [separator alpha-numeric]* // alpha-numeric := /[a-z0-9]+/ // separator := /[_.]|__|[-]*/ // // tag := /[\w][\w.-]{0,127}/ // // digest := digest-algorithm ":" digest-hex // digest-algorithm := digest-algorithm-component [ digest-algorithm-separator digest-algorithm-component ] // digest-algorithm-separator := /[+.-_]/ // digest-algorithm-component := /[A-Za-z][A-Za-z0-9]*/ // digest-hex := /[0-9a-fA-F]{32,}/ ; At least 128 bit digest value 

这个的实际实现是通过distribution / reference / regexp.go中的正则expression式。

但是通过一些挖掘和挖掘,我发现除了这个正则expression式之外还有另一个检查(如果不包含.或者,你会得到一个大写的主机名错误)。 我在docker / reference.go中追踪了以下名称的实际拆分:

 func splitHostname(name string) (hostname, remoteName string) { i := strings.IndexRune(name, '/') if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") { hostname, remoteName = DefaultHostname, name } else { hostname, remoteName = name[:i], name[i+1:] } if hostname == LegacyDefaultHostname { hostname = DefaultHostname } if hostname == DefaultHostname && !strings.ContainsRune(remoteName, '/') { remoteName = DefaultRepoPrefix + remoteName } return } 

对我来说,重要的一点是检查.:在第一个/在第一个if语句之前。 有了它,主机名就从第一个/之前分离出来,没有它,整个名称就被传递给默认的registry主机名。