基于Docker Compose进行服务编排时,一定碰到服务启动顺序的问题,例如:B服务启动之前,A服务要已经启动并且可以正常对外服务。

这个启动顺序的问题,Docker Compose本身它是无法解决的,即使定义了depends_on或者links,它只能保证该服务依赖这些服务,启动本服务时会将依赖的服务也启动,但是启动顺序无法得到保证。

目前本人实验比较好的方案有两种:

  • 基于wait-for-it.sh实现,前提条件是本镜像要支持bash
  • 对于自己构建的镜像时,让工程本身带一个监听类,用于监听依赖服务是否启动,这种方式有侵入性,同时对于第3方的镜像,不太好实现

1、wait-for-it.sh方案

wait-for-it.sh是GitHub中开源一个脚本,很轻量也很实用,以一个例子说明其的法:

本例子中定义了2个服务,一个mysql服务,一个cs2_serv服务,这个cs2_serv需要等mysql启动好并做好初始化后才能启动,要不然cs2_serv服务会由于没法连接到数据库而报错。

version: "3"
services:
mysql:
image: mysql:5.6
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=jgyw@123
- MYSQL_USER=cs2
- MYSQL_PASS=cs2123
volumes:
- ./db/mysql:/var/lib/mysql
- ./db/init:/docker-entrypoint-initdb.d/ cs2_serv:
image: cs2_serv:v1
ports:
- "81:81"
environment:
- SERV_PORT=81
- MYSQL_IP=mysql
- MYSQL_PORT=3306
- DB_USERNAME=root
- DB_PASSWORD=jgyw@123
links:
- mysql
volumes:
- ./wait-for-it.sh:/wait-for-it.sh
entrypoint: "/wait-for-it.sh -t 0 mysql:3306 -- "
command:
- /bin/sh
- -c
- |
sleep 10
java -Djava.security.egd=file:/dev/./urandom -jar /app.jar

此处最为核心的代码就是:

    entrypoint: "/wait-for-it.sh -t 0 mysql:3306 -- "
command:
- /bin/sh
- -c
- |
sleep 10
java -Djava.security.egd=file:/dev/./urandom -jar /app.jar

这2个配置的意思是,要等到mysql:3306服务可以用了,才去执行command对应的命令。

同时我在commad命令中再增加等待10s钟,主要为了完全确保mysql服务启动完成,还有就是初始化数据库也完成,最后才去启动cs2_serv服务。

2、自定义监听类

这种方式有一定侵入性,但是配置起来会比较方便,在此以Spring Boot为例,写了一个简单的监听类,即:

