docker-compose編成のサービス起動順序の問題

4612 ワード

前回では、docker-composerによって基本的に編成されたケースを示しましたが、そのケースには隠れた問題があります.
myappサービスでは、redisサービスに依存することを示したが、docker−composeは、コンテナの起動順序がredisを起動してからnodejsを起動することを保証することができるが、コンテナの起動順序はサービスの起動順序ではない.
仮想すると、バックエンドサービスがredisではなく、起動に時間がかかるバックエンドアプリケーションであれば、composeがバックエンドコンテナを起動した後、すぐにnodejsコンテナを起動します.おそらくnodejsコンテナの起動は完了したが、バックエンドのコンテナはまだ準備完了状態に達していない.この場合、ポートが接続できるかどうかなどのバックエンドコンテナの準備状態を判断するメカニズムが必要です.バックエンドコンテナが使用可能になった後、フロントエンドコンテナを再起動します.
 
最適化案1:wait-for-itを使用する.shスクリプト、遅延起動コンテナ
vi wait-for-it.sh、内容は以下の通りです.
#!/bin/sh
 
TIMEOUT=15
QUIET=0
 
echoerr() {
  if [ "$QUIET" -ne 1 ]; then printf "%s
" "$*" 1>&2; fi } usage() { exitcode="$1" cat << USAGE >&2 Usage: $cmdname host:port [-t timeout] [-- command args] -q | --quiet Do not 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 "$exitcode" } wait_for() { for i in `seq $TIMEOUT` ; do nc -z "$HOST" "$PORT" > /dev/null 2>&1 result=$? if [ $result -eq 0 ] ; then if [ $# -gt 0 ] ; then exec "$@" fi exit 0 fi sleep 1 done echo "Operation timed out" >&2 exit 1 } while [ $# -gt 0 ] do case "$1" in *:* ) HOST=$(printf "%s
" "$1"| cut -d : -f 1) PORT=$(printf "%s
" "$1"| cut -d : -f 2) shift 1 ;; -q | --quiet) QUIET=1 shift 1 ;; -t) TIMEOUT="$2" if [ "$TIMEOUT" = "" ]; then break; fi shift 2 ;; --timeout=*) TIMEOUT="${1#*=}" shift 1 ;; --) shift break ;; --help) usage 0 ;; *) echoerr "Unknown argument: $1" usage 1 ;; esac done if [ "$HOST" = "" -o "$PORT" = "" ]; then echoerr "Error: you need to provide a host and port to test." usage 2 fi wait_for "$@"

docker-composeを変更します.ymlファイル、
version: '3'
services:
  myapp:
    build:
     context: .
     dockerfile: myapp.dockerfile
    ports:
      - "3000:3000"
    volumes:
      - "./wait-for-it.sh:/wait-for-it.sh"
    #links:
    #  - redis 
    depends_on:
      - redis
    entrypoint: sh /wait-for-it.sh redis:6379 -t 5  --
    command: node /myapp/app.js
  redis:
    image: "redis:4-alpine"

wait-for-it.shスクリプトの使用、依存する[ホスト]:[ポート]が使用可能かどうかを検出し、-tは検出のタイムアウト時間を指定し、デフォルトは15秒です.「--」の後に続くのは、検出が通過した後に実行されるコマンドです.上記の例では、commandはentrypointコマンドにパラメータとして渡されます. 
 
二、最適化方案二:entrypointを使用する.shスクリプト、遅延起動コンテナ
vi entrypoint.sh、内容は以下の通りです.
#!/bin/bash
#set -x
#******************************************************************************
# @file    : entrypoint.sh
# @author  : simon
# @date    : 2018-08-28 15: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
 
DEPENDS=''
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

docker-composeを変更します.ymlファイル、
version: '3'
services:
  myapp:
    build:
     context: .
     dockerfile: myapp.dockerfile
    ports:
      - "3000:3000"
    volumes:
      - "./entrypoint.sh:/entrypoint.sh"
    #links:
    #  - redis 
    depends_on:
      - redis
    #entrypoint:  
    command: sh /entrypoint.sh  -d 'redis:6379' -c 'node /myapp/app.js'
  redis:
    image: "redis:4-alpine"

注意:
sh/entrypoint.sh  -d 'redis:6379 192.168.11.1:80' -c 'node/myapp/app.js'の行はentrypoint命令にもcommand命令にも入れることができます. 
entrypoint.shスクリプトの使用:-d引用符には[ホスト]:[ポート]が付いており、検出するサービスを表すスペースで区切られた複数のサービスがあります.検出されたサービスが使用可能(ポート接続可能)である場合、-c引用符のコマンドが実行されます.このスクリプトを使用すると、複数の依存項目を同時に検出できます.