找回密码
 注册
关于网站域名变更的通知
查看: 295|回复: 1
打印 上一主题 下一主题

docker compose 服务启动顺序控制

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-8-10 15:11 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
概要
& d! S1 V) T' y' C" g% e6 ddocker-compose 可以方便组合多个 docker 容器服务, 但是, 当容器服务之间存在依赖关系时, docker-compose 并不能保证服务的启动顺序.: p/ S" L* N* ^$ p  @& ^
: o; c! j& i3 g0 r. ~* `$ E
docker-compose 中的 depends_on 配置是容器的启动顺序, 并不是容器中服务的启动顺序.. @  i, f+ o, C3 A$ Y* j, a8 P
4 s. t9 ^- V, v6 T+ G4 n3 K
问题重现
0 R2 @# r; r. Z首先, 我们构造一个示例, 来演示 docker-compose 带来的问题. docker-compose.yml 文件如下:
/ v2 x" R5 y( M2 d
: H7 |( |( J0 c: Z. r2 F1 Aversion: '2'
1 I: D, w* ]8 G& C4 w6 Iservices:
6 o6 L2 }( |  D* U, E( x, l  web:- N% G7 C. W- t, p* s' M( \
    image: ubuntu:14.04
8 \& T6 i1 C& K9 Y7 t' l, W    depends_on:. C; k9 x0 M5 K
      - web! I: B! V- k. P8 @
    command: nc -z database 3306. U1 _7 r. M4 T

, N0 K0 i3 @; L& \7 E* Y8 A  database:
7 L8 @' N; N7 G' r  ]: y% }    image: ubuntu:14.04
1 X) j5 c& h( O' q2 A    command: >
4 B- u( v7 n8 T* V$ u      /bin/bash -c '# x! f! e5 [5 n5 o
      sleep 5;: ^& J" l# H5 U7 j$ m
      echo "sleep over";# o- X. k& k$ }% T- `1 U
      nc -lk 0.0.0.0 3306;* S+ _( V; c1 ~4 b0 L
      '
7 O- b: ~9 N+ z/ u, B启动后, 可以发现, 确实是先启动 database, 后启动 web, 但是 database 中的服务是在大约 5 秒后才完成的, 所以导致 web 的启动失败.- `+ X3 N6 L6 l" a4 P" S" G2 @7 G

2 @4 d9 \% g/ G0 x- ~% O$ docker-compose up3 k& w( I& r5 X& H3 `
Creating tmp_database_1 ... done' b" o! L" h$ U+ L/ I
Creating tmp_database_1 ...
1 A3 c% ?; Q3 c9 E  U7 d4 ICreating tmp_web_1      ... done+ @. |1 l6 q7 j9 @3 e- c9 M& ?
Attaching to tmp_database_1, tmp_web_15 V' ?. `  V, f; a8 w: }
tmp_web_1 exited with code 1) R$ }% H7 a. _9 Q& A, a
database_1  | sleep over
+ b! w5 `: ^% {问题解决方式 1.0
$ e6 H9 O- E4 A1 E+ Z9 d! c$ o修改 web 的启动脚本, 等待 database 的端口通了之后再启动服务4 Q- E" J2 B: s" w
7 Q9 B( \  s# G! Q; S
version: '2'
+ K/ ?' _( t1 O$ ?services:0 s  |) z, X+ }* m
  web:
6 L) e( C' x3 }! i; S# w0 c    image: ubuntu:14.049 j4 |$ J- E$ \; \
    depends_on:; F" j5 C7 O9 W% T9 C
      - database
8 U2 Q0 y$ {! r: ]. ]# O    command: >8 M) }4 Z4 ?' Y4 Z% s
      /bin/bash -c '2 d8 U6 {# z8 |" V
      while ! nc -z database 3306;
  ^" b8 {! K  X' c      do* Y- A3 z+ C4 n5 O. V4 Y
        echo "wait for database";9 C; z7 X& c, y  d
        sleep 1;8 h( k: d& Z0 x9 [& m
      done;: k0 D, b6 g$ B9 e

6 R# P, `$ Z; \: Y      echo "database is ready!";
6 o3 f5 E" v5 i) r/ y4 i      echo "start web service here";, T& E3 h, V* h7 O5 |/ o/ m( i
      '
