【问题标题】:How to find all image tags of a running Docker container?如何找到正在运行的 Docker 容器的所有镜像标签?
【发布时间】:2019-10-31 23:13:13
【问题描述】:

我在服务器上运行了一堆 Docker 容器,我对所有容器都使用了“最新”标签或根本没有标签。现在我想冻结图像版本,但我不知道我什么时候提取这些图像,所以我不知道“最新”指的是哪个版本。 docker ps 只是告诉我容器使用“最新”或没有标签,如下所示:

# docker ps
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS               NAMES
371d6675888b        node:latest            "npm start"              6 days ago          Up 2 hours                              project_xyz_1
ca5a75425a34        selenium/node-chrome   "/usr/bin/nohup go..."   6 days ago          Up 2 hours                              project_xyz-chrome_1
...

我使用的所有图像都是来自 docker hub 的公共图像。

我想也许我可以使用 docker ps 为所有容器显示的十六进制 ID,但后来我意识到这些 ID 是容器 ID,而不是图像 ID。

是否有可能获取所有正在运行的容器的图像 ID/哈希值,然后扫描所有匹配的标签或类似的东西?

Docker 版本:18.09.1,构建 4c52b90

编辑:

所以有一些答案显示了如何获取图像的 ID(摘要),但我需要以某种方式找到这些图像的实际标签。 在做了一些研究之后,我发现 docker hub 有一个 API,并且有一种方法可以获取给定图像的所有标签,并且有一种方法可以获取给定图像+标签的摘要。在查看了 API 和来自 stackoverflow 的大量示例之后,我想出了这个: (它还包括获取本地图像摘要所需的代码,取自以下答案)

function getDigestByImageNameWithTag () {
    TARGET_IMAGE_NAME_WITH_TAG="$1" # works with and without tag
    docker image inspect --format '{{index .RepoDigests 0}}' "$TARGET_IMAGE_NAME_WITH_TAG" | cut -d '@' -f2
}

function getTagsByDigest () {
    TARGET_IMAGE_NAME="$1"
    TARGET_DIGEST="$2"

    # prepend the image name with "library/" if it doesn't contain a slash
    if [[ $TARGET_IMAGE_NAME != *"/"* ]]; then
        TARGET_IMAGE_NAME="library/$TARGET_IMAGE_NAME"
    fi

    # get authorization token for the given image name
    TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:$TARGET_IMAGE_NAME:pull" | jq -r .token)

    # find all tags for the given image name
    ALL_TAGS=$(curl -s -H "Authorization: Bearer $TOKEN" https://index.docker.io/v2/$TARGET_IMAGE_NAME/tags/list | jq -r .tags[])

    # itate over all these tags
    for TAG in ${ALL_TAGS[@]}; do
        # get image digest
        DIGEST=$(curl -s -D - -H "Authorization: Bearer $TOKEN" -H "Accept: application/vnd.docker.distribution.manifest.v2+json" https://index.docker.io/v2/$TARGET_IMAGE_NAME/manifests/$TAG | grep Docker-Content-Digest | cut -d ' ' -f 2)
        # if the tag matches the given digest
        if [[ $TARGET_DIGEST = $DIGEST ]]; then
            # "return" the tag
            echo "$TAG"
        fi
    done
}

function getContainerImageNames () {
    docker inspect $(docker ps  | awk '{print $2}' | grep -v ID) | jq .[].RepoTags | grep -v "\[" | grep -v "\]" | grep " " | cut -d '"' -f2 | cut -d '/' -f2-
}


# get all image names of all local containers
IMGS_WITH_TAG=$(getContainerImageNames)
# iterate of those image names
for IMAGE_NAME_WITH_TAG in ${IMGS_WITH_TAG[@]}; do
    # get the digest of the current iteration's IMAGE_NAME_WITH_TAG
    DIGEST=$(getDigestByImageNameWithTag $IMAGE_NAME_WITH_TAG)
    echo "TARGET_DIGEST: $DIGEST" 
    # get the raw image name without the tag
    IMAGE_NAME=$(echo "$IMAGE_NAME_WITH_TAG" | cut -d ':' -f1)
    # find all tags for this image that have the same digest
    MATCHING_TAGS=$(getTagsByDigest $IMAGE_NAME $DIGEST)
    echo "Image: $IMAGE_NAME_WITH_TAG"
    echo "Image digest: $IMAGE_NAME"
    echo "Image tags with same digest: "
    echo "$MATCHING_TAGS"
    echo "-----------------------------"
done

不幸的是,它似乎需要很长时间才能完成。我不确定我是否做错了什么,但这是我能想到的最好的办法。

关于如何使其正常工作的任何想法?

【问题讨论】:

  • docker ps | awk '{print $2}' | grep -v ID 只是docker ps --format '{{.ID}}'。你能发布什么方法来测试你的脚本并用一些标签填充一些 docker 图像吗?
  • 好吧,你只需要安装 docker 和 jq 然后你至少需要启动一个容器。例如:docker run -d -t --name=test node:11 bash。据我了解,在这种情况下,具有相同摘要的标签现在将是 11.15.0-stretch、11.15-stretch、11-stretch、11.15.0、11.15、11。所以脚本应该返回那些..
  • 因为你比较不必要的标签,只比较你在本地系统上使用的那些标签以节省时间,你可以查看我更新的答案。
  • 数组使用错误。添加一个shebang,然后将您的脚本粘贴到那里:shellcheck.net
  • @Cyrus shellcheck 没有显示任何错误。它只是警告可能不需要的拆分和通配,我认为这不是这个脚本的问题。

标签: linux bash docker docker-container docker-image


【解决方案1】:

docker inspect 命令可用于此。 您可以在这里查看答案https://stackoverflow.com/a/54075889/8113039

【讨论】:

  • 这只会让我得到图像 ID。我还需要一种方法来获取给定提取的图像 ID 的标签。
【解决方案2】:

Docker 镜像和容器由 ID 标识,对于正在运行的容器,您可以获取其镜像的 Id,然后拉取与给定 ID 对应的镜像。

首先,您需要在所有正在运行的容器上使用docker inspect,以获取容器所基于的映像的sha256 ID。

docker inspect返回"Image"下的图片ID:

{
  "Id": "6de053a2afa4499471c5e5c2afe0b0d83c9c7e50fc7e687fb63a7ebfd2bff320",
  ...
  },
  "Image": "sha256:26eb6780e26887a6838684a549562c0404fd85c55f71e0af6c79a4da5505d2a7",
  ....
}

然后您只需通过摘要(不可变标识符)提取这些图像

$ docker pull node@sha256:the-image-digest-here

$ docker pull node@sha256:26eb6780e26887a6838684a549562c0404fd85c55f71e0af6c79a4da5505d2a7

如果幸运的话,与这些摘要相对应的图像仍然可以在 docker hub 中使用。

在那之后,您是否仍然面对latest 图像,我建议您使用正确的名称和标签重命名这些图像,并将它们拉到您自己的 docker hub 存储库中,以便能够直接使用它们......

【讨论】:

    【解决方案3】:

    我认为这是一种更好的方法,无需检查容器,因为 docker ps 已经打印了创建容器的 docker 图像标签表单。

    docker inspect $(docker ps  | awk '{print $2}' | grep -v ID) | jq .[].RepoTags
    

    所以首先获取正在运行的容器列表,然后检查正在运行的容器使用的每个映像,并使用jq 获取该映像的所有 repo 标签。

    这是输出。

    更新:

    这是你使用 skopeo 的地方,你可以使用 API 但会付出努力,那么为什么如果你有 skopeo

    你不需要安装skopeo你可以运行容器然后或删除一次得到结果,或者你可以安装,脚本支持两者

    running_container=$(docker ps  | awk '{print $2}' | grep -v ID) 
    echo "running container: $running_container"
    for image in $running_container
    do
    local_tag=$(echo "$image" | awk -F":" '{print $2}')
    if [ -z $local_tag ]; then
    # if tag is empty then tag is latest
    local_tag="latest"
    image="$image":"$local_tag"
    fi
    local_digest=$(docker inspect $image | jq '.[].RepoDigests[]' | awk -F"@" '{print $2}' | tr -d '"')
    echo "Local digest is:" $local_digest
    remote_digest=$(docker run --rm --env image=$image alexeiled/skopeo:latest ash -c "skopeo inspect docker://docker.io/$image" | jq '.Digest' | tr -d '"' )
    echo $remote_digest 
    
    # option2 install the skopeo on your local system
    # remote_digest=$(skopeo inspect docker://docker.io/$image | jq '.Digest' | tr -d '"')
    echo "Remote digest is : "$remote_digest
    
    if [ "${local_digest}" == "${remote_digest}" ]; then
    echo "local image is up to date with remote"
    else
    echo "Remote image is updated; please run docker pull $image"
    fi
    done
    

    【讨论】:

    • 我喜欢这个!但是这样做你有任何保证,例如当前运行的alpine:latest 与当前在 docker hub 上可用的alpine:latest 相同吗?
    • 嗨@Nirekin,我刚刚检查过,请给你
    • @Forivin 你试过我的回答了吗?
    【解决方案4】:

    如果您从注册表中提取图像,则图像检查中的 RepoDigest 字段将具有 sha256 引用:

    docker ps --format '{{.Image}}' | xargs \
      docker image inspect --format '{{if .RepoDigests}}{{index .RepoDigests 0}}{{end}}'
    

    对于您主机上的node:latest 之类的单个图像,它看起来像:

    docker image inspect --format '{{index .RepoDigests 0}}' node:latest
    

    无法通过推送到具有相同标签名称的注册表来更改该摘要。当您从注册表中提取更新的标签时,您将看到此摘要更新。

    【讨论】:

    • 好的,那么我会有一个摘要,但我想有类似node:10.7.3 而不是node@sha256:0aec4c38431c386877888c612a9340b1132bbeb4dc4af5b5ff54b9310d48e5a1 因为后者我不知道是否必须更新漏洞在我的版本中找到。
    • @Forivin 您在本地没有此信息。您只提取了指向静态 sha256 的 latest 。所有其他标签都在注册服务器上,远程查询每个标签并查看它使用的存储库摘要需要一些工作,特别是考虑到可能更新的多架构图像和标签。
    • @Forivin 如果 repo 使用 semver,那么最好的做法是指定适用于您的应用的最广泛的依赖关系,例如node:10 而不是 node:10.7.3,然后定期拉取新镜像并重新部署您的容器。
    • 但是应该可以使用 docker hub API 来检索信息吧?我知道我可以使用registry.hub.docker.com/v2/repositories/library/node/tags/… 等来获取有关所有可能标签的一些信息。它只是缺少摘要信息。
    • @Forivin 可能:是的。琐碎:没有。
    猜你喜欢
    • 1970-01-01
    • 2022-11-09
    • 2019-10-09
    • 1970-01-01
    • 2016-10-28
    • 2022-10-15
    • 2021-02-18
    • 2017-08-04
    • 2017-10-17
    相关资源
    最近更新 更多