当前位置:   article > 正文

Docker:Docker-compose编排微服务顺序启动解决方案_微服务工程中如何让服务按照指定顺序启动呢?

微服务工程中如何让服务按照指定顺序启动呢?

docker-compose可以方便组合多个 docker 容器服务, 但是, 当容器服务之间存在依赖关系时, docker-compose 并不能保证服务的启动顺序。docker-compose 中的 depends_on 配置是容器的启动顺序, 并不是容器中服务的启动顺序。那我们来看看如何 docker-compose 顺序启动微服务的问题

1)配置docker-compose.yml

足够的容错和重试机制,比如从配置中心获取配置文件,服务消费者可以不断的重试直到连上为止,这里就用到了docker-compose 中的 restart配置,docker-compose.yml如下:

  1. version: "3"
  2. services:
  3. # 指定服务名称
  4. #服务注册与发现中心
  5. simonEureka:
  6. image: simon/eureka-server:2.0.1-SNAPSHOT
  7. hostname: simonEureka
  8. ports:
  9. - "8100:8100"
  10. #配置中心
  11. simonConfig:
  12. image: simon/config-server:2.0.1-SNAPSHOT
  13. hostname: simonConfig
  14. ports:
  15. - "8101:8101"
  16. depends_on:
  17. - simonEureka
  18. restart: always
  19. #路由网关
  20. apigateway:
  21. image: simon/apigateway:2.0.1-SNAPSHOT
  22. ports:
  23. - "8102:8102"
  24. depends_on:
  25. - simonEureka
  26. - simonConfig
  27. restart: always
  28. #监控平台
  29. admin:
  30. image: simon/admin:2.0.1-SNAPSHOT
  31. ports:
  32. - "8103:8103"
  33. depends_on:
  34. - simonEureka
  35. - simonConfig
  36. restart: always

docker-compose.yml进行拆分,分成两部分部署, 将要先启动的服务放在一个docker-compose中,后启动的服务放在第二个docker-compose中,启动两次,两者使用同一个网络,启动命令示例:

$ docker-compose -f docker-compose-commond.yml up

同步等待,使用shell脚本阻止当前服务启动,直到所需依赖的服务全部启动之后再启动当前服务。

下面我将详细的讲述第三种解决顺序启动问题的方案。部署的微服务清单如下:

服务名

端口

服务说明

依赖服务

启动优先级(优先级越高越先启动)

eureka-service

8100

服务注册与发现

1

config-server

8101

配置中心

eureka-server

2

apigateway

8102

网关服务

eureka-server,config-server

3

admin

8103

监控服务

eureka-server,config-server

3

2)各微服务镜像构建配置 

由于各微服务的镜像构建配置差不多,这里只列举配置中心的配置:

  1. <!-- Docker maven plugin -->
  2. <plugin>
  3. <groupId>com.spotify</groupId>
  4. <artifactId>docker-maven-plugin</artifactId>
  5. <version>1.0.0</version>
  6. <configuration>
  7. <imageName>simon/${project.artifactId}:${project.version}</imageName>
  8. <!--<dockerDirectory>src/main/docker</dockerDirectory>-->
  9. <forceTags>true</forceTags>
  10. <baseImage>java</baseImage>
  11. <!--安装镜像所需要的软件-->
  12. <runs>
  13. <!--同步 /etc/apt/sources.list 和 /etc/apt/sources.list.d 中列出的源的索引,这样才能获取到最新的软件包-->
  14. <run>["apt-get","update"]</run>
  15. <!--安装netcat-->
  16. <run>["apt-get","-y","install","netcat"]</run>
  17. </runs>
  18. <entryPoint>["java","-jar","/${project.build.finalName}.jar"]</entryPoint>
  19. <resources>
  20. <resource>
  21. <targetPath>/</targetPath>
  22. <directory>${project.build.directory}</directory>
  23. <include>${project.build.finalName}.jar</include>
  24. </resource>
  25. </resources>
  26. </configuration>
  27. </plugin>

runs标签表示在构建镜像的时候,会顺序执行标签run中的命令,因为后面顺序启动微服务需要镜像中包含netcat,所以在构建镜像的时候要进行安装。

