Helpful shell snippets for Docker, Testing and Bootstrapping
Today, I won’t provide a real article but some helpful shell snippets to working with bootstrap scripts, docker images or other minimal setups.
Please notice I didn’t put a lot of work into the description but it should be understandable. It’s written for my personal usage. Maybe I’ll update this article later, to explain every snippet in detail.
I try to prevent myself from reinventing the wheel each time, so I started this collection.
Various tools
Check if a command exists
This function takes one parameter, which is the name of the command.
command_exists() { command -v $1 >/dev/null 2>&1 || { echo >&2 "I require $1 but it's not installed. Aborting."; exit 1; }; }
Example:
command_exists wget
Get a random port from range
This function generates a random number from a given range. The range is defined by two parameters.
get_random_port() { cat /dev/urandom|od -N2 -An -i|awk -v f=$1 -v r=$2 '{printf "%i\n", f + r * $1 / 65536}'; }
Example:
get_random_port 10000 19999
Check for port
Checks that the port specified by $CLIENT_PORT
is available/empty (nothing is listening on it).
In case it’s bound, it will restart the script. (Used with get_random_port()
)
[ $(netstat -an | grep LISTEN | grep :$CLIENT_PORT | wc -l) -eq 0 ] || { ./$0 && exit 0 || exit 1; }
GitHub
Get latest release tag
This function takes one parameter, which is the name of the repository it should look up. The returned string is the latest published version of the given repository.
github_latest_release() { wget -qO- https://api.github.com/repos/$1/releases/latest | jq .tag_name | sed -e 's/"//g'; }
Example:
github_latest_release docker/docker
Docker
Docker basics
Some simple snippets for docker environments
Check for Docker
This function takes no parameters
It checks docker for being installed and attempts to install if it is missing, failing if the installation attempt fails.
In case the installation doesn’t success it fails.
docker_installed() { command -v docker >/dev/null 2>&1 || { wget -O- https://get.docker.com | sh - ; }; command -v docker >/dev/null 2>&1 || { echo >&2 "I require docker but it's not installed and I can't install it myself. Aborting."; exit 1; }; }
Example:
docker_installed
Create docker swarm
This snippet simply inits a docker swarm at the current host using the first routable IPv4.
(Workaround to prevent --advertise-addr
errors in scripts)
docker swarm init --advertise-addr `ip addr s | grep global | grep -oE '((1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])\.){3}(1?[0-9][0-9]?|2[0-4][0-9]|25[0-5])' | head -n1`
Docker Hub
Docker image versions
This function takes one parameter, which is the name of the Docker image on Docker Hub.
It returns the tags for the given image.
Notice: It only matches versions like 1
, 1.2.3
or 1.0
but not tags like latest
docker_image_tags() { REPO=$1; [ $(echo $REPO | grep '/' | wc -l) -eq 0 ] && REPO=library/$1; wget -q -O- https://registry.hub.docker.com/v2/repositories/${REPO}/tags | jq .results[].name | { [ "$(uname)" = "Linux" ] && sort -V || sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n; } | sed -e 's/"//g' | grep -P '[[:digit:]]+((.[[:digit:]]+)?.[[:digit:]]+)'; }
Example:
docker_image_tags alpine
# OR
docker_image_tags sheogorath/minecraft
Docker latest version tag
This function is an extended version of the previous one.
It simple returns only the “latest” version of an image.
Notice: It only matches versions like 1
, 1.2.3
or 1.0
but not tags like latest
docker_image_latest_tag() { REPO=$1; [ $(echo $REPO | grep '/' | wc -l) -eq 0 ] && REPO=library/$1; wget -q -O- https://registry.hub.docker.com/v2/repositories/${REPO}/tags | jq .results[].name | { [ "$(uname)" = "Linux" ] && sort -V || sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n; } | sed -e 's/"//g' | grep -P '[[:digit:]]+((.[[:digit:]]+)?.[[:digit:]]+)' | tail -1; }
Example:
docker_image_latest_tag alpine
# OR
docker_image_latest_tag sheogorath/minecraft
Docker local
Base image version
This function takes one parameter, the path to the Dockerfile
.
It returns the tag of the base image in the Dockerfile.
docker_base_version() { cat $1 | grep FROM | sed -e "s/FROM.*://g"; }
Example:
docker_base_version Dockerfile
Base image name
This function takes one parameter. This parameter is the path to the Dockerfile
.
It returns the name of the base image in the Dockerfile.
docker_base_name() { cat $1 | grep FROM | sed -e "s/FROM[^[:alpha:]]//g" -e "s/:.*//g"; }
Example:
docker_base_version Dockerfile
Version comparison
Often you want to compare versions. For example the results of the previous commands.
Here is a small set of useful comparisons.
greater or equal
version_ge() { test "$(printf '%s\n' "$@" | { [ "$(uname)" = "Linux" ] && sort -V || sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n; } | head -n 1)" != "$1" || test "$1" = "$2"; }
greater
version_gt() { test "$(printf '%s\n' "$@" | { [ "$(uname)" = "Linux" ] && sort -V || sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n; } | head -n 1)" != "$1"; }
equal
version_eq() { test "$1" = "$2"; }
not equal
version_ne() { test "$1" != "$2"; }
lower
version_lt() { test "$(printf '%s\n' "$@" | { [ "$(uname)" = "Linux" ] && sort -V || sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n; } | tail -n 1)" != "$1"; }
lower equal
version_le() { test "$(printf '%s\n' "$@" | { [ "$(uname)" = "Linux" ] && sort -V || sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n; } | tail -n 1)" != "$1" || test "$1" = "$2"; }
The parameters are the same as used in regular comparisons.
Example:
version_gt "1.0" "1.1" && echo is greater || echo is not greater
Works like:
[ 5 -gt 6 ] && echo is greater || echo is not greater
version.sh
You may say “All this is nice but what can actually I do with it?”
Let me show you my newest project:
#!/bin/sh
DOCKERFILE=${1:-Dockerfile}
# Check for command existence
command_exits() { command -v $1 >/dev/null 2>&1 || { echo >&2 "I require $1 but it's not installed. Aborting."; exit 1; }; }
# Docker latest version tag
docker_image_latest_tag() { REPO=$1; [ $(echo $REPO | grep '/' | wc -l) -eq 0 ] && REPO=library/$1; wget -q -O- https://registry.hub.docker.com/v2/repositories/${REPO}/tags | jq .results[].name | { [ "$(uname)" = "Linux" ] && sort -V || sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n; } | sed -e 's/"//g' | grep -P '[[:digit:]]+((.[[:digit:]]+)?.[[:digit:]]+)' | tail -1; }
# Version comparison greater or equal
version_ge() { test "$(printf '%s\n' "$@" | { [ "$(uname)" = "Linux" ] && sort -V || sort -t. -k 1,1n -k 2,2n -k 3,3n -k 4,4n; } | head -n 1)" != "$1" || test "$1" = "$2"; }
# Docker base image version
docker_base_version() { cat "$1" | grep FROM | sed -e "s/FROM.*://g"; }
# Docker base image name
docker_base_name() { cat "$1" | grep FROM | sed -e "s/FROM[^[:alpha:]]//g" -e "s/:.*//g"; }
command_exits wget
[ -e "$DOCKERFILE" ] || { echo >&2 "File '$DOCKERFILE' doesn't exist. Aborting."; exit 1; }
version_ge $(docker_base_version "$DOCKERFILE") $(docker_image_latest_tag `docker_base_name "$DOCKERFILE"`) || { echo >&2 "A newer base image is available! Please update."; exit 1; }
The version.sh
is a little shell script that checks if your Dockerfile uses the latest version of your base image. Since TravisCI supports cron builds, you can use version.sh
in your CI and automatically get notified about outdated versions.
About the usage: version.sh
with no parameter expects a Dockerfile
in the current working directory. In case you have a custom path you can pass it as a parameter.
If you want to see my most recent snippets, I use my personal HackMD instance to write them down. Don’t expect very useful descriptions. It’s mostly for myself. https://pad.shivering-isles.com/KwIwTAxgnAJgjADgLTAGaokgLIzBDBABgDYliBTQgdlUK2LkSyA=
I hope you found these snippets helpful. Please support me so I can continue writing articles, scripts, and Dockerfiles.
If you have suggestions feel free to comment or poke me on Mastodon.
Special thanks to the Docker Community for supporting me writing this article!