docker-compose下的java应用启动顺序两部曲之一:问题分析
在docker-compose编排多个容器时,需要按实际情况控制各容器的启动顺序,本文是《docker-compose下的java应用启动顺序两部曲》的第一篇,文中会分析启动顺序的重要性,以及启动顺序有问题时会有什么样的影响,再给出临时解决的和官方推荐的两种解决方案,为下一篇的实战做好铺垫。
环境信息
本次实战的环境如下:
- 操作系统:CentOS Linux release 7.7.1908
- docker:1.13.1
- docker-compose:1.24.1
- spring cloud:Finchley.RELEASE
分布式环境中的依赖关系
在分布式环境中,各服务之间可能存在依赖关系,例如SpringCloud环境中的应用在启动时都会先往注册中心Eurka发起请求,如下图(来自spring官方博客:https://spring.io/blog/2015/07/14/microservices-with-spring ):

从上图可知,如果Eureka的服务不可用,就会影响业务服务的功能;
Docker环境中的依赖关系
- 上述服务如果用docker-compose编排在一起,也面依赖着问题:Eureka容器启动完毕并且能提供http服务以后,业务服务的容器才能在Eureka注册成功并取得服务列表,通常我们都使用depends_on参数来设定依赖关系;
- 以下是个docker-compose.yml文件,里面有两个容器:eureka和service,eureka是注册中心,service是业务服务,service启动后要去eureka注册,为了确保启动顺序,service配置了depends_on参数:
version: '3'
services:
eureka:
image: bolingcavalry/eureka:0.0.1-SNAPSHOT
container_name: eureka
restart: unless-stopped
service:
image: bolingcavalry/service:0.0.1-SNAPSHOT
container_name: service
restart: unless-stopped
command: sh -c 'java -Xms1g -Xmx1g -cp /app/resources:/app/classes:/app/libs/* com.bolingcavalry.waitforitdemo.ServiceApplication'
depends_on:
- eureka
- 上述yml文件能解决依赖问题吗?service服务启动时能否成功在eureka注册?来试试吧,在Linux电脑上创建docker-compose.yml文件,内容如上所示;
- 在docker-compose.yml所在目录执行docker-compose up,docker服务会先去hub.docker.com下载镜像,然后依次创建容器,控制台会同时打印eureka和service的日志,如下图所示,service注册eureka失败了,请注意图中的文字分析:

- 为何会注册失败呢?继续看后面的日志,如下图,service注册失败后eureka才初始化完成,所以前面的service注册会失败:

- 至此可以确定:depends_on参数可以确保eureka容器启动后再启动service容器,但我们真正想要的,是eureka容器启动后,并且eureka服务初始化完毕进入可用状态后,再启动service容器,显然depends_on参数达不到我们的要求;
- docker官方文档也证实了这一点,如下图红框所示:

- 看来depends_on参数解决不了我们的问题,需要去寻找其他方法;
另外您可能会说:没关系,service会自动重新注册,但是在真实环境中,不是每个服务都有能力去自己解决依赖不可用的问题,例如spring-cloud-config服务如果起不来,依赖它的服务可能会立即停止;
有一种临时方法(此方法V3版语法不再支持)
- 如果eureka容器配置了健康检查,那么service容器可以配置健康检查依赖来控制启动时机,具体的做法可以参考官方示例,如下所示,地址是:https://docs.docker.com/compose/compose-file/compose-file-v2/ :
version: "2.4"
services:
web:
build: .
depends_on:
db:
condition: service_healthy
redis:
condition: service_started
redis:
image: redis
db:
image: redis
healthcheck:
test: "exit 0"
从上述编排内容可见:db容器有健康检查,可以确定db容器的服务是否可用,web容器的depends_on参数内可以配置condition,这样就做到了只有redis已经启动并且db的健康检查通过,才会启动web容器;
2. 上述配置看起来似乎是个不错的方案,在我们这里,只要给eureka配置要健康检查,再让service容器的depends_on参数内配置condition: service_healthy就可以了;
3. 不幸的是:在docker-compose的第三版语法中,取消了condition参数!文档地址是:https://docs.docker.com/compose/compose-file/ ,如下图红框所示:

4. 因此,condition参数看似好用,但是从V3版开始的docker-compose.yml已经不再支持该参数,不能作为标准的解决方案;
官方推荐的方案
如下图红框所示,docker官方推荐使用wait-for-it.sh脚本来解决问题,地址:https://docs.docker.com/compose/startup-order/ :

至此,本篇已经分析了docker-compose下容器启动顺序的问题,下一篇文章,我们用SpringCloud应用来做实战,将其做到在docker-compose下有序启动;
参考文章
如果您对docker容器健康检查有兴趣,可以参考以下文章:
欢迎关注公众号:程序员欣宸
docker-compose下的java应用启动顺序两部曲之一:问题分析的更多相关文章
- docker-compose下的java应用启动顺序两部曲之二:实战
上篇回顾 本文是<docker-compose下的java应用启动顺序两部曲>的终篇,在上一篇<docker-compose下的java应用启动顺序两部曲之一:问题分析>中,我 ...
- 第一课:Centos下配置java环境变量的两种方式(jdk1.8)
配置java环境(yum安装) 1.查出java1.8的全部版本 yum list java-1.8* 2.安装你需要的java1.8 版本(安装的名字根据查询出来的结果输入这里只是举例) yum i ...
- Docker创建MySQL容器环境两部曲
1:下载MySQL镜像 需要执行以下命令,确保主机或者VM联网,从官网下载mysql的最新镜像(镜像版本以官网为主) docker pull mysql 下载成功后执行 docker image ...
- Docker学习笔记之常用的 Docker Compose 配置项
0x00 概述 与 Dockerfile 一样,编写 Docker Compose 的配置文件是掌握和使用好 Docker Compose 的前提.编写 Docker Compose 配置文件,其本质 ...
- Docker小白到实战之Docker Compose在手,一键足矣
前言 Docker可以将应用程序及环境很方便的以容器的形式启动,但当应用程序依赖的服务比较多,或是遇到一个大系统拆分的服务很多时,如果还一个一个的根据镜像启动容器,那就有点累人了,到这有很多小伙伴会说 ...
- docker和docker compose安装使用、入门进阶案例
一.前言 现在可谓是容器化的时代,云原生的袭来,导致go的崛起,作为一名java开发,现在慌得一批.作为知识储备,小编也是一直学关于docker的东西,还有一些持续继承jenkins. 提到docke ...
- Docker学习笔记之使用 Docker Compose 管理容器
0x00 概述 通过之前的介绍,我们已经基本掌握了构建.运行容器的方法,但这还远远不够,由于 Docker 采用轻量级容器的设计,每个容器一般只运行一个软件,而目前绝大多数应用系统都绝不是一个软件所能 ...
- Docker Compose的安装及命令补全
安装Compose Compose的安装有多种方式,例如通过shell安装.通过pip安装.以及将compose作为容器安装等等.本文讲解通过shell安装的方式.其他安装方式如有兴趣,可以查看Doc ...
- 控制Docker Compose的启动顺序的一个思路
起源 守护进程daemon 从守护进程的角度看Docker Compose Docker的解决方案 思路 代码 结果 起源 Docker Compose提供了一个depends_on参数. https ...
随机推荐
- Maven项目运行报错提示找不到加载主类
遇到这个问题花了几小时时间看网上的各种解决方法.试了几种都没用,最后用了这种本办法. 亲测第三条 https://blog.csdn.net/yuliantao/article/details/766 ...
- 死磕 java同步系列之zookeeper分布式锁
问题 (1)zookeeper如何实现分布式锁? (2)zookeeper分布式锁有哪些优点? (3)zookeeper分布式锁有哪些缺点? 简介 zooKeeper是一个分布式的,开放源码的分布式应 ...
- 概率与期望详解!一次精通oi中的概率期望
目录 基础概念 最大值不超过Y的期望 概率为P时期望成功次数 基础问题 拿球 随机游走 经典问题 期望线性性练习题 例题选讲 noip2016换教室 区间交 0-1边树求直径期望 球染色 区间翻转 二 ...
- CentOS7 Redis5.0.5环境搭建
CentOS7 Redis5.0.5环境搭建 1基本环境配置 CentOS Linux release 7.6.1810 (Core) redis 5.0.5 1.下载解压redis.通过wget在官 ...
- 写了那么多年 Java 代码,终于 debug 到 JVM 了
继上篇文章 原创 | 全网最新最简单的 openjdk13 代码编译 之后,我们有了自己编译后的 jdk 和 hotspot,如下图所示.接下来就来干一番事情. 搭建调试环境 1.下载 CLion 软 ...
- Web应用程序并发问题处理的一点小经验
在web应用中,一个账户,会有N多个涉及到数字的字段.比如一个账户的金额,积分等.这些字段就涉及到增减的情况.如果是在测试环境下,靠程序员或者测试手动点击.一般是发现不了问题. 一旦上到正式环境下.有 ...
- idea快捷键(mac下)
ctrl+/ 代码提示 command+o 搜索要进入的类并进入 command+shift+enter 另起一行 command+shift+u 在变成全大写与变成全小写之间切换 shift+鼠标滑 ...
- redis相关缓存知识
Redis redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorte ...
- linux分区与挂载
分区是将一个硬盘驱动器分成若干个逻辑驱动器,分区是把硬盘连续的区块当做一个独立的磁盘使用.分区表是一个硬盘分区的索引,分区的信息都会写进分区表.通常情况下,为磁盘分区通常使用fdisk,它是对基于MB ...
- Cobalt Strike之信息收集、木马钓鱼
System Profiler使用 System Profiler 模块,搜集目标的各类机器信息(操作系统版本,浏览器版本等) Attacks->web drive-by->System ...