docker容器中获取宿主机任意信息

实现思路

通过在运行docker容器的系统中安装ssh、sshpass服务,编写ssh连接到宿主机脚本,同时携带在宿主机中需要执行的命令,来达到在容器中获取宿主机执行命令的返回值的效果。因此这里有一个前提,必须知道宿主机的IP地址,如果在执行脚本时不知道宿主机IP地址,可以在项目中添加一个手动配置宿主机IP地址的功能,当然这是要根据功能来定的。


安装ssh服务

lz使用的镜像是centos的官方镜像,具体安装方式可以自行百度

  • 安装ssh服务
 yum -y install openssh-server

docker容器中获取宿主机任意信息_第1张图片
更改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地址

在这里插入图片描述



安装sshpass

yum -y install sshpass

测试指令是否可以使用
格式:sshpass -p '宿主机密码' ssh -o StrictHostKeyChecking=no -p 22 root@宿主机IP地址 df -h
docker容器中获取宿主机任意信息_第2张图片
此时已经可以读取到宿主机的磁盘信息了,如果你想执行其他命令,可以把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 root@192.168.0.196 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命令

docker容器中获取宿主机任意信息_第3张图片
日志信息,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的输出图
docker容器中获取宿主机任意信息_第4张图片
最后输出了容器ic01和ic058的容器ID,后面可以用来终止容器
在这里插入图片描述
|为管道符,可以理解成将管道符前面的返回值基础上再次操作,具体的grep和awk的指令可以参考下面链接
linux下awk命令详解
grep命令详解


解决这个问题之前也尝试过网上的很多种方法,但觉得依旧不是很方便,然后查阅很多资料后突然想到这个方法,尝试了大约一两天才完全解决这个问题,希望大家能支持一下,原创

来生还长,切勿惆怅;创作不易,随手点赞 ^_^


****************************20211120补充****************************
今天将对应的脚本移到另外的镜像中运行后发现没有反应,于是将脚本中的指令取出来单独运行发现还是同样的问题,找了一下原因,后来通过更新yum后和重新安装sshpass解决这个问题
更新yum:

sudo yum clean all
sudo yum makecache
sudo yum update -y

你可能感兴趣的