写点什么

docker-compose 下的 java 应用启动顺序两部曲之一:问题分析

作者:程序员欣宸
  • 2022-11-07
    广东
  • 本文字数:2051 字

    阅读完需:约 7 分钟

docker-compose下的java应用启动顺序两部曲之一:问题分析

欢迎访问我的 GitHub

这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos


  • 在 docker-compose 编排多个容器时,需要按实际情况控制各容器的启动顺序,本文是《docker-compose 下的 java 应用启动顺序两部曲》的第一篇,文中会分析启动顺序的重要性,以及启动顺序有问题时会有什么样的影响,再给出临时解决的和官方推荐的两种解决方案,为下一篇的实战做好铺垫。

环境信息

  • 本次实战的环境如下:


  1. 操作系统:CentOS Linux release 7.7.1908

  2. docker:1.13.1

  3. docker-compose:1.24.1

  4. 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 版语法不再支持)


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 容器;

  • 上述配置看起来似乎是个不错的方案,在我们这里,只要给 eureka 配置要健康检查,再让 service 容器的 depends_on 参数内配置 condition: service_healthy 就可以了;

  • 不幸的是: 在 docker-compose 的第三版语法中,取消了 condition 参数! 文档地址是:https://docs.docker.com/compose/compose-file/ ,如下图红框所示:

  • 因此,condition 参数看似好用,但是从 V3 版开始的 docker-compose.yml 已经不再支持该参数,不能作为标准的解决方案;

官方推荐的方案

参考文章

  • 如果您对 docker 容器健康检查有兴趣,可以参考以下文章:


  1. 《极速体验docker容器健康》

  2. 《Java应用在docker环境配置容器健康检查》

欢迎关注 InfoQ:程序员欣宸

学习路上,你不孤单,欣宸原创一路相伴...


发布于: 2022-11-07阅读数: 39
用户头像

搜索"程序员欣宸",一起畅游Java宇宙 2018-04-19 加入

前腾讯、前阿里员工,从事Java后台工作,对Docker和Kubernetes充满热爱,所有文章均为作者原创,个人Github:https://github.com/zq2599/blog_demos

评论

发布
暂无评论
docker-compose下的java应用启动顺序两部曲之一:问题分析_Java_程序员欣宸_InfoQ写作社区