• 记一次如何在docker容器内执行容器外的Linux命令检测MySQL和Redis进程是否挂掉


    基础配置

    首先Java项目使用docker方式部署,其次开发的同事已搭建好dockerFile和docker-compose,效果是每次会批量自动执行生成镜像并执行项目。

    需求背景

    想要监测MySQL和Redis的进程是否挂掉的需求,如果挂掉就需抛出异常信息给消息队列。

    需求整体思路

    遇到这个问题,最先想到的肯定是直接ps -ef|grep xxx或者netstat来观察项目是否挂掉,然后建立Java与Linux系统的连接使得可以定时在Java代码中执行

    初版遇到的困难导图

    请添加图片描述

    引入正题

    首先先看一下第一版设计遇到了哪些困难,我会一一介绍遇到的问题。
    话不多说直接登录linux服务器,由于项目部署是通过docker的,那直接输入下面的命令是无效的。别看有返回,这个只是你执行的命令。那明明启动了,为什么查不到mysql的动向呢?

    ps-ef |grep mysql
    
    • 1

    在这里插入图片描述
    原因就是项目中MySQL也是在docker容器的,那这样就得换一种写法。如下图所示,

    docker ps |grep mysql
    
    • 1

    在这里插入图片描述
    这里不扩展判断依据,比如可以查询条数,如下所示,

    docker ps |grep mysql|wc-l
    
    • 1

    那就引出我们最重要的核心问题集,如上图所示项目就是我们的出发点,那我们知道docker容器直接无法直接通信,那我们该如何访问呢?那我们可以借助Linux容器来帮我们解决。归纳出下面两个问题,
    第一个问题:如何解决在容器内使用容器外的脚本问题(难)
    第二个问题:如何在Java里面使用执行Linux的cmd指令(难)
    第二个问题:如何定时任务(易)

    解决方案

    1、首先容器内访问容器外该如何解决呢?
    在这里插入图片描述
    a.在resources下添加mysql.exp与redis.exp脚本
    在这里插入图片描述
    b.在dockerFile中添加如下内容

    RUN apt-get update && apt-get -y install expect vim lrzsz
    COPY ./target/classes/mysql.exp mysql.exp
    COPY ./target/classes/redis.exp redis.exp
    
    • 1
    • 2
    • 3

    c.我们以mysql.exp为例,其对应在命令行输入的格式应为expect mysql.exp + host + port + passwd,其中host例如op@192.168.1.1,port例如22,passwd例如123456

    #!/usr/bin/expect -f
    #ssh连接服务器
    set host [ lindex $argv 0 ]
    set port [ lindex $argv 1 ]
    set passwd [ lindex $argv 2 ]
    spawn ssh -o "StrictHostKeyChecking no" $host -p $port
    #等待带有password字样,并输入密码
    expect "*password*" {send "$passwd\r"}
    #执行命令
    expect "*op@dev-test*" {
        send "cd\r"   
        send "docker ps|grep mysql\r"
    }
    #退出
    expect eof
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2、Java里面使用执行Linux的cmd指令,这个可以直接放到Java代码中

        public static String exeCmd(String commandStr) {
    
            String result = null;
            try {
                String[] cmd = new String[]{"/bin/sh", "-c", commandStr};
                Process ps = Runtime.getRuntime().exec(cmd);
                BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream()));
                StringBuffer sb = new StringBuffer();
                String line;
                while ((line = br.readLine()) != null) {
                    //执行结果加上回车
                    sb.append(line).append("\n");
                }
                result = sb.toString();
                System.out.println(result);
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            return result;
    
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    3、定时任务实现,这一块儿用伪代码表示

    @Component
    @Slf4j
    public class MonitorByLinuxJob {
        @Value("${working.mysql.host}")
        private String host;
        @Value("${working.mysql.port}")
        private String port;
        @Value("${working.mysql.passwd}")
        private String passwd;
    
        @Scheduled(fixedDelayString = "${working.fixedDelay:5000}")
        public void reportCurrentTime() throws InterruptedException {
            if (ObjectUtils.isNotEmpty(exeCmd("expect mysql.exp" + " " + host + " " + port + " " + passwd))) {
                log.info("mysql is OK");
            } else {
                log.error("mysql is disconnected");
            }
        }  
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    注意事项

    加上定时间隔10秒,预计每30秒返回一次查询结果。如果发现某个连接断开,比如MySQL挂了,那么可以在log.error(“mysql is disconnected”)这个分支中增加Thread.sleep,使其检测到中断也不会频繁报错。

    项目可扩展点

    虽然我们需求只是想要监测MySQL和Redis的进程是否挂掉的需求,但只需稍加改变就可以检测它的性能(top),其他在docker中的对象如zbus等……

    拓展思路

    我看到网上有人用SSH-client-pool连接需要发送的服务器,然后在Java代码里生成脚本文件,再用executeCommand执行。

  • 相关阅读:
    【微服务】spring 控制bean加载顺序使用详解
    will insert additional declarations immediately before the previous line.#endif
    设计模式-状态模式
    算法基础:贪心策略
    Linux发展历程
    Unix系统获取文件长度相关操作
    SAP出现库存数量为0金额不为0的调整方法
    面试Python一定要记住的超基础知识点【速记】
    索引和切片--numpy
    构建私有的 CA 机构(拓展)
  • 原文地址:https://blog.csdn.net/weixin_43914278/article/details/127650583