My Profile Photo

Sheogorath's Blog

Helpful shell snippets for Docker, Testing and Bootstrapping

on

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!