【发布时间】: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