Skip to content

Instantly share code, notes, and snippets.

@JasonHewison
Last active June 2, 2022 21:34
Show Gist options
  • Save JasonHewison/eafcd42c782e5bf29dbe18ac89042503 to your computer and use it in GitHub Desktop.
Save JasonHewison/eafcd42c782e5bf29dbe18ac89042503 to your computer and use it in GitHub Desktop.
wait-for-containers.sh
#!/usr/bin/env bash
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
COLOR_NC='\033[0m'
timeout=${1:-600}
start=$(date +%s)
while read container
do
status=$(docker inspect --format "{{ .State.Status }}" $container)
name=$(docker inspect --format "{{ .Name }}" $container)
service=$(docker inspect --format "{{index .Config.Labels \"com.docker.compose.service\" }}" $container 2>/dev/null)
if ! [[ "${status//[$' \t\n\r']/}" == "running" ]]; then
echo -e ""
echo -e "${RED}Error${COLOR_NC}: Expected ${PURPLE}${service:-$name}${COLOR_NC} to be <${BLUE}running${COLOR_NC}>, but it is <${RED}$status${COLOR_NC}>.${COLOR_NC}" 1>&2
echo -e ""
exit 1
fi
while true; do
health=$(docker inspect --format "{{ .State.Health.Status }}" $container 2>/dev/null)
if [[ "${health//[$' \t\n\r']/}" == "" ]] || [[ "${health//[$' \t\n\r']/}" == "healthy" ]]; then
break;
fi;
((C++))
case "$(($C % 4))" in
0) char=". "
;;
1) char=".. "
;;
2) char="..."
;;
3) char=" "
;;
esac
sleep .2
echo -ne "${COLOR_NC}${service:-$name}: ${YELLOW}$health${COLOR_NC} $char" "\r"
if [[ "${health//[$' \t\n\r']/}" == "unhealthy" ]]; then
echo -e "${COLOR_NC}${service:-$name}: ${RED}$health${COLOR_NC} "
echo -e ""
echo -e "${RED}Error${COLOR_NC}: ${PURPLE}${service:-$name}${COLOR_NC} is <${RED}$health${COLOR_NC}>.${COLOR_NC}" 1>&2
echo -e ""
exit 1
fi
if [[ $(( $(date +%s) - start )) -ge $timeout ]]; then
echo -e "${COLOR_NC}${service:-$name}: ${RED}$health${COLOR_NC} "
echo -e ""
echo -e "${RED}Error${COLOR_NC}: Timed out after ${YELLOW}$(( ($(date +%s) - start)/60 ))${COLOR_NC}m ${YELLOW}$((($(date +%s) - start)%60 ))${COLOR_NC}s${COLOR_NC}" 1>&2
echo -e ""
exit 1
fi
done
if [ "$health" == "" ]; then
echo -e "${COLOR_NC}${service:-$name}: ${GRAY}n/a${COLOR_NC} "
else
echo -e "${COLOR_NC}${service:-$name}: ${GREEN}healthy${COLOR_NC} "
fi
done

wait-for-containers.sh

Synopsis

  • The wait-for-containers.sh bash script allows you to wait until a list of containers are healthy.
  • The script will exit 0 if all of the supplied containers are healthy and exit 1 if any of the containers are not healthy/starting.
  • An optional timeout argument can be passed to the script, the default timeout is 10 minutes (600).

NOTE: The script is intended to be used with docker-compose so it will report the docker-compose service name if present over the container name, e.g. my-service instead of project_my-service_1.

Installation

To install wait-for-containers.sh run the following:

curl https://gist.githubusercontent.com/JasonHewison/eafcd42c782e5bf29dbe18ac89042503/raw/a84b4c1dde0f66dad9cb12f3e5c7c55be113de4a/wait-for-containers.sh --output wait-for-containers.sh
chmod +x wait-for-containers.sh

You should now be able to run any of the following examples

Usage Examples

Wait for all docker-compose containers

docker-compose ps -q | ./wait-for-containers.sh

Add a custom timeout (2 minutes)

docker-compose ps -q | ./wait-for-containers.sh 180

Wait for a specific container by id

echo 7d780bc23df9 | ./wait-for-containers.sh

Wait for all containers currently running

docker ps -q | ./wait-for-containers.sh

Wait for all containers on your machine

docker ps -aq | ./wait-for-containers.sh

Wait for any containers that are in some way related to bob

docker ps | grep bob | awk '{print $1}' | ./wait-for-containers.sh

Wait for any containers with the bob label

docker ps --filter "label=bob" -q | ./wait-for-containers.sh

Motivation

The wait-for-containers.sh script is currently being used to help run end to end tests against a docker-compose environment with a script like the one below.

docker-compose -f docker-compose.yml -f docker-compose.hub.yml up -d
docker-compose -f docker-compose.yml -f docker-compose.hub.yml ps -q | ./wait-for-containers.sh
docker-compose -f docker-compose.yml -f docker-compose.hub.yml -f docker-compose.runner.yml run --rm runner;
docker-compose -f docker-compose.yml -f docker-compose.hub.yml stop

In the above setup with startup all of our services and a selenium hub. They are all configured with healthchecks that report healthy when the services are ready to receive requests, the database is configured and the selenium hub is fully configured and all browser nodes are registered.

wait-for-containers.sh allows us to wait until the environment is ready before we start the test runner containined in docker-compose.runner.yml. The runner joins the existing docker-compose environment and network so can start running e2e tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment