Last active
July 8, 2020 18:46
-
-
Save basebandit/20b0abd26127dc7f94cc10eb19711618 to your computer and use it in GitHub Desktop.
How to wait on another container using docker-compose
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
version: "3.7" | |
services: | |
fupisha: | |
build: | |
context: . | |
container_name: fupisha-backend | |
depends_on: | |
- postgres | |
- redis | |
command: | |
[ | |
"./wait-for-it.sh", | |
"postgres:5432", | |
"redis:6379", | |
"--strict", | |
"--timeout=300", | |
"--", | |
"./fupisha", | |
"-t", | |
"./templates/email", | |
] | |
ports: | |
- 8888:8888 | |
- 53:53/udp | |
- 80:80 | |
- 2345:2345 | |
- 443:443 | |
volumes: | |
- ./fupisha:/fupisha | |
tty: true | |
networks: | |
- backend | |
postgres: | |
image: postgres:12.2 | |
container_name: postgres | |
ports: | |
- 5432:5432 | |
environment: | |
POSTGRES_DB: "fupisha" | |
POSTGRES_USER: "fupisha" | |
POSTGRES_PASSWORD: "fupisha" | |
volumes: | |
- ./init.sql:/docker-entrypoint-initdb.d/init.sql | |
- pgdata:/var/lib/postgresql/data | |
networks: | |
- backend | |
redis: | |
image: redis:5.0.7 | |
container_name: cache | |
ports: | |
- 6379:6379 | |
command: redis-server --appendonly yes --requirepass Fup1sha | |
volumes: | |
- redisdata:/data | |
networks: | |
- backend | |
volumes: | |
pgdata: | |
redisdata: | |
fupisha: | |
networks: | |
backend: | |
driver: "bridge" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Start from the latest golang base image | |
FROM golang:1.14-alpine as builder | |
# Add Maintainer Info | |
LABEL maintainer="The Basebandit <@the_basebandit>" | |
# Set the Current Working Directory inside the container | |
WORKDIR /backend | |
# Copy everything from the current directory to the Working Directory inside the container | |
COPY . . | |
# Build the Go app | |
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o mvuvi . | |
FROM aquasec/trivy:0.4.4 as trivy | |
# RUN executes commands on top of the current image as a new layer and commits the results | |
# Scan the golang alpine image before production use | |
RUN trivy --debug --timeout 4m golang:1.14-alpine && \ | |
echo "No image vulnerabilities" > result | |
######## Start a new stage from scratch ####### | |
FROM alpine:3.12 | |
ENV FUPISHA_USER fupisha | |
ENV FUPISHA_HOME /go/src/fupisha | |
ENV FUPISHA_JWT_SECRET Ic@nk33py0uR53cr3tf0rAsL0nga5Y0uW@nt! | |
ENV FUPISHA_JWT_EXPIRATION_DELTA 6 | |
ENV FUPISHA_JWT_REFRESH_EXPIRATION_DELTA 60 | |
ENV FUPISHA_REDIS_PWD Fupisha | |
ENV FUPISHA_PG_USER fupisha | |
ENV FUPISHA_PG_PWD fupisha | |
ENV FUPISHA_PG_DB fupisha | |
# postgres is the name of the postgres container in docker-compose file | |
ENV FUPISHA_PG_HOST postgres | |
ENV FUPISHA_PG_PORT 5432 | |
ENV FUPISHA_PG_SSL disable | |
ENV FUPISHA_EMAIL_SMTP_HOST smtp.gmail.com | |
ENV FUPISHA_EMAIL_SMTP_PORT 587 | |
ENV FUPISHA_EMAIL_SMTP_USER yourgmailemail | |
ENV FUPISHA_EMAIL_SMTP_PASSWORD yourappsecret | |
ENV FUPISHA_EMAIL_FROM_ADDRESS support@fupisha.io | |
ENV FUPISHA_EMAIL_FROM_NAME Fupisha | |
ENV FUPISHA_LOGIN_URL https://fupisha.io/auth/login | |
ENV FUPISHA_TEXT_LOGGING true | |
ENV FUPISHA_LOG_LEVEL info | |
RUN apk update && apk --no-cache add ca-certificates | |
RUN apk --no-cache add bash | |
WORKDIR /root/ | |
COPY templates/ /root/templates/ | |
# Copy the Pre-built binary file from the previous stage | |
COPY --from=builder /backend/fupisha. | |
#Copy the wait script file from the previous stage | |
COPY --from=builder /backend/wait-for-it.sh . | |
# Give permission to run script | |
RUN chmod +x ./wait-for-it.sh | |
# Expose ports to the outside world | |
# port 80 - http server | |
# port 443 - https server | |
# port 53/udp - name server | |
# port 8888 - api server | |
EXPOSE 8888 443 80 53/udp | |
# Command to run the executable | |
CMD ["./fupisha","-t","./templates/email"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# Use this script to test if a given TCP host/port are available | |
WAITFORIT_cmdname=${0##*/} | |
echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi } | |
usage() | |
{ | |
cat << USAGE >&2 | |
Usage: | |
$WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args] | |
-h HOST | --host=HOST Host or IP under test | |
-p PORT | --port=PORT TCP port under test | |
Alternatively, you specify the host and port as host:port | |
-s | --strict Only execute subcommand if the test succeeds | |
-q | --quiet Don't output any status messages | |
-t TIMEOUT | --timeout=TIMEOUT | |
Timeout in seconds, zero for no timeout | |
-- COMMAND ARGS Execute command with args after the test finishes | |
USAGE | |
exit 1 | |
} | |
wait_for() | |
{ | |
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then | |
echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" | |
else | |
echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout" | |
fi | |
WAITFORIT_start_ts=$(date +%s) | |
while : | |
do | |
if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then | |
nc -z $WAITFORIT_HOST $WAITFORIT_PORT | |
WAITFORIT_result=$? | |
else | |
(echo > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1 | |
WAITFORIT_result=$? | |
fi | |
if [[ $WAITFORIT_result -eq 0 ]]; then | |
WAITFORIT_end_ts=$(date +%s) | |
echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds" | |
break | |
fi | |
sleep 1 | |
done | |
return $WAITFORIT_result | |
} | |
wait_for_wrapper() | |
{ | |
# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 | |
if [[ $WAITFORIT_QUIET -eq 1 ]]; then | |
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & | |
else | |
timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & | |
fi | |
WAITFORIT_PID=$! | |
trap "kill -INT -$WAITFORIT_PID" INT | |
wait $WAITFORIT_PID | |
WAITFORIT_RESULT=$? | |
if [[ $WAITFORIT_RESULT -ne 0 ]]; then | |
echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" | |
fi | |
return $WAITFORIT_RESULT | |
} | |
# process arguments | |
while [[ $# -gt 0 ]] | |
do | |
case "$1" in | |
*:* ) | |
WAITFORIT_hostport=(${1//:/ }) | |
WAITFORIT_HOST=${WAITFORIT_hostport[0]} | |
WAITFORIT_PORT=${WAITFORIT_hostport[1]} | |
shift 1 | |
;; | |
--child) | |
WAITFORIT_CHILD=1 | |
shift 1 | |
;; | |
-q | --quiet) | |
WAITFORIT_QUIET=1 | |
shift 1 | |
;; | |
-s | --strict) | |
WAITFORIT_STRICT=1 | |
shift 1 | |
;; | |
-h) | |
WAITFORIT_HOST="$2" | |
if [[ $WAITFORIT_HOST == "" ]]; then break; fi | |
shift 2 | |
;; | |
--host=*) | |
WAITFORIT_HOST="${1#*=}" | |
shift 1 | |
;; | |
-p) | |
WAITFORIT_PORT="$2" | |
if [[ $WAITFORIT_PORT == "" ]]; then break; fi | |
shift 2 | |
;; | |
--port=*) | |
WAITFORIT_PORT="${1#*=}" | |
shift 1 | |
;; | |
-t) | |
WAITFORIT_TIMEOUT="$2" | |
if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi | |
shift 2 | |
;; | |
--timeout=*) | |
WAITFORIT_TIMEOUT="${1#*=}" | |
shift 1 | |
;; | |
--) | |
shift | |
WAITFORIT_CLI=("$@") | |
break | |
;; | |
--help) | |
usage | |
;; | |
*) | |
echoerr "Unknown argument: $1" | |
usage | |
;; | |
esac | |
done | |
if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then | |
echoerr "Error: you need to provide a host and port to test." | |
usage | |
fi | |
WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15} | |
WAITFORIT_STRICT=${WAITFORIT_STRICT:-0} | |
WAITFORIT_CHILD=${WAITFORIT_CHILD:-0} | |
WAITFORIT_QUIET=${WAITFORIT_QUIET:-0} | |
# Check to see if timeout is from busybox? | |
WAITFORIT_TIMEOUT_PATH=$(type -p timeout) | |
WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH) | |
WAITFORIT_BUSYTIMEFLAG="" | |
if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then | |
WAITFORIT_ISBUSY=1 | |
# Check if busybox timeout uses -t flag | |
# (recent Alpine versions don't support -t anymore) | |
if timeout &>/dev/stdout | grep -q -e '-t '; then | |
WAITFORIT_BUSYTIMEFLAG="-t" | |
fi | |
else | |
WAITFORIT_ISBUSY=0 | |
fi | |
if [[ $WAITFORIT_CHILD -gt 0 ]]; then | |
wait_for | |
WAITFORIT_RESULT=$? | |
exit $WAITFORIT_RESULT | |
else | |
if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then | |
wait_for_wrapper | |
WAITFORIT_RESULT=$? | |
else | |
wait_for | |
WAITFORIT_RESULT=$? | |
fi | |
fi | |
if [[ $WAITFORIT_CLI != "" ]]; then | |
if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then | |
echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess" | |
exit $WAITFORIT_RESULT | |
fi | |
exec "${WAITFORIT_CLI[@]}" | |
else | |
exit $WAITFORIT_RESULT | |
fi |
There are some good libraries out there for retry policies. I also wrote a post a while back on doing this without a library: https://upgear.io/blog/simple-golang-retry-function/
If you were deploying to something like kubernetes I would not even worry about adding a retry policy into my code. I would let kubernetes restart my containers for me. Thinking about production, this would give me quick feedback that my app is failing. It has been a while since I messed with docker-compose, but it looks like you might be able to specify a restart policy for your app: https://docs.docker.com/compose/compose-file/#restart_policy
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I tend to think it would be simpler to use a retry policy in your app (estimating ~5-10 lines) rather than using the
wait-for-it.sh
script (182 lines).