docker 我是否可以在不下载映像的情况下获取映像摘要?

qyzbxkaa  于 2022-12-18  发布在  Docker
关注(0)|答案(9)|浏览(143)

类似于问题“What´s the sha256 code of a docker 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
$

另一个问题What is the Docker registry v2 API endpoint to get the digest for an image的答案建议使用Docker-Content-Digest头文件。
当我获取映像的清单时,我可以看到有一个Docker-Content-Digest头:

$ 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

然而,这个标题是不一样的。pull命令得到了6f21,而标题显示了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标记(它一直在变化)转换成一个固定摘要的方法,这样我就可以可靠地提取它,但我不想为了进行转换而实际上将它拉下来。

c6ubokkw

c6ubokkw1#

编辑2022年10月4日:

# INPUT
REPO=waisbrot/wait
user=my-user
password=my-password

# Get TOKEN
username_password_base64=$(echo -n $user:$password | base64)

TOKEN=$(curl -s -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' \
        | jq -r .token)

# GET Digest from v2 API
curl -s -D - -H "Authorization: Bearer $TOKEN" \
     https://registry-1.docker.io/v2/waisbrot/wait/manifests/latest 2>&1 \
  | grep docker-content-digest \
  | cut -d' ' -f2

原#答:

对于较新版本的Docker,inspect命令提供了正确的值(要求图像已经被拉取,正如Jan Hudec在评论中指出的那样):

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'


获取该值的天真尝试会失败,因为服务器选择的默认内容类型是application/vnd.docker.distribution.manifest.v1+prettyjws(v1清单),而您需要v2清单。因此,您需要将Accept标头设置为application/vnd.docker.distribution.manifest.v2+json

ycggw6v2

ycggw6v22#

这就是今天使用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"
        }
  },
  ...
}
6jjcrrmo

6jjcrrmo3#

用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)"'

示例:
x一个一个一个一个x一个一个二个x

qnakjoqk

qnakjoqk4#

我最近遇到一个任务,需要查看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
4zcjmb1e

4zcjmb1e5#

我意识到这个问题得到了回答,但要么我错过了一些东西或当前版本的AWS ECR注册表服务不工作的预期。
当尝试使用HEAD从AWS ECR获取摘要,并且尝试切换内容类型时,没有返回摘要值,我可以使用该值使用注册表API拉取图像。
要获取此摘要,您必须获取感兴趣的标记的清单,并按原样计算响应Json的sha256,包括格式,但不包括签名部分

4zcjmb1e

4zcjmb1e6#

我也很纠结这个问题。如果有人感兴趣的话,这里有一个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; }

}
dwthyt8l

dwthyt8l7#

正如在其他回答中提到的,这个摘要不匹配,因为您试图在没有Accept头的情况下进行curl,因此注册中心触发了一个回退到旧的v1映像清单:

< Content-Type: application/vnd.docker.distribution.manifest.v1+prettyjws
< Docker-Content-Digest: sha256:128c6e3534b842a2eec139999b8ce8aa9a2af9907e2b9269550809d18cd832a3

您可以使用如下脚本使用curl查询Hub:

#!/bin/sh

ref="${1:-library/ubuntu:latest}"
sha="${ref#*@}"
if [ "$sha" = "$ref" ]; then
  sha=""
fi
wosha="${ref%%@*}"
repo="${wosha%:*}"
tag="${wosha##*:}"
if [ "$tag" = "$wosha" ]; then
  tag="latest"
fi
cto="application/vnd.oci.image.index.v1+json"
ctol="application/vnd.oci.image.manifest.v1+json"
ctd="application/vnd.docker.distribution.manifest.v2+json"
ctdl="application/vnd.docker.distribution.manifest.list.v2+json"
token=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:${repo}:pull" \
        | jq -r '.token')
curl -H "Accept: ${cto}" -H "Accept: ${ctol}" -H "Accept: ${ctd}" -H "Accept: ${ctdl}" \
     -H "Authorization: Bearer $token" \
     -I -s "https://registry-1.docker.io/v2/${repo}/manifests/${sha:-$tag}"

然而,这是有限制的,因为它是特定于Hub的,您仍然需要解析头部。从skopeo输出中,它仍然拉取整个清单,而不是HEAD请求,这将计入Hub速率限制。
相反,我更喜欢的两个工具是go-containerregistry/起重机和regclient/regctl(我是后者的作者),每个工具都有一个digest命令,自动处理不同注册表的身份验证,包括所需的Accept头,并将输出解析为摘要,这对脚本编写很有用:

$ regctl image digest busybox
sha256:3b3128d9df6bbbcc92e2358e596c9fbd722a437a62bafbc51607970e9e3b8869

$ crane digest busybox
sha256:3b3128d9df6bbbcc92e2358e596c9fbd722a437a62bafbc51607970e9e3b8869


为了避免安装其他工具,docker现在有docker buildx imagetools inspect,但类似于skopeo,这是拉取整个清单,而不是HEAD请求:

$ docker buildx imagetools inspect busybox
Name:      docker.io/library/busybox:latest
MediaType: application/vnd.docker.distribution.manifest.list.v2+json
Digest:    sha256:3b3128d9df6bbbcc92e2358e596c9fbd722a437a62bafbc51607970e9e3b8869
...

$ docker buildx imagetools inspect busybox --format '{{json .}}' | jq -r .manifest.digest
sha256:3b3128d9df6bbbcc92e2358e596c9fbd722a437a62bafbc51607970e9e3b8869
js5cn81o

js5cn81o8#

根据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
hpxqektj

hpxqektj9#

你可以使用docker inspect来得到这个:
docker inspect --format='{{index .RepoDigests 0}}' ${IMAGE_NAME}
文件:https://docs.docker.com/engine/reference/commandline/inspect/
这至少从v1.9开始就已到位。

相关问题