Reputation: 183
We have a bash script that installs a program, which includes running a docker-compose
file. One of the services, RabbitMQ, takes some time to load and I need a command to wait until it's loaded before the other services are loaded. We were using a sleep
command, but our customers use different laptops, so it takes longer to load on some than others. Is there a way to just hold it until it finishes loading the service before moving on to the next without using the sleep
command? I have included the part of the script below. Thanks!
# Execute applications
cd /opt/program
docker-compose up -d
echo "waiting for message queue..."
sleep 15
echo "starting ingest manager"
cd /opt/program/scripts
chmod +x start-manager.sh
./start-manager.sh &
Upvotes: 8
Views: 15321
Reputation: 9018
As already stated in the other answers you'll have to do an application-specific readiness-check for your container. Personally I prefer to provide these checks/scripts with the container image, e.g. by adding the wait-for-it.sh
(see ErikMD's answer) or similar scripts to the image and executing them within the running container e.g. with docker exec
(as proposed by Ahmed Arafa's answer).
This has some advantages over running the check on the host:
wget
/curl
available on the host, or even a bash
/shell? Is the docker
/docker-compose
command executed on the same host as the docker deamon, i.e. could you reach the container via localhost
?)So, to apply this method to your example, simply add a script - e.g. is_ready.sh
- to the image, execute it within the container with docker-compose exec
and act upon its exit status:
# Execute applications
cd /opt/program
docker-compose up -d
echo "waiting for message queue..."
while ! docker-compose exec rabbitmq /is_ready.sh; do sleep 1; done
echo "starting ingest manager"
cd /opt/program/scripts
chmod +x start-manager.sh
./start-manager.sh &
where is_ready.sh
may look like this:
#!/bin/bash
rabbitmqctl status
Going even further down this road you may leverage the native healtcheck feature of docker and docker-compose. With these docker
will automatically execute the defined healthcheck script/command and indicate the current health in the container status.
Incorporated into your script this could look like:
# Execute applications
cd /opt/program
docker-compose up -d
echo "waiting for message queue..."
is_healthy() {
service="$1"
container_id="$(docker-compose ps -q "$service")"
health_status="$(docker inspect -f "{{.State.Health.Status}}" "$container_id")"
if [ "$health_status" = "healthy" ]; then
return 0
else
return 1
fi
}
while ! is_healthy rabbitmq; do sleep 1; done
echo "starting ingest manager"
cd /opt/program/scripts
chmod +x start-manager.sh
./start-manager.sh &
with the healthcheck defined in the docker-compose.yml
...
services:
rabbitmq:
...
healtcheck:
test: rabbitmqctl status
For more complex healthchecks you can also add a longer script to the image and execute that instead.
Upvotes: 8
Reputation: 500
First you need to determine specific name for rabbitmq container in your docker-compose.yaml by adding:
version: "3"
services:
web:
image: rabbitmq:latest
container_name: rabbitmq
to service block
And script will be like:
#!/bin/bash
cd /opt/program
docker-compose up -d
echo "waiting for message queue..."
rabbitmq_status() {
docker exec -it rabbitmq rabbitmqctl status
}
rabbitmq_status
if [ $? -eq 0 ]
then
echo "starting ingest manager"
cd /opt/program/scripts
chmod +x start-manager.sh
./start-manager.sh &
else
echo "rabbitmq container is not running"
fi
Which will not move to the next step till rabbitmq container is up and running.
Upvotes: 1
Reputation: 14753
The docker-compose up -d
command is run in the background in "detached mode", but I guess that your setup exposes at least one web service…
If yes, you can rely on a tool such as wait-for-it to precisely wait for this service to be ready.
First, download and inspect this script:
https://github.com/vishnubob/wait-for-it/raw/master/wait-for-it.sh
Next, assuming your docker-compose.yml
setup exposes a web service at localhost:9090
with:
version: 3
services:
frontend:
image: user/image
ports:
- '9090:8080'
You could refactor your Bash script (named e.g. run.sh
) as follows:
#!/bin/bash
# retrieve and remember the directory where is stored this script
srcdir=$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )
# we assume the script "wait-for-it.sh" is also in this directory
# Execute applications
cd /opt/program
docker-compose up -d
# Change the working directory now
cd /opt/program/scripts
chmod +x start-manager.sh
echo "waiting for message queue..."
"$srcdir/wait-for-it.sh" -h localhost -p 9090 -s -t 0 -- ./start-manager.sh
For more details, some online doc. is available at https://github.com/vishnubob/wait-for-it#readme
Upvotes: 1