3)同步等待脚本和使用

下面一共提供两种脚本,但前提是镜像中必须如上一节安装netcat

3.1)检测服务是否启动的脚本wait-for.sh

  1. #!/bin/sh
  2. TIMEOUT=15
  3. QUIET=0
  4. echoerr() {
  5. if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi
  6. }
  7. usage() {
  8. exitcode="$1"
  9. cat << USAGE >&2
  10. Usage:
  11. $cmdname host:port [-t timeout] [-- command args]
  12. -q | --quiet Do not output any status messages
  13. -t TIMEOUT | --timeout=timeout Timeout in seconds, zero for no timeout
  14. -- COMMAND ARGS Execute command with args after the test finishes
  15. USAGE
  16. exit "$exitcode"
  17. }
  18. wait_for() {
  19. for i in `seq $TIMEOUT` ; do
  20. nc -z "$HOST" "$PORT" > /dev/null 2>&1
  21. result=$?
  22. if [ $result -eq 0 ] ; then
  23. if [ $# -gt 0 ] ; then
  24. exec "$@"
  25. fi
  26. exit 0
  27. fi
  28. sleep 1
  29. done
  30. echo "Operation timed out" >&2
  31. exit 1
  32. }
  33. while [ $# -gt 0 ]
  34. do
  35. case "$1" in
  36. *:* )
  37. HOST=$(printf "%s\n" "$1"| cut -d : -f 1)
  38. PORT=$(printf "%s\n" "$1"| cut -d : -f 2)
  39. shift 1
  40. ;;
  41. -q | --quiet)
  42. QUIET=1
  43. shift 1
  44. ;;
  45. -t)
  46. TIMEOUT="$2"
  47. if [ "$TIMEOUT" = "" ]; then break; fi
  48. shift 2
  49. ;;
  50. --timeout=*)
  51. TIMEOUT="${1#*=}"
  52. shift 1
  53. ;;
  54. --)
  55. shift
  56. break
  57. ;;
  58. --help)
  59. usage 0
  60. ;;
  61. *)
  62. echoerr "Unknown argument: $1"
  63. usage 1
  64. ;;
  65. esac
  66. done
  67. if [ "$HOST" = "" -o "$PORT" = "" ]; then
  68. echoerr "Error: you need to provide a host and port to test."
  69. usage 2
  70. fi
  71. wait_for "$@"

查看使用示例输入一下命令:

./wait-for.sh --help

示例:

  1. $ ./wait-for.sh www.baidu.com:80 -- echo "baidu is up"
  2. baidu is up

3.2)docker-compose.yml

  1. #docker compose编排微服务脚本version: "3"services:
  2. # 指定服务名称
  3. simonEureka:
  4. image: simon/eureka-server:2.0.1-SNAPSHOT
  5. hostname: simonEureka
  6. ports:
  7. - "8100:8100"
  8. simonConfig:
  9. image: simon/config-server:2.0.1-SNAPSHOT
  10. hostname: simonConfig
  11. ports:
  12. - "8101:8101"
  13. volumes:
  14. - "./wait-for.sh:/wait-for.sh"
  15. entrypoint: "sh /wait-for.sh ibaseEureka:8100 -- java -jar /config-server.jar"

实际使用中, 可以将 wait-for.sh 打包到发布的镜像之中, 不用通过 volumes 配置来加载wait-for.sh脚本;

entrypoint配置会覆盖maven docker插件entrypoint标签的配置而执行,这里就是控制服务启动顺序的关键配置。