package com.swnote.cs2.common.listener;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.Map; import org.apache.log4j.Logger;
import org.springframework.boot.context.event.ApplicationStartingEvent;
import org.springframework.context.ApplicationListener; /**
* 依赖服务检查
*/
public class DependsOnServiceCheckListener implements ApplicationListener<ApplicationStartingEvent> {
private Logger logger = Logger.getLogger(DependsOnServiceCheckListener.class); @Override
public void onApplicationEvent(ApplicationStartingEvent event) {
// 获取环境变量
Map<String, String> envs = System.getenv(); // 环境变量中DEPENDS_ON值,即是依赖的服务,值的内容格式为:host1:port1,host2:port2
if (envs.containsKey("DEPENDS_ON")) {
// 依赖服务是否启动的标志
boolean flag = false; String val = envs.get("DEPENDS_ON");
String[] servs = val.split(","); while (!flag) {
try {
Thread.sleep(5000L);
} catch (InterruptedException e) {
logger.warn("Wait depends on Service started...");
} for (String serv : servs) {
flag = checkServ(serv);
if (!flag) {
break;
}
}
} logger.info("Depends on Service started...");
}
} /**
* 检查服务是否启动
*
* @param serv
* @return
*/
private boolean checkServ(String serv) {
String[] servs = serv.split(":");
String host = servs[0].trim();
int port = Integer.parseInt(servs[1].trim()); Socket socket = null;
try {
socket = new Socket();
socket.connect(new InetSocketAddress(host, port));
logger.info(serv + ": Service started...");
return true;
} catch (Exception e) {
logger.warn(serv + ": Service not started...");
return false;
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}

这个监听类,是将依赖的服务信息放到环境变量DEPENDS_ON中,即是依赖的服务,值的内容格式为:host1:port1,host2:port2,然后每隔5s去测试依赖的服务是否是通的,如果所有依赖的服务都是通的,那么本服务就可以启动,否则本服务一直处于等待状态。

以一个实例说明使用方式,即:

  cs2_web:
image: cs2_web:v1
ports:
- "82:82"
environment:
- WEB_PORT=82
- SERV_DOMAIN=cs2_serv
- DEPENDS_ON=cs2_serv:81
links:
- cs2_serv

这里定义了一个cs2_web服务,该服务是依赖上面例子中的cs2_serv,但是它配置依赖关系是通过环境变量DEPENDS_ON来配置的。

3、参考资料

https://github.com/vishnubob/wait-for-it

关注我

以你最方便的方式关注我:

微信公众号:

微服务架构 - 解决Docker-Compose服务编排启动顺序问题的更多相关文章

  1. asp.net core容器&mysql容器network互联 & docker compose方式编排启动多个容器

    文章简介 asp.net core webapi容器与Mysql容器互联(network方式) docker compose方式编排启动多个容器 asp.net core webapi容器与Mysql ...

  2. 庐山真面目之十二微服务架构基于Docker搭建Consul集群、Ocelot网关集群和IdentityServer版本实现

    庐山真面目之十二微服务架构基于Docker搭建Consul集群.Ocelot网关集群和IdentityServer版本实现 一.简介      在第七篇文章<庐山真面目之七微服务架构Consul ...

  3. 庐山真面目之十四微服务架构的Docker虚拟技术深入探究

    庐山真面目之十四微服务架构的Docker虚拟技术深入探究 一.我的开场白 曾几何时,分布式的发展也影响了后来的微服务架构的实现方式.到了现在,只要涉及到互联网技术领域,就会设计一个概念,那就是微服务. ...

  4. Spring Cloud构建微服务架构(五)服务网关

    通过之前几篇Spring Cloud中几个核心组件的介绍,我们已经可以构建一个简略的(不够完善)微服务架构了.比如下图所示: 我们使用Spring Cloud Netflix中的Eureka实现了服务 ...

  5. Spring Cloud构建微服务架构(二)服务消费者

    Netflix Ribbon is an Inter Process Communication (IPC) cloud library. Ribbon primarily provides clie ...

  6. 整合SPRING CLOUD云服务架构 - 企业分布式微服务云架构构建

    整合SPRING CLOUD云服务架构 - 企业分布式微服务云架构构建 1.   介绍 Commonservice-system是一个大型分布式.微服务.面向企业的JavaEE体系快速研发平台,基于模 ...

  7. AspNetCore容器化(Docker)部署(三) —— Docker Compose容器编排

    一.前言 上一篇部署了一个最基础的helloworld应用,创建了两个容器和一个network,还算应付得过来. 如果该应用继续引入mysql.redis.job等若干服务,到时候发布一次得工作量之大 ...

  8. Docker | 第七章:Docker Compose服务编排介绍及使用

    前言 前面章节,我们学习了如何构建自己的镜像文件,如何保存自己的镜像文件.大多都是一个镜像启动.当一个系统需要多个子系统进行配合时,若每个子系统也就是镜像需要一个个手动启动和停止的话,那估计实施人员也 ...

  9. 微服务架构 - 搭建docker本地镜像仓库并提供权限校验及UI界面

    搭建docker本地镜像仓库并提供权限校验及UI界面 docker本地镜像仓库的作用跟maven私服差不多,特别是公司级或者是小组级开发好的docker仓库可以上传到本地镜像仓库中,需要用时,直接从本 ...

随机推荐

  1. RocketMQ源码 — 九、 RocketMQ延时消息

    上一节消息重试里面提到了重试的消息可以被延时消费,其实除此之外,用户发送的消息也可以指定延时时间(更准确的说是延时等级),然后在指定延时时间之后投递消息,然后被consumer消费.阿里云的ons还支 ...

  2. js实现定时器,时间倒计时为0后停止

    <script type="text/javascript"> var orign_time = 1496706400; var leftTime = Date.par ...

  3. Python 基础【一】

    python运行流程 一.变量及注释 命名: 合法-变量名由字母.数字和下划线组成,并且不能以数字开头.以下保留字不可以当变量名: ['False', 'None', 'True', 'and', ' ...

  4. CSS学习笔记五:display,position区别

    最近常用css,经常在位置方面使用导display与position这两个属性,所以想要弄清楚它们之间的意思. 一.display 作用是规定元素应该生成的框的类型.意思是定义建立布局时元素生成的显示 ...

  5. 杨校老师课堂之JavaScript右下角广告弹框教程

    案例制作思路: 1.先制作界面 添加一个盒子包含一个按钮,使盒子绝对定位在右上角 添加一个大盒子,同理,将盒子居于左下角:其中内部包含一个顶端盒子和底部盒子 顶端盒子因为是属于大盒子内部的存在,所以宽 ...

  6. Linux内核参数调优

    用法: vim /etc/sysctl.conf #修改内容 sysctl -p #生效 相关参数仅供参考,具体数值还需要根据机器性能,应用场景等实际情况来做更细微调整.   net.core.net ...

  7. java中的取整(/)和求余(%)

    1.取整运算符取整从字面意思理解就是被除数到底包含几个除数,也就是能被整除多少次,那么它有哪些需要注意的地方呢?先看下面的两端代码: int a = 10; int b = 3; double c= ...

  8. 居中 html css

    <div id="main" style="width:800px;height: 600px;margin:0 auto"> <!-- 这里 ...

  9. @Scheduled不执行的原因

    1. 今天用@Schedule做了一个定时任务,希望凌晨1点执行,代码如下 @Service public class ParseJsonService { @Scheduled(cron = &qu ...

  10. open_basedir restriction in effect,解决php引入文件权限问题

    一.前言 今天在Ubuntu安装了lnmp环境,运行项目的时候出现了,引入500的错误 二.查看错误 再项目文件入口添加,代码显示错误内容,查看到一下错误 ini_set('display_error ...