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

docker compose 服务启动顺序控制

[复制链接]

该用户从未签到

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

EDA365欢迎您登录!

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

x
概要
0 N4 y5 `& z. T5 K" k3 e# j" Vdocker-compose 可以方便组合多个 docker 容器服务, 但是, 当容器服务之间存在依赖关系时, docker-compose 并不能保证服务的启动顺序.1 @/ A' S! U+ `' ^% \
( L& p, J& x( s/ T% k' U8 h: N
docker-compose 中的 depends_on 配置是容器的启动顺序, 并不是容器中服务的启动顺序.8 i  c2 \$ m/ f' d* B& f

, h! Q% F, e" M$ z, B- {2 ^问题重现
6 j$ U' V( v6 Y( X+ B首先, 我们构造一个示例, 来演示 docker-compose 带来的问题. docker-compose.yml 文件如下:
& o. {% u, [" g( g
& P2 w; Q: N3 e% f+ d% V& nversion: '2'$ D6 q, g2 f' L3 q5 @
services:
+ K# C' v8 `: ?) R6 E  web:
) ]- f  i9 O- B6 k3 ]% b9 x1 `    image: ubuntu:14.04
( r# t+ j; p0 h( v& f    depends_on:
8 d6 f/ ^2 e0 Q" B4 e      - web4 G$ L- c" J% k; U. _
    command: nc -z database 33066 o+ c! y5 U6 k1 {6 M3 Y0 s9 M( q* T

& |( y/ t! L' I; M  database:
" B6 _" ?$ J' d4 i0 z4 B- o    image: ubuntu:14.04
, D* K" U- g7 e0 n+ W* T    command: >9 h5 ^4 \& m" w$ v3 `& G! U
      /bin/bash -c '9 K$ j% u' k! R1 h/ [% O
      sleep 5;0 T; ^3 S" |: U0 B2 Z: ?8 R5 Y
      echo "sleep over";7 L7 v7 F# Q0 a
      nc -lk 0.0.0.0 3306;6 C& t& t6 d5 t  z8 d* s( x
      '
% U4 F5 K4 u5 ?& J启动后, 可以发现, 确实是先启动 database, 后启动 web, 但是 database 中的服务是在大约 5 秒后才完成的, 所以导致 web 的启动失败.) B- R/ ~5 w. a0 X' }6 w+ j) E
! u! ?+ ^0 e, I7 L6 N; |+ G
$ docker-compose up
% z' q0 D) c' E  `2 P2 o; X7 _, uCreating tmp_database_1 ... done. q7 D) h1 Y: J8 f; e& m) r
Creating tmp_database_1 ...$ n& h* ?2 H# P6 W8 }( n
Creating tmp_web_1      ... done- V5 m1 u9 `, h: V. f8 h( r
Attaching to tmp_database_1, tmp_web_1
! u/ M8 s8 ^5 a3 N! o; btmp_web_1 exited with code 1
. P' s+ [/ ?( Z- [& ]' Hdatabase_1  | sleep over
9 {: v# a6 c' |5 }8 X& p问题解决方式 1.0
/ f, w, I, A8 q( ^; r5 |+ y4 D修改 web 的启动脚本, 等待 database 的端口通了之后再启动服务
4 m1 H) O1 V0 w! W
& B4 a/ m0 N; _# ?  [version: '2'
. n' `- l( Q" N4 ^4 Pservices:1 L+ c* _% B/ @, v; l$ s$ M* E
  web:& ?& \& _% x2 k8 E
    image: ubuntu:14.04
# ~8 k2 n; N% H) c7 M7 \    depends_on:
  C' w0 {. m- ^' b      - database
! ~: P9 x+ \  S1 h7 T( N. D% W    command: >/ o- i+ U8 R  ^7 m) j* s
      /bin/bash -c '
2 m& B( g0 p: b' @      while ! nc -z database 3306;4 G& o& ?; c  }% }9 i; `( a! M
      do4 V. s# [( G* V3 o7 q2 U
        echo "wait for database";" S" V/ Z% q) F; M, I6 S3 [, O
        sleep 1;/ o9 @, U* @4 C, f2 C# U( ~  d0 L
      done;8 D! V" b  C, s( N7 o0 \

" O1 q0 l# S6 C  U/ R      echo "database is ready!";
& r; Y0 C, ~, f. U" L      echo "start web service here";
& s% n% Z* E- ^% c; n8 {- |% r      ': o- d: E7 }5 N9 `5 p3 j

' ?$ M$ x* e2 Z; T0 P& Q  database:3 T# h+ g6 T; @9 ?2 _' f
    image: ubuntu:14.04! @1 ]* X& x4 t" @
    command: >  x% u7 Q$ a% b4 s) |$ v! f) e3 L
      /bin/bash -c '
% n0 A, X& e" I$ [  T) ?      sleep 5;
& W- l) R3 [7 j7 r' a      echo "sleep over";: a  I$ u2 m" S. N  h. k/ p
      nc -lk 0.0.0.0 3306;* m) b4 ^3 |) w6 H% x% m, b8 b1 N8 f
      ', _: {' P- D9 r; h8 _; V  |