9 r, Z4 a! F1 a( H
* f, q+ y, D, C: Q8 n  database:5 b5 l) L7 s3 G. J/ j: i, M' @, [
    image: ubuntu:14.04/ H2 \' o3 e/ ~
    command: >* t3 H1 `+ z) u+ K: ~
      /bin/bash -c '
+ W# ^* p4 P) v, v      sleep 5;4 i' V9 V* R6 b5 T& N4 m9 ^
      echo "sleep over";) r8 Q( C5 f: I
      nc -lk 0.0.0.0 3306;
4 ~' U8 O" s) v2 u( W4 W      '
3 }' ^* ^, |# N8 N: Q% I再次启动,
* R+ q* e7 @) k" ?0 @  ~/ [! Z, T
* w. r$ U+ c' Y6 x" N! P6 X$ docker-compose up7 `0 l: Q0 Q1 G. h: d
Creating tmp_database_1 ... done
) O- A6 a, ?: Y( P1 T/ k/ \7 z1 ?Creating tmp_database_1 ...: |8 p$ T( M! g, P8 m
Creating tmp_web_1      ... done& c. C$ a4 P6 Q" o- r5 y  i" D
Attaching to tmp_database_1, tmp_web_1
: _) Q6 P+ i! }web_1       | wait for database
$ M# ?6 \3 I( V$ gweb_1       | wait for database
# w2 u1 e* s# U4 S( f( Lweb_1       | wait for database% |; P: z1 D. {7 |- W
web_1       | wait for database
5 j0 k* W" D' r1 v: p* M) yweb_1       | wait for database$ }. z4 K4 u2 R0 D3 @& H4 P
database_1  | sleep over
. Z8 b) U+ v1 e. o9 T' jweb_1       | database is ready!
( c, f& r9 R" w) x" R3 e3 sweb_1       | start web service here$ E, m+ e# s, h6 y3 F
tmp_web_1 exited with code 0! M: L! V& a, `& T. L8 e
web 会在 database 启动完成, 端口通了之后才启动.0 w3 A) V7 Q0 _

' y; I$ _- a3 Q4 j问题解决方式 2.0
! c" N/ p! A; V" z/ @# Y上面的解决方式虽然能够解决问题, 但是在 yaml 中直接插入脚本不好维护, 也容易出错. 如果有多个依赖, 或者多层依赖的时候, 复杂度会直线上升.
  j8 E9 D8 Y$ c! U* \0 n& S6 Q& z1 e: i: x% l5 o
所以, 要封装一个 entrypoint.sh 脚本, 可以接受启动命令, 以及需要等待的服务和端口. 脚本内容如下:
9 w; ]5 q- }6 D
! B  N' d8 c3 v' K6 h#!/bin/bash$ D3 P8 [; |; m0 O- a
#set -x
1 O( b: [* k9 W" Q- q2 d; T. ~6 T( \6 t#******************************************************************************1 a! m0 i6 o+ Z% A) N9 q. [
# @File    : entrypoint.sh
: A1 X) x/ ~% L% _# @author  : wangyubin: `1 X$ \9 p+ P4 {% c5 \9 i
# @date    : 2018-08- 1 10:18:43- |& K  N* b( p; N
#
# b( I% `( N5 M# @brief   : entry point for manage service start order
# o* P1 b& a  D' i( z/ ?- P8 P# history  : init% f% U  b' `. A- G" s: `
#******************************************************************************7 j+ Y! b+ i/ S- N3 _3 d4 `7 P
. B2 M- T* L- r7 U7 a4 b( P  O1 w
: ${SLEEP_SECOND:=2}2 d, R( T- g" L" ^

7 P8 ^- @$ h  j0 |+ I) ^" xwait_for() {
9 }* u8 P) O' P* {% C& G    echo Waiting for $1 to listen on $2...
9 s/ w5 {0 ^) y1 f    while ! nc -z $1 $2; do echo waiting...; sleep $SLEEP_SECOND; done
9 i: ~  k# k. w2 i}
! D8 k5 j0 y# q# E5 D
7 v+ E+ F( ~! Z4 xdeclare DEPENDS; L& u7 D0 I4 H0 ?2 m
declare CMD
% f6 a4 I2 ?+ a& ~( Y2 u5 C: `% X! J$ F" y
while getopts "d:c:" arg  H3 A* g( k, Z* a+ ]. P1 ?+ [/ M
do1 g0 I: v; D; `6 c, R
    case $arg in7 K- P: x; e+ _
        d)6 H/ F( q! @$ }# c5 ^: o* M. n' C
            DEPENDS=$OPTARG6 l4 `+ h# @4 W. z) L
            ;;* }% J- D( C4 s
        c). Z4 n# C/ G: b& ^4 N4 j. X
            CMD=$OPTARG: @  r- \4 Q$ K3 l; |! ]  _5 e$ F
            ;;4 S5 b( L* h- j
        ?)
+ F' k; V/ _( w            echo "unkonw argument"3 t- O/ J  c; T8 u
            exit 1
6 Q/ x7 J) n4 |% c7 m+ h- b1 V            ;;+ r# c: ?! F3 {% z$ n% [/ C  Y
    esac0 U5 B0 ~6 I8 f) O" k1 I
done' E; @8 d. R) N# m" J9 M6 C5 p$ Q& b+ A

4 V. b9 L' u& i2 kfor var in ${DEPENDS//,/ }
0 [. Y, l; B& p! H& Tdo; v. B. J) V9 b( r- l$ d
    host=${var%:*}
" I% P( t% Q* y( D    port=${var#*:}
( T- R/ I9 D( h7 O    wait_for $host $port
. }. _4 i+ c% |0 f! a3 Fdone/ R9 i  n# O: t4 ?1 u. ]
8 t- [# g- E2 ]3 G
eval $CMD; o  D' _9 K+ Z, H
这个脚本有 2 个参数, -d 需要等待的服务和端口, -c 等待的服务和端口启动之后, 自己的启动命令! \) Q, l/ L4 G3 F; ~
2 P) u6 K- ~. M4 c, \
修改 docker-compose.yml, 使用 entrypoint.sh 脚本来控制启动顺序.1 w! Z9 N: H$ h8 A! V/ r

- ?+ L8 w' Q0 _5 \5 l  A- j7 rversion: '2'
) B) e( l5 L8 x) eservices:4 ?/ B5 u) h5 v* V8 K0 [. z+ C
  web:1 A4 u; ^; j0 W# m# |
    image: ubuntu:14.04; E2 t) B* Q1 u+ ?" ?2 C! [, c/ B
    depends_on:# @1 S, A5 t2 B, m
      - database  T. K* g$ ^' a& Y& y
    volumes:
# ~4 P% M$ ?- P! C      - "./entrypoint.sh:/entrypoint.sh"
7 S3 W4 \7 p, {0 W# P, k, A% e* s    entrypoint: /entrypoint.sh -d database:3306 -c 'echo "start web service here"';4 F6 N7 X6 c9 t+ M: }

8 k# G3 B# R; g% g9 y% K  database:1 @. `5 Q: L3 ^: l7 B4 M
    image: ubuntu:14.04
4 P- W; j: {% d) X    command: >
7 }! }) t  o4 U: t6 m5 s) C      /bin/bash -c '
* L' A5 P. m7 o      sleep 5;  f2 Z3 a0 e6 O
      echo "sleep over";2 B2 V  |5 W' v
      nc -lk 0.0.0.0 3306;
