记一次如何在docker容器内执行容器外的Linux命令检测MySQL和Redis进程是否挂掉
docker容器内执行容器外Linux命令检测进程是否挂掉
基础配置
首先Java项目使用docker方式部署,其次开发的同事已搭建好dockerFile和docker-compose,效果是每次会批量自动执行生成镜像并执行项目。
需求背景
想要监测MySQL和Redis的进程是否挂掉的需求,如果挂掉就需抛出异常信息给消息队列。
需求整体思路
遇到这个问题,最先想到的肯定是直接ps -ef|grep xxx或者netstat来观察项目是否挂掉,然后建立Java与Linux系统的连接使得可以定时在Java代码中执行
初版遇到的困难导图
引入正题
首先先看一下第一版设计遇到了哪些困难,我会一一介绍遇到的问题。
话不多说直接登录linux服务器,由于项目部署是通过docker的,那直接输入下面的命令是无效的。别看有返回,这个只是你执行的命令。那明明启动了,为什么查不到mysql的动向呢?
ps-ef |grep mysql
原因就是项目中MySQL也是在docker容器的,那这样就得换一种写法。如下图所示,
docker ps |grep mysql
这里不扩展判断依据,比如可以查询条数,如下所示,
docker ps |grep mysql|wc-l
那就引出我们最重要的核心问题集,如上图所示项目
就是我们的出发点
,那我们知道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
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
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;
}
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");
}
}
}
注意事项
加上定时间隔10秒,预计每30秒返回一次查询结果。如果发现某个连接断开,比如MySQL挂了,那么可以在log.error(“mysql is disconnected”)这个分支中增加Thread.sleep,使其检测到中断也不会频繁报错。
项目可扩展点
虽然我们需求只是想要监测MySQL和Redis的进程是否挂掉的需求,但只需稍加改变就可以检测它的性能(top),其他在docker中的对象如zbus等……
拓展思路
我看到网上有人用SSH-client-pool连接需要发送的服务器,然后在Java代码里生成脚本文件,再用executeCommand执行。
更多推荐
所有评论(0)