Automatic cleanup of old gcloud container images
I have been using Google Cloud Build for a budget project for roughly a year now. Cloud Build stores built images in a storage bucket which you are of course billed for. Within the first weeks of using it I realized that I needed some automated way to cleanup unused and old images that were built there.
At the time I had a quick search around on the web for something already implemented that I could copy, but I came up blank, and decided putting my problem off would be the best solution. I filed issue number 6 for my project and left it for future me.
Now it’s time to finally close that issue, and I hope others might also find the small bash script useful.
The script
The script uses the gcloud container images list command to first retrieve all images within the stated repository.
It then uses gcloud container images list-tags to get all digests for the images, ordered by timestamp created.
Assuming the latest 3 images might be useful for rollbacks etc the script keeps those around, deleting all other images with gcloud container images delete.
#!/usr/bin/env bash
RED='\033[0;31m'
YELL='\033[1;33m'
NC='\033[0m' # No Color
IMAGES_TO_KEEP="3"
IMAGE_REPO="gcr.io/myproject"
# Get all images at the given image repo
echo -e "${YELL}Getting all images${NC}"
IMAGELIST=$(gcloud container images list --repository=${IMAGE_REPO} --format='get(name)')
echo "$IMAGELIST"
while IFS= read -r IMAGENAME; do
IMAGENAME=$(echo $IMAGENAME|tr -d '\r')
echo -e "${YELL}Checking ${IMAGENAME} for cleanup requirements${NC}"
# Get all the digests for the tag ordered by timestamp (oldest first)
DIGESTLIST=$(gcloud container images list-tags ${IMAGENAME} --sort-by timestamp --format='get(digest)')
DIGESTLISTCOUNT=$(echo "${DIGESTLIST}" | wc -l)
if [ ${IMAGES_TO_KEEP} -ge "${DIGESTLISTCOUNT}" ]; then
echo -e "${YELL}Found ${DIGESTLISTCOUNT} digests, nothing to delete${NC}"
continue
fi
# Filter the ordered list to remove the most recent 3
DIGESTLISTTOREMOVE=$(echo "${DIGESTLIST}" | head -n -${IMAGES_TO_KEEP})
DIGESTLISTTOREMOVECOUNT=$(echo "${DIGESTLISTTOREMOVE}" | wc -l)
echo -e "${YELL}Found ${DIGESTLISTCOUNT} digests, ${DIGESTLISTTOREMOVECOUNT} to delete${NC}"
# Do deletion or say nothing to do
if [ "${DIGESTLISTTOREMOVECOUNT}" -gt "0" ]; then
echo -e "${YELL}Removing ${DIGESTLISTTOREMOVECOUNT} digests${NC}"
while IFS= read -r LINE; do
LINE=$(echo $LINE|tr -d '\r')
gcloud container images delete ${IMAGENAME}@${LINE} --force-delete-tags --quiet
done <<< "${DIGESTLISTTOREMOVE}"
else
echo -e "${YELL}No digests to remove${NC}"
fi
done <<< "${IMAGELIST}"
Code language: PHP (php)
It’s a pretty basic bash script, but hopefully this can serve as a nice copy and paste starting point for people with the same issue as me.
Awesome script! thank you very much for sharing this!
I have one small comment:
This line doesn’t work on macOS, since the version of head doesn’t support negative values to remove n last lines.
As a workaround, need to replace this line –
DIGESTLISTTOREMOVE=$(echo “${DIGESTLIST}” | head -n -${IMAGES_TO_KEEP})
With the following line –
DIGESTLISTTOREMOVE=$(echo “${DIGESTLIST}” | awk -v n=${IMAGES_TO_KEEP} ‘NR>n{print line[NR%n]};{line[NR%n]=$0}’)