再次启动,
* j5 n+ ^2 K" }2 ~& m! I2 r" j: o% }2 w: h4 C+ c+ Z1 o
$ docker-compose up
& v% L$ x" Q5 _4 k$ Z7 HCreating tmp_database_1 ... done6 J) y2 t% C$ Q5 m
Creating tmp_database_1 ...
2 ?9 A, b4 G' lCreating tmp_web_1      ... done/ |  O, A1 }" t6 a  Y! i3 _9 F
Attaching to tmp_database_1, tmp_web_1" V2 F; x9 o9 v9 a8 w  Z- g; O
web_1       | wait for database
' n# E) M/ S% J& {! _# hweb_1       | wait for database
5 ~+ J5 f$ b7 }4 v! k" D, D6 _web_1       | wait for database! d9 s8 w( T$ O7 [# J
web_1       | wait for database, Y) Y; d1 g( \) S; a7 u* O
web_1       | wait for database5 w( G8 ]4 K6 i- h( S; M
database_1  | sleep over5 E" l' q  h( k/ }3 D
web_1       | database is ready!
4 n& P. y' R+ k5 Zweb_1       | start web service here% I1 c$ Q' t0 Z# T: u
tmp_web_1 exited with code 0
' E5 t0 h6 C9 ?- }  F* N, oweb 会在 database 启动完成, 端口通了之后才启动.
2 w+ x3 ]& ^( e$ Z- c" q: `
$ [; P, a; C5 G% G2 E& X2 z, t% o问题解决方式 2.0: Y$ b( R. O2 e9 C) z1 X* N  J
上面的解决方式虽然能够解决问题, 但是在 yaml 中直接插入脚本不好维护, 也容易出错. 如果有多个依赖, 或者多层依赖的时候, 复杂度会直线上升.$ Z6 L; }& {# U  g  L
0 V0 Q4 @: X, V" h
所以, 要封装一个 entrypoint.sh 脚本, 可以接受启动命令, 以及需要等待的服务和端口. 脚本内容如下:
& l7 D' E% ^. v" {% C+ G% T- v1 f% s- E9 E- Q" n
#!/bin/bash
( X' @) R/ x) U  A. r( o7 J/ Q  y#set -x$ b  O1 V: m' l
#******************************************************************************/ Y1 W& n3 Q  d
# @File    : entrypoint.sh7 T9 `( h1 {8 M6 u; H
# @author  : wangyubin
* X5 X# f9 }# z9 p1 w% O% R# @date    : 2018-08- 1 10:18:434 d* Q% d# y2 ?: w5 `/ C+ b( f
#
- y* g/ [0 R; N1 B# @brief   : entry point for manage service start order
) V* l2 h7 w9 T; ?/ _# history  : init0 p4 T- B- [7 `( M+ t$ y7 A  `
#******************************************************************************
$ P6 f) n1 N( ]: N! q- w  @
  Q1 U- M5 v" O! C- j, h  g: ${SLEEP_SECOND:=2}, j- o- y7 b+ Y, D

. e" U! a# U( {8 h1 K" ~& |wait_for() {' N- c& W  o/ G
    echo Waiting for $1 to listen on $2...
6 F( V% Z7 n; C+ ~0 f    while ! nc -z $1 $2; do echo waiting...; sleep $SLEEP_SECOND; done
* `+ m) S: H$ n/ x3 O7 A/ H  t% \}
+ D2 Q& r( b& s- K# q" [! _
1 Z: u7 C* D$ X/ r& o" e6 pdeclare DEPENDS* @, M' `: P1 z. q* G
declare CMD
2 c% o/ _/ E, b4 d' H. Y" {; n. Q) E# Q
while getopts "d:c:" arg- e0 }# U% d/ R: `5 h7 b; ]( `2 U
do
# `, e, O  N8 H8 b* }2 k. `    case $arg in& t0 }2 i: V+ G( m
        d)1 D8 F' y# h# g1 D" ]6 L1 \
            DEPENDS=$OPTARG3 K% ]/ F% s0 u( ~7 N- [! I
            ;;7 x+ l% w; R- W+ D
        c)
6 C- ~7 \* b  W* I* V9 D' J% b            CMD=$OPTARG
: ^# A6 }+ V4 Q, g* N$ R1 W0 n8 ~& y7 E            ;;
/ Q% G  B; w# b3 i2 a: W* A        ?)5 E, z2 X" }' N+ ?2 W
            echo "unkonw argument"
) l. B1 C  d7 u2 l7 |1 _6 d; _            exit 1
4 X2 ]3 `6 T: b% _) o. E            ;;
; G% D$ o& W0 |: c9 z& T    esac
2 i3 x5 j  h$ n4 P) u8 y; rdone
0 P; }0 D6 n$ Q, R& x0 V. J# g/ x, q- R. r
for var in ${DEPENDS//,/ }
+ [. ?6 Y- y8 Y4 j7 e( T- jdo& o* ]  p' `. H* ?% F
    host=${var%:*}/ C4 P& W3 o! K7 T# E  ^, U
    port=${var#*:}
$ y$ ^: q' T5 r7 S# T, L! \  G    wait_for $host $port
5 z# p5 R1 h; o5 c' O4 P/ @' N1 jdone
8 f( c; R" i8 r6 ?( Z0 T1 f! A2 ^4 x  v: N- j( y1 D+ x( T
eval $CMD- e  k- T% _3 c  P2 |2 s& C3 i
这个脚本有 2 个参数, -d 需要等待的服务和端口, -c 等待的服务和端口启动之后, 自己的启动命令
& \- F1 T7 A: K8 Z' l8 n4 w" N- D& t
4 p( ^1 p. E3 K; y8 N/ J/ O修改 docker-compose.yml, 使用 entrypoint.sh 脚本来控制启动顺序.$ H: v1 h( \( C/ A6 Y( D' Z

: M9 r& c! g: d6 {3 Tversion: '2'* s2 V6 ~: S& U: m
services:: ^/ k# F& n7 D6 m* _; \- ]  j. Q6 V
  web:& O9 Y3 F4 q$ x* u
    image: ubuntu:14.04" M& i6 h" B+ W8 c/ ~" W
    depends_on:
- m- H9 d$ b0 l0 C5 x      - database2 j5 @! {: n! j  U1 h
    volumes:. J5 x' w/ z7 X  y; ^
      - "./entrypoint.sh:/entrypoint.sh"# d$ v+ g! Z, |- g
    entrypoint: /entrypoint.sh -d database:3306 -c 'echo "start web service here"';3 y, ]6 h& a) u* s8 E! U% l

8 ]. K: M% M8 X1 U- G  database:' @7 {. e0 a- y2 H
    image: ubuntu:14.041 [, ]0 {) c* D  j
    command: >* X- r% a$ E" R# h8 t
      /bin/bash -c '
3 j. w5 X* a$ @2 L5 i' {3 g9 g      sleep 5;
. q1 T5 {) v3 Z+ l( z+ q      echo "sleep over";# d5 _: P+ _$ a: z; l* e4 U
      nc -lk 0.0.0.0 3306;7 s' l$ _; }3 A. M( t
      ') o" y5 h+ {& F
实际使用中, 也可以将 entrypoint.sh 打包到发布的镜像之中, 不用通过 volumes 配置来加载 entrypoint.sh 脚本.4 |, R! G0 M1 V

$ P% Q+ X7 D1 ^6 p$ G0 ^8 R测试结果如下:
, `% e& x; O, W. b+ [& Q' G& R! h; z. u& X/ k
; E; E. _8 s- V& P4 w' v. F7 I1 O9 n$ docker-compose up/ v: Z, y: x3 K. r% ]( ?
Starting tmp_database_1 ... done
( O7 C, I0 g) L  J3 w/ Q! ]# tStarting tmp_web_1 ... done4 c; N. X  C3 C, _" {9 s
Attaching to tmp_database_1, tmp_web_1
1 ~5 {0 t+ C) }- s6 t& Q, C) ?. W$ yweb_1       | Waiting for database to listen on 3306...
) A6 _: Q/ G4 F- @$ n! Y2 Pweb_1       | waiting...
. e0 a- w! |& T9 p8 F9 H/ {4 Uweb_1       | waiting...
2 u! _6 H% P) k1 i9 eweb_1       | waiting...  B8 ?. r: \% g+ J# V
database_1  | sleep over, y  A$ G; o! y+ L# l: o- y
web_1       | start web service here
. x6 M( r, _) L' l, S8 ^  S$ mtmp_web_1 exited with code 01 Q( g- S9 W% Z) X
补充
# Q: f+ H* H" X依赖多个服务和端口
% b/ c% _0 M; N) X  f使用上面的 entrypoint.sh 脚本, 也可以依赖多个服务和端口, -d 参数后面的多个服务和端口用逗号(,)隔开.
5 N" p; \0 m; k
6 i( ]. J" R+ f8 A% Xversion: '2'; }' Q/ L) W. W- ^$ H( k: i2 S
services:: t# I. N) h+ l. e/ G7 A9 `
  web:
4 a6 Q+ G# z, O% V* X) L8 d& Z    image: ubuntu:14.049 Q& D8 \/ F% l9 }
    depends_on:
) |+ J$ ]+ J( F& t7 K8 Z      - mysql
4 ~1 s4 ^# g; L      - postgresql
% P8 Z, F! i. h9 O    volumes:
4 D& N) Y! V6 u" L. q2 [      - "./entrypoint.sh:/entrypoint.sh": ~& K  s1 q1 F" U
    entrypoint: /entrypoint.sh -d mysql:3306,postgresql:5432 -c 'echo "start web service here"';: t" Y: w" X% P2 K( a$ r  h0 q

" f  p, i7 b2 G  mysql:
8 i) n# B# B8 I  @( r( R    image: ubuntu:14.047 ?. T; {0 t9 c  }
    command: >: t" |+ u* V1 I. U
      /bin/bash -c ') K* p. ]7 S) d9 L# @! z+ \
      sleep 4;$ z* \$ m; x, u0 S* C1 i
      echo "sleep over";8 r% E% V3 q4 l' [+ z/ U# R9 }
      nc -lk 0.0.0.0 3306;
) n# [) t1 r  x3 \7 [: h5 n  _      '
+ }- s9 X3 J+ r/ O/ m; M  postgresql:8 `  g& N* ]/ A# e- l  s8 p
    image: ubuntu:14.043 T- J; Z' j" C  K* I5 |4 N! v
    command: >
0 ]0 D* X: @) S5 W. B& U      /bin/bash -c '
+ d: r& ~3 W( C% c, ~      sleep 8;9 `6 X, u+ x5 X# D) @
      echo "sleep over";
9 o2 `! c, p6 o% K3 G* x( x5 ^  M      nc -lk 0.0.0.0 5432;
. O! a8 k/ ^/ D; `& T, p      '
- M4 a6 X/ [  C5 T. W执行的效果可以自行尝试.
) K0 M  p0 I* ^
4 a9 N' d. m; g% k/ h1 \9 `, {尝试间隔的配置
) s3 ~3 p# S4 [* |) D* y每次尝试连接的等待时间可以通过 环境变量 SLEEP_SECOND 来配置, 默认 2 秒 下面的配置等待时间设置为 4 秒, 就会每隔 4 秒才去尝试 mysql 服务时候可连接." ^' r- S* i: B
1 }" p4 P: F- l8 d/ L! |( r
version: '2'
( G, K& g3 V  H$ Xservices:4 O  j, A' ^/ F5 |7 V; _8 n
  web:
$ H/ B. A) v3 q4 N) Z$ {4 a    image: ubuntu:14.04; c+ s3 E: Z4 d7 E6 c7 C* G
    environment:  b; V7 a9 d% q0 C
      SLEEP_SECOND: 44 L. Y) I9 @8 I' l
    depends_on:
6 F" Q& z; W; t+ K% J5 L  R0 d      - mysql
& I8 H  F; n* |6 z9 x$ T+ d    volumes:8 @( U' }& _. T! ?% N5 y" V
      - "./entrypoint.sh:/entrypoint.sh"
* B3 n3 L6 ?5 `5 x    entrypoint: /entrypoint.sh -d mysql:3306 'echo "start web service here"';
* P# c) ]9 U8 p: \
" ^! n+ Z& y7 O6 L- v5 S6 h  mysql:
3 g. _3 ?# c* m( o    image: ubuntu:14.04& J+ ~9 T* a5 j, {' V7 k
    command: >
6 b" ~& x$ s* f+ X: h- ]      /bin/bash -c '
' @/ P  A3 m! l0 x. H( T' `( B3 m      sleep 4;
1 K, H- s4 e- ]7 O* t      echo "sleep over";
9 Y8 R6 l- e7 Z: l6 w$ M  @6 `      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-25 02:01 , Processed in 0.187500 second(s), 24 queries , Gzip On.

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

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

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