# w+ I2 A+ V% y8 c+ ~; S      '
! W  h1 ~5 \" F; Q/ f1 C实际使用中, 也可以将 entrypoint.sh 打包到发布的镜像之中, 不用通过 volumes 配置来加载 entrypoint.sh 脚本.
% B7 T  z. Y; I* Z
2 G  F6 {* R- i* C测试结果如下:" M: C4 |9 B- D# z  }
& T0 G  ]2 P5 M; ~5 D
$ docker-compose up
" O0 K  I0 v" ~. XStarting tmp_database_1 ... done
! \" i( d; [1 k" r6 W  J4 ^. ~0 {Starting tmp_web_1 ... done
# s4 l# I, [% o' {6 D% _, tAttaching to tmp_database_1, tmp_web_1% U7 s6 u- J9 r' D3 C
web_1       | Waiting for database to listen on 3306...
+ K' q+ D1 g$ D5 r0 Eweb_1       | waiting..." [# q3 c6 ?# u& ?
web_1       | waiting...
! j& S1 t$ M2 k. Z; p# d0 `8 Vweb_1       | waiting...
/ o0 D. ~5 J( ~4 `4 F# y0 _database_1  | sleep over0 L- f* F8 l# K- e. P. F, o! m! a& H
web_1       | start web service here  P" y/ T; j/ b- N' ~* R" b6 N! n: ]
tmp_web_1 exited with code 0
6 T. N5 T9 m  O, g补充. g6 K1 z4 l$ }& j. M2 w4 I6 V
依赖多个服务和端口
7 Q- {+ c5 ~! C6 z3 x' |使用上面的 entrypoint.sh 脚本, 也可以依赖多个服务和端口, -d 参数后面的多个服务和端口用逗号(,)隔开.
" j) @8 F+ _+ z1 m
# M. `/ {( ^3 u8 Y% \4 ~# ]version: '2'# E: q7 N/ a' }( Q* z5 E
services:
1 k# K/ i* e6 h( {  web:$ K0 Q$ x: o3 k
    image: ubuntu:14.046 s: L: t& |1 o' P& o
    depends_on:
+ a, k& Y% V: U. ]- r8 G8 I      - mysql
/ s, F2 k! q$ @/ G, Q+ B      - postgresql9 |* h4 M) I. m( s' w2 X
    volumes:/ R4 K& L1 f! ?# m4 l- m: ~
      - "./entrypoint.sh:/entrypoint.sh"
2 o7 d% Q4 ]! w    entrypoint: /entrypoint.sh -d mysql:3306,postgresql:5432 -c 'echo "start web service here"';# y6 m0 e) Q! Q& t

7 ?5 X# V; H0 ]7 E/ n, ^  mysql:! R- Q( F' p3 V; O: B; D
    image: ubuntu:14.04
- Z* f2 J- C" B" O; ]; L5 z' J    command: >
4 e9 o  f, X4 |: _7 O      /bin/bash -c '/ H* i' |5 X2 t% Z
      sleep 4;. N2 l9 p# h% [/ L8 O7 e: k/ y
      echo "sleep over";% D" I; m( H, A1 z9 I/ H; @
      nc -lk 0.0.0.0 3306;' g1 l* X2 J2 M: t  d0 S3 a+ w+ N
      '
- T& o  r! h$ `0 B  postgresql:# q+ F$ R- n+ [% ]
    image: ubuntu:14.04
) k0 L6 D1 {& ?3 h    command: >" m! W; H7 l0 J2 {6 _
      /bin/bash -c '
: J- q9 t" u+ C: d5 P+ ]      sleep 8;
5 P8 X4 q  q4 r. a, U! C      echo "sleep over";
' a  X2 e8 N& l  K/ @      nc -lk 0.0.0.0 5432;
: z6 n; `" v1 H: k      '
2 d( N: s& n+ R4 |9 `执行的效果可以自行尝试.
/ ^% n6 j2 m, g' \* D/ D. Y0 \
, O: v# O- X# a( O" S5 w; {尝试间隔的配置
: [- y* e9 }6 d( Z) p每次尝试连接的等待时间可以通过 环境变量 SLEEP_SECOND 来配置, 默认 2 秒 下面的配置等待时间设置为 4 秒, 就会每隔 4 秒才去尝试 mysql 服务时候可连接.
: }" J; s9 J& u9 a0 ?5 o0 d6 K4 s
version: '2'0 i) m+ e4 `5 t/ g9 l
services:7 A1 R4 F1 n& z: Q: D& q& `# k& z
  web:
7 c: A4 y8 C0 M! o5 p) Z    image: ubuntu:14.04
/ @! e3 K5 N2 W    environment:9 e; n& X; H0 v: J8 k( C4 ]
      SLEEP_SECOND: 4& H/ v1 U4 _3 j0 K: i: y- N
    depends_on:  W  R$ E* u0 J, t* z. f
      - mysql
+ t2 X/ ?$ X0 G9 i) n  K    volumes:4 u; x0 K/ `0 _, Z" J' I7 f
      - "./entrypoint.sh:/entrypoint.sh"( J4 y/ X7 c: W2 T
    entrypoint: /entrypoint.sh -d mysql:3306 'echo "start web service here"';
3 R5 V, F) q1 k- y. A3 R4 X& G7 E. ?
  mysql:" M- Y! f  ^7 d( ^
    image: ubuntu:14.04
; {! @# u  u5 n" q% b3 l0 q; |    command: >
  W9 D( K' X+ V4 h      /bin/bash -c '
) r/ z' o1 S$ i" E7 O      sleep 4;
" ^- W. C! P# S& b8 c      echo "sleep over";
! `% l0 U  R' \; f. j/ F5 X      nc -lk 0.0.0.0 3306;

该用户从未签到

2#
发表于 2020-8-10 18:05 | 只看该作者
docker compose 服务启动顺序控制
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-11-24 23:49 , Processed in 0.140625 second(s), 23 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表