我可以在不下载图像的情况下获得图像摘要吗?
Can I get an image digest without downloading the image?
类似于问题“”,我想找到Docker图像的摘要。下载图片时可以看到摘要:
$ docker pull waisbrot/wait:latest
latest: Pulling from waisbrot/wait
Digest: sha256:6f2185daa4ab1711181c30d03f565508e8e978ebd0f263030e7de98deee5f330
Status: Image is up to date for waisbrot/wait:latest
$
另一个问题, 的答案建议 Docker-Content-Digest
header。
当我获取图像的清单时,我可以看到有一个 Docker-Content-Digest
header:
$ curl 'https://auth.docker.io/token?service=registry.docker.io&scope=repository:waisbrot/wait:pull' -H "Authorization: Basic ${username_password_base64}"
# store the resulting token in DT
$ curl -v https://registry-1.docker.io/v2/waisbrot/wait/manifests/latest -H "Authorization: Bearer $DT" -XHEAD
* Trying 52.7.141.30...
* Connected to registry-1.docker.io (52.7.141.30) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate: *.docker.io
* Server certificate: RapidSSL SHA256 CA - G3
* Server certificate: GeoTrust Global CA
> GET /v2/waisbrot/wait/manifests/latest HTTP/1.1
> Host: registry-1.docker.io
> User-Agent: curl/7.43.0
> Accept: */*
> Authorization: Bearer LtVRw-etc-etc-etc
>
< HTTP/1.1 200 OK
< Content-Length: 4974
< Content-Type: application/vnd.docker.distribution.manifest.v1+prettyjws
< Docker-Content-Digest: sha256:128c6e3534b842a2eec139999b8ce8aa9a2af9907e2b9269550809d18cd832a3
< Docker-Distribution-Api-Version: registry/2.0
< Etag: "sha256:128c6e3534b842a2eec139999b8ce8aa9a2af9907e2b9269550809d18cd832a3"
< Date: Wed, 07 Sep 2016 16:37:15 GMT
< Strict-Transport-Security: max-age=31536000
然而,这 header 不一样。 pull
命令让我 6f21
而 header 显示 128c
。此外,pull 命令不适用于该摘要:
$ docker pull waisbrot/wait@sha256:128c6e3534b842a2eec139999b8ce8aa9a2af9907e2b9269550809d18cd832a3
Error response from daemon: manifest unknown: manifest unknown
而当我有正确的摘要时,事情就如我所愿:
$ docker pull waisbrot/wait@sha256:6f2185daa4ab1711181c30d03f565508e8e978ebd0f263030e7de98deee5f330 12:46 waisbrot@influenza
sha256:6f2185daa4ab1711181c30d03f565508e8e978ebd0f263030e7de98deee5f330: Pulling from waisbrot/wait
Digest: sha256:6f2185daa4ab1711181c30d03f565508e8e978ebd0f263030e7de98deee5f330
Status: Image is up to date for waisbrot/wait@sha256:6f2185daa4ab1711181c30d03f565508e8e978ebd0f263030e7de98deee5f330
我正在寻找的是一种将 latest
标记(它一直在变化)转换为我可以可靠地提取的固定摘要的方法。但我不想真的为了做这个翻译而把它拉下来。
对于 Docker 的较新版本,inspect 命令提供了正确的值:
docker inspect --format='{{index .RepoDigests 0}}' waisbrot/wait
对于旧版本,按照此示例使用主 Docker 存储库从存储库中获取值:
curl -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
-H "Authorization: Basic ${username_password_base64}" \
'https://auth.docker.io/token?service=registry.docker.io&scope=repository:waisbrot/wait:pull'
天真的尝试获取该值失败,因为服务器选择的默认 content-type 是 application/vnd.docker.distribution.manifest.v1+prettyjws
(v1 清单),您需要 v2 清单。因此,您需要将 Accept
header 设置为 application/vnd.docker.distribution.manifest.v2+json
.
我知道这个问题已经得到解决,但是要么我遗漏了一些东西,要么当前版本的 AWS ECR 注册服务没有按预期工作。
当尝试使用任一 HEAD 从 AWS ECR 获取摘要并尝试切换内容类型时,return 不是我可以用来使用注册表提取图像的摘要值 Api.
要获取此摘要,您必须获取您感兴趣的标签的清单,并按原样计算响应的 sha256 Json ,包括格式,不包括签名部分
按照 ByteFlinger 的建议,没有例子,我试了一下,这是如何计算的:
$ docker-ls tag -registry https://myregistry.net:5000
spicysomtam/zookeeper:latest
requesting manifest . done
repository: spicysomtam/zookeeper
tagName: latest
digest: sha256:bd5dd80253171e4dffccbea7c639c90a63d5424aa2d7fe655aea766405c83036
$ curl -ns -H "Accept:
application/vnd.docker.distribution.manifest.v2+json" -X GET
https://myregistry.net:5000/v2/spicysomtam/zookeeper/manifests/latest|sha256sum
bd5dd80253171e4dffccbea7c639c90a63d5424aa2d7fe655aea766405c83036 -
$ docker images --digests |grep zookeeper
myregistry.net:5000/spicysomtam/zookeeper latest sha256:bd5dd80253171e4dffccbea7c639c90a63d5424aa2d7fe655aea766405c83036 a983e71ca22d 29 hours ago 584MB
您可以使用 docker inspect
:
docker inspect --format='{{index .RepoDigests 0}}' ${IMAGE_NAME}
文档:https://docs.docker.com/engine/reference/commandline/inspect/
这至少从 v1.9 开始就已经存在。
2个http请求,就搞定了。第一个获取身份验证令牌,第二个获取按体系结构和变体的图像摘要列表:
token=$(curl --silent "https://auth.docker.io/token?scope=repository:$image:pull&service=registry.docker.io" | jq -r '.token')
curl -s --header "Accept: application/vnd.docker.distribution.manifest.list.v2+json" --header "Authorization: Bearer ${token}" "https://registry-1.docker.io/v2/$image/manifests/$tag" | jq -r '.manifests|.[]| "\(.digest) \(.platform.architecture) \(.platform.variant)"'
示例:
image=library/nginx
tag=stable-alpine
sha256:8853c7e938c2aa5d9d7439e698f0e700f058df8414a83134a09fcbb68bb0707a amd64 null
sha256:dbcd23f95b94018fe72bfdb356e40f4ae8b95063883f3456fedaed1c02204ed4 arm v6
sha256:d3670edcd50bb07cae303767426adf9bc7ba0219736148d30e6f30dd4e08695c arm v7
sha256:0bcd76faa141e4fa37e875834b3994261e0cfc94b7233ac84896381315b845ca arm64 v8
sha256:da8e62ddb3fab89ff4fa0271dbe230f849ab53402a71338503952437dcda1026 386 null
sha256:269bf99e100294b6b75fbdecf7b4ddbef8b29ea0a953e2e904452a50dbc923ab ppc64le null
sha256:103da50956034c157abeffbc869e2e38a4fabbf913bed8ae6ae7c59e646b28a1 s390x null
我最近遇到一个任务,需要查看 sha256 摘要而不必拉取图像。工具 skopeo 调用注册表 API,因此您无需拉取映像。
例如,
$ skopeo inspect --creds "username:password" docker://waisbrot/wait:latest
如果您只想获取摘要值,则可以将其通过管道传输到 jq
。
$ skopeo inspect --creds "username:password" \
docker://waisbrot/wait:latest | jq -r '.Digest'
sha256:6f2185daa4ab1711181c30d03f565508e8e978ebd0f263030e7de98deee5f330
这就是您今天使用 V2 清单的方式。
docker manifest inspect <REMOTE IMAGE>:<TAG> -v
你的输出是JSON:
{
...
"Descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:d13e102941a9f7bd417440f62f9cb29de35f6acb13a26cbf6a34f4c7340f0b63",
"size": 3255,
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
...
}
我也为此苦苦挣扎。如果有人感兴趣,这是一个 C# (dotnet core 5.0) 实现:
/**
TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:waisbrot/wait:pull" | jq -r .token)
curl -s -D - -H "Authorization: Bearer $TOKEN" -H "Accept: application/vnd.docker.distribution.manifest.v2+json" https://index.docker.io/v2/waisbrot/wait/manifests/latest
*/
private string GetRemoteImageDigest(string image, string tag) {
using HttpClient client = new ();
var url = string.Format($"https://auth.docker.io/token?service=registry.docker.io&scope=repository:{image}:pull");
//var response = client.Send(new HttpRequestMessage(HttpMethod.Get, url));
var result = client.GetStringAsync(url);
var drt = JsonSerializer.Deserialize<DockerRegistryToken>(result.Result);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", drt.Token);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.docker.distribution.manifest.v2+json"));
var response = client.GetAsync(string.Format($"https://index.docker.io/v2/{image}/manifests/{tag}"));
var headers = response.Result.Headers;
IEnumerable<string> values;
headers.TryGetValues("Docker-Content-Digest", out values);
return values.FirstOrDefault();
}
DockerRegistryToken 定义为:
public class DockerRegistryToken{
[JsonPropertyName("token")]
public string Token { get; set; }
/// always null
[JsonPropertyName("access_token")]
public string AccessToken {get; set; }
[JsonPropertyName("expires_in")]
public int ExpiresInSeconds { get; set; }
[JsonPropertyName("issued_at")]
public DateTime IssuedAt { get; set; }
}
类似于问题“
$ docker pull waisbrot/wait:latest
latest: Pulling from waisbrot/wait
Digest: sha256:6f2185daa4ab1711181c30d03f565508e8e978ebd0f263030e7de98deee5f330
Status: Image is up to date for waisbrot/wait:latest
$
另一个问题,Docker-Content-Digest
header。
当我获取图像的清单时,我可以看到有一个 Docker-Content-Digest
header:
$ curl 'https://auth.docker.io/token?service=registry.docker.io&scope=repository:waisbrot/wait:pull' -H "Authorization: Basic ${username_password_base64}"
# store the resulting token in DT
$ curl -v https://registry-1.docker.io/v2/waisbrot/wait/manifests/latest -H "Authorization: Bearer $DT" -XHEAD
* Trying 52.7.141.30...
* Connected to registry-1.docker.io (52.7.141.30) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate: *.docker.io
* Server certificate: RapidSSL SHA256 CA - G3
* Server certificate: GeoTrust Global CA
> GET /v2/waisbrot/wait/manifests/latest HTTP/1.1
> Host: registry-1.docker.io
> User-Agent: curl/7.43.0
> Accept: */*
> Authorization: Bearer LtVRw-etc-etc-etc
>
< HTTP/1.1 200 OK
< Content-Length: 4974
< Content-Type: application/vnd.docker.distribution.manifest.v1+prettyjws
< Docker-Content-Digest: sha256:128c6e3534b842a2eec139999b8ce8aa9a2af9907e2b9269550809d18cd832a3
< Docker-Distribution-Api-Version: registry/2.0
< Etag: "sha256:128c6e3534b842a2eec139999b8ce8aa9a2af9907e2b9269550809d18cd832a3"
< Date: Wed, 07 Sep 2016 16:37:15 GMT
< Strict-Transport-Security: max-age=31536000
然而,这 header 不一样。 pull
命令让我 6f21
而 header 显示 128c
。此外,pull 命令不适用于该摘要:
$ docker pull waisbrot/wait@sha256:128c6e3534b842a2eec139999b8ce8aa9a2af9907e2b9269550809d18cd832a3
Error response from daemon: manifest unknown: manifest unknown
而当我有正确的摘要时,事情就如我所愿:
$ docker pull waisbrot/wait@sha256:6f2185daa4ab1711181c30d03f565508e8e978ebd0f263030e7de98deee5f330 12:46 waisbrot@influenza
sha256:6f2185daa4ab1711181c30d03f565508e8e978ebd0f263030e7de98deee5f330: Pulling from waisbrot/wait
Digest: sha256:6f2185daa4ab1711181c30d03f565508e8e978ebd0f263030e7de98deee5f330
Status: Image is up to date for waisbrot/wait@sha256:6f2185daa4ab1711181c30d03f565508e8e978ebd0f263030e7de98deee5f330
我正在寻找的是一种将 latest
标记(它一直在变化)转换为我可以可靠地提取的固定摘要的方法。但我不想真的为了做这个翻译而把它拉下来。
对于 Docker 的较新版本,inspect 命令提供了正确的值:
docker inspect --format='{{index .RepoDigests 0}}' waisbrot/wait
对于旧版本,按照此示例使用主 Docker 存储库从存储库中获取值:
curl -H "Accept: application/vnd.docker.distribution.manifest.v2+json" \
-H "Authorization: Basic ${username_password_base64}" \
'https://auth.docker.io/token?service=registry.docker.io&scope=repository:waisbrot/wait:pull'
天真的尝试获取该值失败,因为服务器选择的默认 content-type 是 application/vnd.docker.distribution.manifest.v1+prettyjws
(v1 清单),您需要 v2 清单。因此,您需要将 Accept
header 设置为 application/vnd.docker.distribution.manifest.v2+json
.
我知道这个问题已经得到解决,但是要么我遗漏了一些东西,要么当前版本的 AWS ECR 注册服务没有按预期工作。
当尝试使用任一 HEAD 从 AWS ECR 获取摘要并尝试切换内容类型时,return 不是我可以用来使用注册表提取图像的摘要值 Api.
要获取此摘要,您必须获取您感兴趣的标签的清单,并按原样计算响应的 sha256 Json ,包括格式,不包括签名部分
按照 ByteFlinger 的建议,没有例子,我试了一下,这是如何计算的:
$ docker-ls tag -registry https://myregistry.net:5000
spicysomtam/zookeeper:latest
requesting manifest . done
repository: spicysomtam/zookeeper
tagName: latest
digest: sha256:bd5dd80253171e4dffccbea7c639c90a63d5424aa2d7fe655aea766405c83036
$ curl -ns -H "Accept:
application/vnd.docker.distribution.manifest.v2+json" -X GET
https://myregistry.net:5000/v2/spicysomtam/zookeeper/manifests/latest|sha256sum
bd5dd80253171e4dffccbea7c639c90a63d5424aa2d7fe655aea766405c83036 -
$ docker images --digests |grep zookeeper
myregistry.net:5000/spicysomtam/zookeeper latest sha256:bd5dd80253171e4dffccbea7c639c90a63d5424aa2d7fe655aea766405c83036 a983e71ca22d 29 hours ago 584MB
您可以使用 docker inspect
:
docker inspect --format='{{index .RepoDigests 0}}' ${IMAGE_NAME}
文档:https://docs.docker.com/engine/reference/commandline/inspect/
这至少从 v1.9 开始就已经存在。
2个http请求,就搞定了。第一个获取身份验证令牌,第二个获取按体系结构和变体的图像摘要列表:
token=$(curl --silent "https://auth.docker.io/token?scope=repository:$image:pull&service=registry.docker.io" | jq -r '.token')
curl -s --header "Accept: application/vnd.docker.distribution.manifest.list.v2+json" --header "Authorization: Bearer ${token}" "https://registry-1.docker.io/v2/$image/manifests/$tag" | jq -r '.manifests|.[]| "\(.digest) \(.platform.architecture) \(.platform.variant)"'
示例:
image=library/nginx
tag=stable-alpine
sha256:8853c7e938c2aa5d9d7439e698f0e700f058df8414a83134a09fcbb68bb0707a amd64 null
sha256:dbcd23f95b94018fe72bfdb356e40f4ae8b95063883f3456fedaed1c02204ed4 arm v6
sha256:d3670edcd50bb07cae303767426adf9bc7ba0219736148d30e6f30dd4e08695c arm v7
sha256:0bcd76faa141e4fa37e875834b3994261e0cfc94b7233ac84896381315b845ca arm64 v8
sha256:da8e62ddb3fab89ff4fa0271dbe230f849ab53402a71338503952437dcda1026 386 null
sha256:269bf99e100294b6b75fbdecf7b4ddbef8b29ea0a953e2e904452a50dbc923ab ppc64le null
sha256:103da50956034c157abeffbc869e2e38a4fabbf913bed8ae6ae7c59e646b28a1 s390x null
我最近遇到一个任务,需要查看 sha256 摘要而不必拉取图像。工具 skopeo 调用注册表 API,因此您无需拉取映像。
例如,
$ skopeo inspect --creds "username:password" docker://waisbrot/wait:latest
如果您只想获取摘要值,则可以将其通过管道传输到 jq
。
$ skopeo inspect --creds "username:password" \
docker://waisbrot/wait:latest | jq -r '.Digest'
sha256:6f2185daa4ab1711181c30d03f565508e8e978ebd0f263030e7de98deee5f330
这就是您今天使用 V2 清单的方式。
docker manifest inspect <REMOTE IMAGE>:<TAG> -v
你的输出是JSON:
{
...
"Descriptor": {
"mediaType": "application/vnd.docker.distribution.manifest.v2+json",
"digest": "sha256:d13e102941a9f7bd417440f62f9cb29de35f6acb13a26cbf6a34f4c7340f0b63",
"size": 3255,
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
...
}
我也为此苦苦挣扎。如果有人感兴趣,这是一个 C# (dotnet core 5.0) 实现:
/**
TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:waisbrot/wait:pull" | jq -r .token)
curl -s -D - -H "Authorization: Bearer $TOKEN" -H "Accept: application/vnd.docker.distribution.manifest.v2+json" https://index.docker.io/v2/waisbrot/wait/manifests/latest
*/
private string GetRemoteImageDigest(string image, string tag) {
using HttpClient client = new ();
var url = string.Format($"https://auth.docker.io/token?service=registry.docker.io&scope=repository:{image}:pull");
//var response = client.Send(new HttpRequestMessage(HttpMethod.Get, url));
var result = client.GetStringAsync(url);
var drt = JsonSerializer.Deserialize<DockerRegistryToken>(result.Result);
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", drt.Token);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.docker.distribution.manifest.v2+json"));
var response = client.GetAsync(string.Format($"https://index.docker.io/v2/{image}/manifests/{tag}"));
var headers = response.Result.Headers;
IEnumerable<string> values;
headers.TryGetValues("Docker-Content-Digest", out values);
return values.FirstOrDefault();
}
DockerRegistryToken 定义为:
public class DockerRegistryToken{
[JsonPropertyName("token")]
public string Token { get; set; }
/// always null
[JsonPropertyName("access_token")]
public string AccessToken {get; set; }
[JsonPropertyName("expires_in")]
public int ExpiresInSeconds { get; set; }
[JsonPropertyName("issued_at")]
public DateTime IssuedAt { get; set; }
}