Docker:Docker-compose编排微服务顺序启动解决方案

本文介绍了如何在DockerCompose中处理微服务之间的依赖关系,以确保服务按照特定顺序启动。通过配置`depends_on`、`restart`属性,以及自定义启动脚本(如wait-for.sh和entrypoint.sh),实现服务启动的有序性和容错处理。
摘要由CSDN通过智能技术生成

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

1)配置docker-compose.yml

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

version: "3"
services:
# 指定服务名称
#服务注册与发现中心
simonEureka:
image: simon/eureka-server:2.0.1-SNAPSHOT
hostname: simonEureka
ports:
- "8100:8100"
#配置中心
simonConfig:
image: simon/config-server:2.0.1-SNAPSHOT
hostname: simonConfig
ports:
- "8101:8101"
depends_on:
- simonEureka
restart: always
#路由网关
apigateway:
image: simon/apigateway:2.0.1-SNAPSHOT
ports:
- "8102:8102"
depends_on:
- simonEureka
- simonConfig
restart: always
#监控平台
admin:
image: simon/admin:2.0.1-SNAPSHOT
ports:
- "8103:8103"
depends_on:
- simonEureka
- simonConfig
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)各微服务镜像构建配置 

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

<!-- Docker maven plugin -->
<plugin>
	<groupId>com.spotify</groupId>
	<artifactId>docker-maven-plugin</artifactId>
	<version>1.0.0</version>
	<configuration>
		<imageName>simon/${project.artifactId}:${project.version}</imageName>
		<!--<dockerDirectory>src/main/docker</dockerDirectory>-->
		<forceTags>true</forceTags>
		<baseImage>java</baseImage>
		<!--安装镜像所需要的软件-->
		<runs>
			<!--同步 /etc/apt/sources.list 和 /etc/apt/sources.list.d 中列出的源的索引,这样才能获取到最新的软件包-->
			<run>["apt-get","update"]</run>
			<!--安装netcat-->
			<run>["apt-get","-y","install","netcat"]</run>
		</runs>
		<entryPoint>["java","-jar","/${project.build.finalName}.jar"]</entryPoint>
		<resources>
			<resource>
				<targetPath>/</targetPath>
				<directory>${project.build.directory}</directory>
				<include>${project.build.finalName}.jar</include>
			</resource>
		</resources>
	</configuration>
</plugin>

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

3)同步等待脚本和使用

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

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

#!/bin/sh

TIMEOUT=15
QUIET=0

echoerr() {
if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 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\n" "$1"| cut -d : -f 1)
PORT=$(printf "%s\n" "$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 "$@"

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

./wait-for.sh --help

示例:

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

baidu is up

3.2)docker-compose.yml

#docker compose编排微服务脚本version: "3"services:
# 指定服务名称
simonEureka:
image: simon/eureka-server:2.0.1-SNAPSHOT
hostname: simonEureka
ports:
- "8100:8100"
simonConfig:
image: simon/config-server:2.0.1-SNAPSHOT
hostname: simonConfig
ports:
- "8101:8101"
volumes:
- "./wait-for.sh:/wait-for.sh"
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

#!/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

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
#避免执行完命令之后退出容器
tail -f /dev/null

这个脚本有 2 个参数,:

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

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

3.4)docker-compose.yml

#docker compose编排微服务脚本version: "3"services:
# 指定服务名称
simonEureka:
image: simon/eureka-server:2.0.1-SNAPSHOT
hostname: simonEureka
ports:
- "8100:8100"
simonConfig:
image: simon/config-server:2.0.1-SNAPSHOT
hostname: simonConfig
ports:
- "8101:8101"
depends_on:
- simonEureka
volumes:
- "./entrypoint.sh:/entrypoint.sh"
environment:
SLEEP_SECOND: 4
tty: true
entrypoint: /entrypoint.sh -d simonEureka:8100 -c 'java -jar /config-server.jar';
apigateway:
image: simon/apigateway:2.0.1-SNAPSHOT
ports:
- "8102:8102"
depends_on:
- simonEureka
- simonConfig
volumes:
- "./entrypoint.sh:/entrypoint.sh"
environment:
SLEEP_SECOND: 4
tty: true
entrypoint: /entrypoint.sh -d simonEureka:8100,simonConfig:8101 -c 'java -jar /apigateway.jar';
admin:
image: simon/admin:2.0.1-SNAPSHOT
ports:
- "8103:8103"
depends_on:
- simonEureka
- simonConfig
volumes:
- "./entrypoint.sh:/entrypoint.sh"
environment:
SLEEP_SECOND: 4
tty: true
entrypoint: /entrypoint.sh -d simonEureka:8100,simonConfig:8101 -c 'java -jar /admin.jar';

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

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

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

$ docker-compose up

[root@kingbal simon2.0]# docker-compose up
Starting simon20_simonEureka_1 ... done
Starting simon20_simonConfig_1 ... done
Starting simon20_admin_1 ... done
Starting simon20_apigateway_1 ... done
Attaching to simon20_simonEureka_1, simon20_simonConfig_1, simon20_admin_1, simon20_apigateway_1
simonConfig_1 | Waiting for simonEureka to listen on 8100...
simonConfig_1 | waiting...
admin_1 | Waiting for simonEureka to listen on 8100...
admin_1 | waiting...
apigateway_1 | Waiting for simonEureka to listen on 8100...
apigateway_1 | waiting...
......

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值