通过在运行docker容器的系统中安装ssh、sshpass服务,编写ssh连接到宿主机脚本,同时携带在宿主机中需要执行的命令,来达到在容器中获取宿主机执行命令的返回值的效果。因此这里有一个前提,必须知道宿主机的IP地址,如果在执行脚本时不知道宿主机IP地址,可以在项目中添加一个手动配置宿主机IP地址的功能,当然这是要根据功能来定的。
lz使用的镜像是centos的官方镜像,具体安装方式可以自行百度
yum -y install openssh-server
更改ssh服务配置,将PermitRootLogin的值修改为yes保存退出,如果是yes的话不需要修改
vim /etc/ssh/sshd_config
启动ssh服务
systemctl start sshd.service
设置ssh服务开机自启
systemctl enable sshd.service
查看ssh状态
systemctl status sshd.service
测试格式,输入完成后如果提示输入目标服务器密码即代表安装完成
ssh -p 22 root@IP地址
yum -y install sshpass
测试指令是否可以使用
格式:sshpass -p '宿主机密码' ssh -o StrictHostKeyChecking=no -p 22 root@宿主机IP地址 df -h
此时已经可以读取到宿主机的磁盘信息了,如果你想执行其他命令,可以把df -h换成你想在宿主机中执行的命令
vim runningContainerInfo.sh
添加内容,记得将密码改成自己的
:<<!
sshpass 携带ssh连接时的密码,避免使用ssh连接时第二次输入密码(20101111为宿主机root账号密码)
StrictHostKeyChecking=no 避免第一次连接时需要输入密码
$1 宿主机IP地址
脚本执行格式:sh /root/runningContainerInfo.sh 192.168.0.1
192.168.0.1是宿主机IP地址
!
sshpass -p '20101111' ssh -o StrictHostKeyChecking=no -p 22 root@$1 docker ps
启动脚本
sh /root/runningContainerInfo.sh 192.168.0.196
@ResponseBody
@GetMapping("/testInDockerGetHostInfo")
public ResponseResult testInDockerGetHostInfo(String command) {
// sshpass -p "20100514" ssh -p 22 [email protected] command
log.info("开始执行Linux命令:【{}】", command);
String[] split = command.split(" ");
List<String> cmd = Arrays.asList(split);
ProcessBuilder builder = new ProcessBuilder(cmd);
log.info("command命令:{}", cmd.toString());
try {
Process start = builder.start();
try {
start.waitFor();
} catch (InterruptedException e) {
e.printStackTrace();
}
BufferedReader br2 = new BufferedReader(new InputStreamReader(start.getErrorStream()));
StringBuilder buf = new StringBuilder(); // 保存输出结果流
String line;
while ((line = br2.readLine()) != null) buf.append(line); //
log.info("******获取宿主机错误信息:{}******", buf.toString());
BufferedReader or2 = new BufferedReader(new InputStreamReader(start.getInputStream()));
StringBuilder ouf = new StringBuilder(); // 保存输出结果流
String line1;
while ((line1 = or2.readLine()) != null) ouf.append(line1); //
log.info("******获取宿主机正常输出信息:{}******", ouf.toString());
} catch (IOException e) {
e.printStackTrace();
}
return new ResponseResult<String>();
}
浏览器访问信息command参数值为你现在宿主机执行的指令,lz这样写是为了测试的时候比较方便,但实际项目中不建议因为不安全,可以直接执行任意linux命令,最好将command参数去掉,接口中确定command命令
日志信息,lz的脚本命令如下,作用是获取宿主机上运行中的镜像名称为luntek/ic-platform,然后获取每一行数据的第1和28列数据,再除去容器名称为ic的列,最后只获取第一列的数据即得到运行中容器的ID,用来下一步停止正在运行的其他容器
sshpass -p '我的密码' ssh -o StrictHostKeyChecking=no -p 22 root@$1 docker ps | grep luntek/ic-platform |awk -F ' ' '{print $1,$28}'| grep -v "\" |awk -F ' ' '{print $1}'
贴一下宿主机docker ps的输出图
最后输出了容器ic01和ic058的容器ID,后面可以用来终止容器
|为管道符,可以理解成将管道符前面的返回值基础上再次操作,具体的grep和awk的指令可以参考下面链接
linux下awk命令详解
grep命令详解
解决这个问题之前也尝试过网上的很多种方法,但觉得依旧不是很方便,然后查阅很多资料后突然想到这个方法,尝试了大约一两天才完全解决这个问题,希望大家能支持一下,原创
来生还长,切勿惆怅;创作不易,随手点赞 ^_^
****************************20211120补充****************************
今天将对应的脚本移到另外的镜像中运行后发现没有反应,于是将脚本中的指令取出来单独运行发现还是同样的问题,找了一下原因,后来通过更新yum后和重新安装sshpass解决这个问题
更新yum:
sudo yum clean all
sudo yum makecache
sudo yum update -y