3.3)检测服务是否启动的脚本entrypoint.sh

  1. #!/bin/bash
  2. #set -x
  3. #******************************************************************************
  4. # @file : entrypoint.sh
  5. # @author : simon
  6. # @date : 2018-08-28 15:18:43
  7. #
  8. # @brief : entry point for manage service start order
  9. # history : init
  10. #******************************************************************************
  11. : ${SLEEP_SECOND:=2}
  12. wait_for() {
  13. echo Waiting for $1 to listen on $2...
  14. while ! nc -z $1 $2; do echo waiting...; sleep $SLEEP_SECOND; done
  15. }
  16. declare DEPENDS
  17. declare CMD
  18. while getopts "d:c:" arg
  19. do
  20. case $arg in
  21. d)
  22. DEPENDS=$OPTARG
  23. ;;
  24. c)
  25. CMD=$OPTARG
  26. ;;
  27. ?)
  28. echo "unkonw argument"
  29. exit 1
  30. ;;
  31. esac
  32. done
  33. for var in ${DEPENDS//,/}
  34. do
  35. host=${var%:*}
  36. port=${var#*:}
  37. wait_for $host $port
  38. done
  39. eval $CMD
  40. #避免执行完命令之后退出容器
  41. tail -f /dev/null

这个脚本有 2 个参数,:

-d: 需要等待的服务和端口,例如:simonEureka:8080,simonEureka:8080,simonConfig:8081;

-c: 等待的服务和端口启动之后, 自己的启动命令,例如:java -jar eureka.jar

3.4)docker-compose.yml

  1. #docker compose编排微服务脚本version: "3"services:
  2. # 指定服务名称
  3. simonEureka:
  4. image: simon/eureka-server:2.0.1-SNAPSHOT
  5. hostname: simonEureka
  6. ports:
  7. - "8100:8100"
  8. simonConfig:
  9. image: simon/config-server:2.0.1-SNAPSHOT
  10. hostname: simonConfig
  11. ports:
  12. - "8101:8101"
  13. depends_on:
  14. - simonEureka
  15. volumes:
  16. - "./entrypoint.sh:/entrypoint.sh"
  17. environment:
  18. SLEEP_SECOND: 4
  19. tty: true
  20. entrypoint: /entrypoint.sh -d simonEureka:8100 -c 'java -jar /config-server.jar';
  21. apigateway:
  22. image: simon/apigateway:2.0.1-SNAPSHOT
  23. ports:
  24. - "8102:8102"
  25. depends_on:
  26. - simonEureka
  27. - simonConfig
  28. volumes:
  29. - "./entrypoint.sh:/entrypoint.sh"
  30. environment:
  31. SLEEP_SECOND: 4
  32. tty: true
  33. entrypoint: /entrypoint.sh -d simonEureka:8100,simonConfig:8101 -c 'java -jar /apigateway.jar';
  34. admin:
  35. image: simon/admin:2.0.1-SNAPSHOT
  36. ports:
  37. - "8103:8103"
  38. depends_on:
  39. - simonEureka
  40. - simonConfig
  41. volumes:
  42. - "./entrypoint.sh:/entrypoint.sh"
  43. environment:
  44. SLEEP_SECOND: 4
  45. tty: true
  46. entrypoint: /entrypoint.sh -d simonEureka:8100,simonConfig:8101 -c 'java -jar /admin.jar';

实际使用中, 可以将 entrypoint.sh 打包到发布的镜像之中, 不用通过 volumes 配置来加载entrypoint.sh脚本;

entrypoint配置会覆盖maven docker插件entrypoint标签的配置而执行,这里就是控制服务启动顺序的关键配置。

其它服务都在等待simonEureka服务启动,这样就实现了服务的顺序启动,最终所有服务全部启动,如下是注册服务信息:

  1. $ docker-compose up
  2. [root@kingbal simon2.0]# docker-compose up
  3. Starting simon20_simonEureka_1 ... done
  4. Starting simon20_simonConfig_1 ... done
  5. Starting simon20_admin_1 ... done
  6. Starting simon20_apigateway_1 ... done
  7. Attaching to simon20_simonEureka_1, simon20_simonConfig_1, simon20_admin_1, simon20_apigateway_1
  8. simonConfig_1 | Waiting for simonEureka to listen on 8100...
  9. simonConfig_1 | waiting...
  10. admin_1 | Waiting for simonEureka to listen on 8100...
  11. admin_1 | waiting...
  12. apigateway_1 | Waiting for simonEureka to listen on 8100...
  13. apigateway_1 | waiting...
  14. ......

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/936955
推荐阅读
相关标签
  

闽ICP备14008679号