微服务架构 - 解决Docker-Compose服务编排启动顺序问题

基于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

关注我

以你最方便的方式关注我:
微信公众号:

原文地址:https://www.cnblogs.com/atcloud/p/10593396.html

时间: 2024-10-20 03:59:37

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

Docker Compose容器编排

本章知识点概括: Docker Compose容器编排构建自动发现的Docker服务架构实现容器服务自动加入Nginx集群 **Docker Compose容器编排功能** Docker compose的前身是Fig,它是一个定义及运行多个docker容器的工具 使用Docker Compose不再需要使用shell脚本来启动容器 Docker Compose非常适合组合是同多个容器进行开发的场景 可以执行多个容器的操作 **Docker Compose容器编排** YAML是一种标记语言很直观

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

前言 前面章节,我们学习了如何构建自己的镜像文件,如何保存自己的镜像文件.大多都是一个镜像启动.当一个系统需要多个子系统进行配合时,若每个子系统也就是镜像需要一个个手动启动和停止的话,那估计实施人员也会崩溃的,而且效率也很低,维护的量也就很大了.所以,本章节就来了解下,如何利用官方提供的Compose编排工具按一定的业务规则来合理的进行容器启停工作. Compose介绍 Compose安装 二进制文件直接安装 使用pip(Python包管理工具)安装 命令补齐 Compose常用命令 build

Docker Compose服务编排

一.Docker Compose: 服务编排技术:https://github.com/docker/compose/releases 二.安装:(Linux 64位系统) 1)请求安装包:curl -L https://github.com/docker/compose/releases/download/1.24.1/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose 2)改变权限:chmod +x /u

Docker学习 Part-07(Docker Compose 服务编排)

Docker Compose 一.安装Docker Compose # Compose目前已经完全支持Linux.Mac OS和Windows,在我们安装Compose之前,需要先安装Docker.下面我 们以编译好的二进制包方式安装在Linux系统中. curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/

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

通过之前几篇Spring Cloud中几个核心组件的介绍,我们已经可以构建一个简略的(不够完善)微服务架构了.比如下图所示: alt 我们使用Spring Cloud Netflix中的Eureka实现了服务注册中心以及服务注册与发现:而服务间通过Ribbon或Feign实现服务的消费以及均衡负载:通过Spring Cloud Config实现了应用多环境的外部化配置以及版本管理.为了使得服务集群更为健壮,使用Hystrix的融断机制来避免在微服务架构中个别服务出现异常时引起的故障蔓延. 在该架

Spring Cloud构建微服务架构(一)——服务注册与发现

Spring Cloud简介 Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理.服务发现.断路器.智能路由.微代理.控制总线.全局锁.决策竞选.分布式会话和集群状态管理等操作提供了一种简单的开发方式. Spring Cloud包含了多个子项目(针对分布式系统中涉及的多个不同开源产品),比如:Spring Cloud Config.Spring Cloud Netflix.Spring Cloud CloudFoundry.Spr

Spring Cloud构建微服务架构(一)服务注册与发现

原文来源:http://blog.didispace.com/springcloud1/ Spring Cloud简介 Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中的配置管理.服务发现.断路器.智能路由.微代理.控制总线.全局锁.决策竞选.分布式会话和集群状态管理等操作提供了一种简单的开发方式. Spring Cloud包含了多个子项目(针对分布式系统中涉及的多个不同开源产品),比如:Spring Cloud Config.Sprin

构建微服务架构Spring Cloud:服务注册与发现(Eureka、Consul)

Spring Cloud简介 Spring Cloud是一个基于Spring Boot实现的云应用开发工具,它为基于JVM的云应用开发中涉及的配置管理.服务发现.断路器.智能路由.微代理.控制总线.全局锁.决策竞选.分布式会话和集群状态管理等操作提供了一种简单的开发方式. Spring Cloud包含了多个子项目(针对分布式系统中涉及的多个不同开源产品),比如:Spring Cloud Config.Spring Cloud Netflix.Spring Cloud0 CloudFoundry.

构建Docker Compose服务堆栈

1.安装了docker-compose,现在我们要使用docker-compose来运行容器栈.这个地方会有两个容器,一个容器中使用Flask搭建的简单应用,另一个容器是Redis,Flash会向redis写入数据.因此设计到容器之间的通信.之前我们讲到了,容器之间通信可以使用--link,也可以使用docker networking的方式,那这节课,我们讲解使用docker-compose来更加方便的管理多容器栈. 2.创建composeapp目录 $ cd /home/xm6f/dev/ $