├── .dockerignore ├── Dockerfile ├── README.md └── wait /.dockerignore: -------------------------------------------------------------------------------- 1 | .git 2 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine:3.7 2 | MAINTAINER Martin van Beurden 3 | 4 | RUN apk add --no-cache netcat-openbsd 5 | 6 | ADD wait /wait 7 | 8 | ENTRYPOINT ["/wait"] 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | `wait` is a really small (<5MB) Docker utility that blocks until another container is accepting TCP connections, and errors-out if it cannot connect within a given timeout. It can be used to ensure that a service is up and running before starting another service that depends on it. 2 | 3 | The default operation looks up all the `EXPOSE`d ports of all the linked containers and waits for them 4 | 5 | ```shell 6 | $ docker run -d --name mycontainer some-image-or-other 7 | $ docker run --link mycontainer:mycontainer --rm martin/wait 8 | Waiting for 172.17.0.105:5432 . up! 9 | Everything is up 10 | ``` 11 | 12 | It doesn't matter what the link alias is. 13 | 14 | If you want to wait for only a subset of the ports in a linked container, you can provide the list with the `-p` parameter: 15 | 16 | ```shell 17 | $ docker run -d --name mycontainer some-image-or-other 18 | $ docker run --link mycontainer:mycontainer --rm martin/wait -p 5432 19 | Not checking 172.17.0.105:6379 because port is not included. 20 | Waiting for 172.17.0.105:5432 . up! 21 | Everything is up 22 | ``` 23 | 24 | 25 | If you want to connect to hosts/ports that haven't been linked by Docker, you can provide the list with the `-c` parameter: 26 | 27 | ```shell 28 | $ docker run --rm martin/wait -c 8.8.8.8:53,github.com:443 29 | Waiting for 8.8.8.8:53 . up! 30 | Waiting for github.com:443 . up! 31 | Everything is up 32 | ``` 33 | 34 | By default each connection attempt will bail after 30 seconds. You can override this with `-t` parameter: 35 | 36 | ```shell 37 | $ docker run martin/wait -c github.com:5432 -t 15 38 | Waiting for github.com:5432 ............................... ERROR: unable to connect 39 | ``` 40 | 41 | If any connection times out, the `wait` container immediately exits with status code 1 42 | 43 | **credits** 44 | 45 | waisbrot/wait: https://github.com/waisbrot/docker-wait 46 | n3llyb0y/wait: https://github.com/n3llyb0y/docker-wait 47 | aanand/wait: https://github.com/aanand/docker-wait 48 | -------------------------------------------------------------------------------- /wait: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | 4 | usage() { 5 | echo "" 6 | echo "usage: $0 [-p] [-c] [-t]" 7 | echo "" 8 | echo "optional arguments:" 9 | echo " -p only test exposed ports from the linked container that are in this list" 10 | echo " -c custom connection(s) to test, host:port, multiple seperated by comma" 11 | echo " -t timeout after which connection attempt will fail, default 30" 12 | echo "" 13 | echo " Example: $0 -c google.com:443,github.com:443 -t 15" 14 | echo " $0 -p 8080" 15 | } 16 | 17 | set -e 18 | 19 | timeout=${TIMEOUT:-30} 20 | 21 | # Parse arguments 22 | while getopts ":t:c:p:" opt; do 23 | case $opt in 24 | t) 25 | timeout=$OPTARG 26 | case $timeout in 27 | ''|*[!0-9]*) 28 | echo "Invalid timeout number: $timeout" >&2 29 | exit 1 30 | ;; 31 | esac 32 | ;; 33 | c) 34 | TARGETS="$OPTARG" 35 | ;; 36 | p) 37 | PORTS="$OPTARG" 38 | ;; 39 | \?) 40 | set +x 41 | echo "Invalid option: -$OPTARG" >&2 42 | usage 43 | exit 1 44 | ;; 45 | :) 46 | set +x 47 | echo "Option -$OPTARG requires an argument." >&2 48 | usage 49 | exit 1 50 | ;; 51 | esac 52 | done 53 | 54 | if [ -n "$PORTS" ]; then 55 | ports=$(echo "$PORTS"|tr , ' '|tr -s '[:space:]' '\n') 56 | fi 57 | 58 | # our target format is a newline-delimited list where each item is "host:ip" 59 | if [ -z "$TARGETS" ]; then 60 | # empty TARGETS variable will default to checking all host/ports exposed 61 | uris="" 62 | oldifs="$IFS" 63 | IFS=$'\n' 64 | for var in $(env); do 65 | case "$var" in 66 | *_TCP=*) 67 | uris="$uris $(echo "$var" | cut -d= -f2 | cut -c7-)" 68 | ;; 69 | esac 70 | done 71 | IFS="$oldifs" 72 | 73 | if [ -n "$PORTS" ]; then 74 | urisinc="" 75 | for uri in $uris 76 | do 77 | port=$(echo $uri | cut -d: -f2) 78 | [ -n "${port}" ] 79 | #check if port should be checked 80 | for portex in $ports 81 | do 82 | if [ $portex = $port ]; then 83 | if [ -z "$uriinc" ]; then 84 | urisinc="$urisinc $uri" 85 | else 86 | urisinc="$uri" 87 | fi 88 | continue 2 89 | fi 90 | done 91 | echo "Not checking $uri because port is not included." 92 | done 93 | uris=$urisinc 94 | fi 95 | 96 | if [ $(echo $uris | wc -w) -lt 1 ]; then 97 | echo "The linked container(s) export no ports and you didn't specify any manual targets." >&2 98 | usage 99 | exit 1 100 | fi 101 | else 102 | uris=$(echo "$TARGETS"|tr , ' '|tr -s '[:space:]' '\n'|uniq) 103 | fi 104 | 105 | # wait for each target 106 | if [ -z "$uris" ]; then 107 | echo "No wait targets found." >&2 108 | usage 109 | exit 1 110 | fi 111 | 112 | for uri in $uris 113 | do 114 | host=$(echo $uri | cut -d: -f1) 115 | port=$(echo $uri | cut -d: -f2) 116 | [ -n "${host}" ] 117 | [ -n "${port}" ] 118 | echo -n "Waiting for ${uri} ." 119 | timestamp="$(date +%s)" 120 | totalelapseds=0 121 | totalalloweds=$timeout 122 | while [ "$totalelapseds" -lt "$totalalloweds" ] && ! nc -z -w 1 $host $port 123 | do 124 | elapseds="$((($(date +%s)-$timestamp)))" 125 | if [ $elapseds -lt 1 ]; then 126 | sleep 1 127 | elapseds=$(($elapseds+1)) 128 | fi 129 | totalelapseds=$(($totalelapseds+$elapseds)) 130 | echo -n '.' 131 | timestamp="$(date +%s%N)" 132 | done 133 | 134 | if [ "$totalelapseds" -lt "$totalalloweds" ]; then 135 | echo " up!" 136 | else 137 | echo " ERROR: unable to connect" >&2 138 | exit 1 139 | fi 140 | done 141 | echo "Everything is up" 142 | exit 0 143 | --------------------------------------------------------------------------------