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

Vue folding display multi-line text component implementation code

Folding display multi-line text component Fold an...

Example code for realizing charging effect of B station with css+svg

difficulty Two mask creation of svg graphics Firs...

How to build and deploy Node project with Docker

Table of contents What is Docker Client-side Dock...

Analyze the difference between ES5 and ES6 apply

Table of contents Overview Function signature Opt...

Zabbix configuration DingTalk alarm function implementation code

need Configuring DingTalk alarms in Zabbix is ​​s...

Table Tag (table) In-depth

<br />Table is a tag that has been used by e...

Solution to the impact of empty paths on page performance

A few days ago, I saw a post shared by Yu Bo on G...

Linux automatic login example explanation

There are many scripts on the Internet that use e...

How to check if the firewall is turned off in Linux

1. Service method Check the firewall status: [roo...

Vue implements the magnifying glass effect of tab switching

This article example shares the specific code of ...

A brief understanding of the relevant locks in MySQL

This article is mainly to take you to quickly und...

What are the new features of Apache Spark 2.4, which will be released in 2018?

This article is from the Apache Spark Meetup held...

5 solutions to CSS box collapse

First, what is box collapse? Elements that should...