I have a bunch of Docker containers running on a server and I used the "latest" tag or no tag at all for all of them. Now I want to freeze the image versions, but I have no idea when I pulled these images, so I can't tell which version "latest" is referring to. docker ps
is just showing me that the containers use the "latest" or no tag, like this:
# 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
...
All images that I use are public images from the docker hub.
I thought maybe I could use the hex ID that docker ps shows for all the containers, but then I realized that the IDs are container IDs and not image IDs.
Is it maybe possible to get the image IDs/hashes of all running containers and then scan for all matching tags or something like that?
Docker version: 18.09.1, build 4c52b90
Edit:
So there have been some answers showing how to get the IDs (digests) of the images, but I need to somehow find the actual tags of those images. After doing some research, I found that the docker hub has an API and that there is a way to get all tags for a given image and there is a way to get the digest for a given image+tag. After looking at the API and a lot of examples from stackoverflow, I came up with this: (It also includes the code required to get the digest of local images, taken form the answers below)
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
Unfortunately it seems to take forever to finish. I'm not sure if I'm doing something wrong, but that's the best thing I could come up with.
Any ideas on how to make this work properly?