How to control the startup order of docker compose services

How to control the startup order of docker compose services

summary

Docker-compose can easily combine multiple Docker container services. However, when there are dependencies between container services, Docker-compose cannot guarantee the startup order of the services.

The depends_on configuration in docker-compose is the startup order of the containers, not the startup order of the services in the containers.

Problem Reproduction

First, let's construct an example to demonstrate the problems caused by docker-compose. The docker-compose.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 starting, it can be found that the database is started first and then the web, but the service in the database is completed after about 5 seconds, so the web startup fails.

$ 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 Solving Method 1.0

Modify the web startup script and wait for the database port to be connected 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;
   '

Restart,

$ 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

The web will start after the database is started and the port is connected.

Problem Solving 2.0

Although the above solution can solve the problem, inserting scripts directly into yaml is difficult to maintain and prone to errors. If there are multiple dependencies or multiple layers of dependencies, the complexity will increase sharply.

Therefore, we need to encapsulate an entrypoint.sh script that can accept the startup command, as well as the service and port to wait for. The script content is 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 has 2 parameters, -d is the service and port to wait for, -c is the startup command after the service and port are started.

Modify docker-compose.yml and use the entrypoint.sh script to control the startup order.

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 actual use, you can also package entrypoint.sh into the published image, without having to load the entrypoint.sh script through 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

Replenish

Depends on multiple services and ports

Using the entrypoint.sh script above, you can also depend on multiple services and ports by separating the multiple services and ports after the -d parameter with a comma (,).

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;
   '

You can try the execution effect yourself.

Configuration of the try interval

The waiting time for each connection attempt can be configured through the environment variable SLEEP_SECOND. The default is 2 seconds. If the configuration below sets the waiting time to 4 seconds, it will try to connect to the MySQL service every 4 seconds.

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;
   '

The above is the full content of this article. I hope it will be helpful for everyone’s study. I also hope that everyone will support 123WORDPRESS.COM.

You may also be interested in:
  • Detailed explanation of Docker Compose service orchestration

<<:  Vue implements card flip carousel display

>>:  MySQL 5.7 zip version (zip version) installation and configuration steps detailed

Recommend

Solve the problem of installing Theano on Ubuntu 19

Solution: Directly in the directory where you dow...

Linux echo text processing command usage and examples

The description of echo in the Linux help documen...

MYSQL transaction tutorial Yii2.0 merchant withdrawal function

Preface I am a PHP programmer who started out as ...

Simple analysis of EffectList in React

Table of contents EffectList Collection EffectLis...

Detailed explanation of the steps of using ElementUI in actual projects

Table of contents 1. Table self-sorting 2. Paging...

Solution for using Baidu share on Https page

Since enabling https access for the entire site, ...

Detailed explanation of group by and having in MySQL

The GROUP BY syntax can group and count the query...

Detailed examples of Linux disk device and LVM management commands

Preface In the Linux operating system, device fil...

MySQL Series 12 Backup and Recovery

Table of contents Tutorial Series 1. Backup strat...

How to modify the default network segment of Docker0 bridge in Docker

1. Background When the Docker service is started,...

Detailed explanation of Vite's new experience

What is Vite? (It’s a new toy on the front end) V...

Example of how to check the capacity of MySQL database table

This article introduces the command statements fo...

Solve the error of installing VMware Tools on Ubuntu 18.04

1. According to the online tutorial, the installa...

Vue component communication method case summary

Table of contents 1. Parent component passes valu...