我有一堆运行在服务器上的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,并且有一种方法可以获取给定图像的所有标签,并且有一种方法可以获取给定image + tag的摘要。在查看了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
不幸的是,它似乎需要永远完成。我不确定自己做错了什么,但这是我能想到的最好的办法。
关于如何使其正常工作的任何想法?
答案 0 :(得分:4)
我认为这是一种无需检查容器的更好方法,因为docker ps已经打印了创建容器的docker image标签表格。
docker inspect $(docker ps | awk '{print $2}' | grep -v ID) | jq .[].RepoTags
因此,首先获取正在运行的容器的列表,然后检查正在运行的容器使用的每个图像,并使用jq
获取该图像的所有回购标签。
这是输出。
已更新:
这是您要使用 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
答案 1 :(得分:0)
可以使用docker inspect命令。 您可以在这里https://stackoverflow.com/a/54075889/8113039
看一下答案答案 2 :(得分:0)
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 :(得分:0)
如果从注册表中提取图像,则图像检查中的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
不能通过推送到具有相同标签名称的注册表来更改摘要。从注册表中提取更新的标记时,您将看到此摘要更新。