当执行docker push
或拉动图像时,Docker如何确定图像名称中是否存在注册服务器,或者它是默认注册表(例如Docker Hub)上的路径/用户名? / p>
我在1.1 image specification看到以下内容:
代码
标记用于将描述性的,用户指定的名称映射到任何单个图像 ID。标签值仅限于字符集[a-zA-Z_0-9]。
存储库
在公共前缀(名称组件)下分组的标签集合 之前:)。例如,在标记为my-app:3.1.4的图像中, my-app是名称的Repository组件。存储库名称是 由斜杠分隔的名称组件组成,可选地以a为前缀 DNS主机名。主机名必须遵循标准DNS规则, 但可能不包含_字符。如果存在主机名,则可以 可选地后跟一个格式为8080的端口号。名称 组件可能包含小写字符,数字和分隔符。一个 分隔符定义为句点,一个或两个下划线,或一个或 更多破折号。名称组件不能以分隔符开头或结尾。
对于DNS主机名,是否需要使用点完全限定,或者是" my-local-server"有效的注册表主机名?对于名称组件,我认为句点有效,这意味着" team.user / appserver"是有效的图像名称。如果注册表服务器在端口80上运行,因此图像名称中的主机名上不需要端口号,则主机名和注册表服务器上的路径之间似乎存在歧义。我很好奇Docker如何解决这种歧义。
答案 0 :(得分:12)
TL; DR:主机名必须在第一个.
之前包含:
dns分隔符或/
端口分隔符,否则代码假定您需要默认注册表。
经过一些挖掘代码后,我遇到了distribution/reference/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中的正则表达式。
但是通过一些挖掘和挖掘,我发现除了正则表达式之外还有另一个检查(如果你不包含{{{},那么你会得到一个大写主机名的错误{1}}或.
)。我在docker/distribution/reference/normalize.go中跟踪了名称的实际拆分:
:
对我而言,重要的部分是检查第一个if语句中第一个// splitDockerDomain splits a repository name to domain and remotename string.
// If no valid domain is found, the default domain is used. Repository name
// needs to be already validated before.
func splitDockerDomain(name string) (domain, remainder string) {
i := strings.IndexRune(name, '/')
if i == -1 || (!strings.ContainsAny(name[:i], ".:") && name[:i] != "localhost") {
domain, remainder = defaultDomain, name
} else {
domain, remainder = name[:i], name[i+1:]
}
if domain == legacyDefaultDomain {
domain = defaultDomain
}
if domain == defaultDomain && !strings.ContainsRune(remainder, '/') {
remainder = officialRepoName + "/" + remainder
}
return
}
之前的.
和:
。有了它,主机名就会从第一个/
之前拆分出来,没有它,整个名称就会传递给默认的注册表主机名。
答案 1 :(得分:0)
https://github.com/moby/moby/blob/master/image/spec/v1.1.md处的图片规格现已更新,说标签限制为128个字符。
PR主题在https://github.com/docker/distribution/issues/2248
一些Ruby代码在这里https://github.com/cyber-dojo/runner-stateless/blob/master/src/image_name.rb
一些Ruby测试在https://github.com/cyber-dojo/runner-stateless/blob/master/test_server/image_name_test.rb