Skip to content

Instantly share code, notes, and snippets.

@Cellane
Last active January 20, 2020 05:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Cellane/0d98756c244d78413f88ab02db784b6f to your computer and use it in GitHub Desktop.
Save Cellane/0d98756c244d78413f88ab02db784b6f to your computer and use it in GitHub Desktop.
Check updates for Docker images from Docker Hub or private repository, and deploy updated versions to Dokku

Automatic update of Docker image based applications in Dokku

Check updates for Docker images from Docker Hub or private repository, and deploy updated versions to Dokku.

Requirements

  • Bash 4+
  • jq
  • … Dokku, probably? 🤔

Usage

  1. Update the images and privateImages arrays to match your setup
    • The key (blog, matomo, etc.) must correspond to the application name in Dokku
    • For public images, the value is a semicolon-separated string with two values:
      • The first value is Docker Hub path; for official images, replace _ in URL with library (see ghost example); for user images, use both organization name and repository name (see portainer example)
      • The second value is an escaped regex to filter through the retrieved tags; only tags matching the filter will be considered for updates; when in doubt, blame the regex
    • For private images, the value is a semicolon-separated string with five values:
      • The first value is URL for obtaining JWT token
      • The second value is URL for listing all the tags
      • The third value is username for the repository
      • The fourth value is password for the repository
      • The fifth value is regex again
  2. Set the script as executable with chmod u+x update-images.bash
  3. Run the script with ./update-images.bash
declare -A images
declare -A privateImages
images=(
["blog"]='https://registry.hub.docker.com/v2/repositories/library/ghost/;^3\\.[[:digit:]]\\+\\.[[:digit:]]\\+-alpine$'
["matomo"]='https://registry.hub.docker.com/v2/repositories/library/matomo/;^[[:digit:]]\\+\\.[[:digit:]]\\+\\.[[:digit:]]\\+$'
["office"]='https://registry.hub.docker.com/v2/repositories/onlyoffice/documentserver/;^[[:digit:]]\\+\\.[[:digit:]]\\+\\.[[:digit:]]\\+\\.[[:digit:]]\\+$'
["portainer"]='https://registry.hub.docker.com/v2/repositories/portainer/portainer/;^[[:digit:]]\\+\\.[[:digit:]]\\+\\.[[:digit:]]\\+$'
)
privateImages=(
["files"]='https://docker.seadrive.org/service/token?service=harbor-registry&scope=repository:seafileltd/seafile-pro-mc:pull;https://docker.seadrive.org/v2/seafileltd/seafile-pro-mc/tags/list;<username>;<password>;^7\\.[[:digit:]]\\+\\.[[:digit:]]\\+$'
)
#!/usr/bin/env bash
set -e
source ./images
updated=false
resolve() {
image=$1
currentVersion=$2
latestVersion=$3
printf "%30s %s\n" "Currently detected version:" $currentVersion
printf "%30s %s\n\n" "Latest version found:" $latestVersion
if [ "$currentVersion" = "$latestVersion" ]; then
echo "No new version detected. Skipping…"
echo "====> Finished $image"
return
fi
read -p "Is the above correct? Proceed with update? " -r
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "User aborted. Skipping…"
echo "====> Finished $image"
return
fi
currentImageId=$(dokku tags ${image} | grep dokku | grep latest | awk '{ print $3 }')
imageName=$(docker image ls | grep -v latest | grep -v dokku | grep ${currentImageId} | awk '{ print $1 }')
dokkuVersion=$(echo ${latestVersion} | awk -F '-' '{ print $1 }')
docker image pull ${imageName}:${latestVersion}
docker image tag ${imageName}:${latestVersion} dokku/${image}:${dokkuVersion}
dokku tags:deploy ${image} ${dokkuVersion}
updated=true
echo "====> Finished $image"
}
for image in "${!privateImages[@]}"; do
echo "====> Updating $image"
IN=${privateImages[$image]}
IFS=";" read -a parameters <<<"$IN"
tokenUrl="${parameters[0]}"
tagsUrl="${parameters[1]}"
username="${parameters[2]}"
password="${parameters[3]}"
regex="${parameters[4]}"
credentials=$(echo -n "${username}:${password}" | base64)
token=$(curl -L -s -H "Authorization: Basic ${credentials}" ${tokenUrl} | jq -r '."token"')
currentImageId=$(dokku tags ${image} | grep dokku | grep latest | awk '{ print $3 }')
currentVersion=$(docker image ls | grep -v latest | grep -v dokku | grep ${currentImageId} | awk '{ print $2 }')
latestVersion=$(curl -L -s -H "Authorization: Bearer ${token}" ${tagsUrl} | jq -r '."tags"[]' | grep $regex | sort --version-sort | tail -n 1)
resolve "$image" "$currentVersion" "$latestVersion"
done
for image in "${!images[@]}"; do
echo "====> Updating $image"
IN=${images[$image]}
IFS=";" read -a parameters <<<"$IN"
registryUrl="${parameters[0]}tags?page_size=1024"
regex="${parameters[1]}"
currentImageId=$(dokku tags ${image} | grep dokku | grep latest | awk '{ print $3 }')
currentVersion=$(docker image ls | grep -v latest | grep -v dokku | grep ${currentImageId} | awk '{ print $2 }')
latestVersion=$(curl -L -s ${registryUrl} | jq -r '."results"[]["name"]' | sort --version-sort | grep $regex | tail -n 1)
resolve "$image" "$currentVersion" "$latestVersion"
done
if [ "$updated" = true ]; then
read -p "One or more apps were updated. Run \`docker system prune\`? " -n 1 -r
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo -e "\nWaiting for old containers to stop…"
sleep 60
docker system prune
fi
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment