docker compose service startup sequence control method
- 2020-12-10 00:55:55
- OfStack
The profile
docker-compose makes it easy to combine multiple docker container services, but docker-ES7en does not guarantee the starting order of the services when there are dependencies between the container services.
The depends_on configuration in ES10en-ES11en is the order in which the container is started, not the order in which the services in the container are started.
Problem reproduction
First, let's construct an example to illustrate the problems caused by ES18en-ES19en. The docker-ES21en. yml file is as follows:
version: '2'
services:
web:
image: ubuntu:14.04
depends_on:
- web
command: nc -z database 3306
database:
image: ubuntu:14.04
command: >
/bin/bash -c '
sleep 5;
echo "sleep over";
nc -lk 0.0.0.0 3306;
'
After startup, you can see that database was indeed started first and web later, but the service in database took about 5 seconds to complete, causing the startup of web to fail.
$ docker-compose up
Creating tmp_database_1 ... done
Creating tmp_database_1 ...
Creating tmp_web_1 ... done
Attaching to tmp_database_1, tmp_web_1
tmp_web_1 exited with code 1
database_1 | sleep over
Problem resolution 1.0
Modify the startup script for web and wait for database's port to pass before starting the service
version: '2'
services:
web:
image: ubuntu:14.04
depends_on:
- database
command: >
/bin/bash -c '
while ! nc -z database 3306;
do
echo "wait for database";
sleep 1;
done;
echo "database is ready!";
echo "start web service here";
'
database:
image: ubuntu:14.04
command: >
/bin/bash -c '
sleep 5;
echo "sleep over";
nc -lk 0.0.0.0 3306;
'
Start it up again,
$ docker-compose up
Creating tmp_database_1 ... done
Creating tmp_database_1 ...
Creating tmp_web_1 ... done
Attaching to tmp_database_1, tmp_web_1
web_1 | wait for database
web_1 | wait for database
web_1 | wait for database
web_1 | wait for database
web_1 | wait for database
database_1 | sleep over
web_1 | database is ready!
web_1 | start web service here
tmp_web_1 exited with code 0
web will not start until database is started and the port is connected.
Problem solving 2.0
The above solution solves the problem, but inserting scripts directly into yaml is not maintainable and error-prone. If you have multiple dependencies, or layers of dependencies, the complexity goes up linearly.
So, you want to encapsulate an ES56en.sh script that accepts the start command and the service and port to wait for. The script reads as follows:
#!/bin/bash
#set -x
#******************************************************************************
# @file : entrypoint.sh
# @author : wangyubin
# @date : 2018-08- 1 10:18:43
#
# @brief : entry point for manage service start order
# history : init
#******************************************************************************
: ${SLEEP_SECOND:=2}
wait_for() {
echo Waiting for $1 to listen on $2...
while ! nc -z $1 $2; do echo waiting...; sleep $SLEEP_SECOND; done
}
declare DEPENDS
declare CMD
while getopts "d:c:" arg
do
case $arg in
d)
DEPENDS=$OPTARG
;;
c)
CMD=$OPTARG
;;
?)
echo "unkonw argument"
exit 1
;;
esac
done
for var in ${DEPENDS//,/ }
do
host=${var%:*}
port=${var#*:}
wait_for $host $port
done
eval $CMD
This script takes two arguments, -ES62en needs to wait for the service and port, -ES63en waits for the service and port to start after its own startup command
Modify ES66en-ES67en.yml to use the ES69en.ES70en script to control the boot sequence.
version: '2'
services:
web:
image: ubuntu:14.04
depends_on:
- database
volumes:
- "./entrypoint.sh:/entrypoint.sh"
entrypoint: /entrypoint.sh -d database:3306 -c 'echo "start web service here"';
database:
image: ubuntu:14.04
command: >
/bin/bash -c '
sleep 5;
echo "sleep over";
nc -lk 0.0.0.0 3306;
'
In practice, it is also possible to package entrypoint.sh into a published image instead of loading the entrypoint.sh script through the volumes configuration.
The test results are as follows:
$ docker-compose up
Starting tmp_database_1 ... done
Starting tmp_web_1 ... done
Attaching to tmp_database_1, tmp_web_1
web_1 | Waiting for database to listen on 3306...
web_1 | waiting...
web_1 | waiting...
web_1 | waiting...
database_1 | sleep over
web_1 | start web service here
tmp_web_1 exited with code 0
supplement
Depend on multiple services and ports
Using the entrypoint. sh script above, you can also rely on multiple services and ports, separated by commas (,) after the -d parameter.
version: '2'
services:
web:
image: ubuntu:14.04
depends_on:
- mysql
- postgresql
volumes:
- "./entrypoint.sh:/entrypoint.sh"
entrypoint: /entrypoint.sh -d mysql:3306,postgresql:5432 -c 'echo "start web service here"';
mysql:
image: ubuntu:14.04
command: >
/bin/bash -c '
sleep 4;
echo "sleep over";
nc -lk 0.0.0.0 3306;
'
postgresql:
image: ubuntu:14.04
command: >
/bin/bash -c '
sleep 8;
echo "sleep over";
nc -lk 0.0.0.0 5432;
'
The effect of the execution can be tried by yourself.
Try the interval configuration
The wait time per connection attempt can be configured using the environment variable SLEEP_SECOND. By default, the configuration wait time under 2 seconds is set to 4 seconds, so the connection can be made every 4 seconds when the mysql service is tried.
version: '2'
services:
web:
image: ubuntu:14.04
environment:
SLEEP_SECOND: 4
depends_on:
- mysql
volumes:
- "./entrypoint.sh:/entrypoint.sh"
entrypoint: /entrypoint.sh -d mysql:3306 'echo "start web service here"';
mysql:
image: ubuntu:14.04
command: >
/bin/bash -c '
sleep 4;
echo "sleep over";
nc -lk 0.0.0.0 3306;
'