Java获取docker容器状态

最近接到一个小需求,就是通过 java 应用程序获取服务器上 docker 容器的运行状态,所以就再网上搜了搜,发现实现此方式大体有 2 种思路。

1、通过连入系统(ssh),执行 docker ps 等命令,然后根据命令返回的字符串结果,解析出其中的状态信息。此方法的特点就是:非常暴力,如果连接其他主机,需要知晓用户名和密码。

附上相关代码 DockerPsService 类:


package com.collection.dockerdemo.service;

import com.collection.dockerdemo.bean.ContainerInfo;

import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * 通过本地执行 cmd 命令获取 docker 的一些状态参数
 */
public class DockerPsService {private DockerPsService() {}

    /**
     * 此处设置只显示容器名称和运行状态, 可以自定义扩展
     */
    private static final String FORMAT = "\"table {{.Names}}\\t{{.Status}}\"";

    /**
     * 获取容器信息
     */
    public static List getContainerInfoList() throws Exception {List containerInfoList = new ArrayList();

        // 执行 shell 命令获取容器信息
        Process process = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", "docker ps -a --format" + FORMAT}, null, null);
        InputStreamReader ir = new InputStreamReader(process.getInputStream());
        LineNumberReader input = new LineNumberReader(ir);
        String line;
        process.waitFor();

        System.out.println("********************linux 收集 docker 容器启动状态 开始 *****************************");
        int rowIndex = 0;
        while ((line = input.readLine()) != null) {System.out.println(line);
            // 表格头部信息不需要获取
            if (rowIndex != 0) {
                // 把连续的空格转成 1 个空格
                line = line.replaceAll("+", " ");
                String arr[] = line.split(" ");
                containerInfoList.add(new ContainerInfo(arr[0], arr[1]));
            }
            rowIndex++;
        }

        System.out.println("********************linux 收集 docker 容器启动状态 结束 *****************************");
        System.out.println("************************* 打印容器名称和状态 ***************************************");
        containerInfoList.forEach(item -> System.out.println(item.toString()));

        return containerInfoList;
    }

    /**
     * 检测容器是否启动
     * 如果未启动, 执行重启命令
     */
    public static void checkContainerIsRuning(String containerName) throws Exception {List containerInfoList = getContainerInfoList();
        // 非空检测
        if (containerInfoList.size() == 0 || containerName == null || containerName.trim().length() == 0) {return;}
        // 从 Java 8 引入的一个很有趣的特性是 Optional 类,Optional 类主要解决的问题是臭名昭著的空指针异常 (NullPointerException)
        Optional containerInfoOptiona = containerInfoList.stream().filter(containerInfo -> containerName.equals(containerInfo.getName())).findFirst();

        // 如果容器存在
        if (containerInfoOptiona.isPresent()) {ContainerInfo containerInfo = containerInfoOptiona.get();
            //Up 状态标识运行中
            if ("Up".equals(containerInfo.getStatus())) {System.out.printf("容器:{%s} 心跳检测正常......", containerName);
                return;
            }
            System.err.printf("容器:{%s} 运行状态为:{%s}, 正在准备重启....\n", containerName, containerInfo.getStatus());

            //docker 命令去掉 -a 只看运行中的容器
            Process process = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", "docker restart" + containerName}, null, null);
            InputStreamReader ir = new InputStreamReader(process.getInputStream());
            LineNumberReader input = new LineNumberReader(ir);
            process.waitFor();

            String line;
            // 输出执行 docker restart 命令的返回结果
            while ((line = input.readLine()) != null) {System.out.println(line);
            }
        } else {System.err.printf("容器:{%s} 不存在!", containerName);
        }
    }

}

2、通过 docker-java api 调取 docker 提供的统一接口获取容器相关状态。此方法的特点就是:需要开启 docker 对应端口,测试前务必测试下 docker 2375 端口时候开启,接口是否能够打开,一般都需要手动开启(踩坑了的地方)。

附上相关代码 DockerJavaService:


package com.collection.dockerdemo.service;

import com.collection.dockerdemo.bean.ContainerStatisticsInfo;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.command.InspectContainerResponse;
import com.github.dockerjava.api.model.HostConfig;
import com.github.dockerjava.api.model.Statistics;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.core.InvocationBuilder;
import org.apache.commons.lang3.SystemUtils;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

@Service
public class DockerJavaService {

    // 注意,务必开启 docker 的 2375 监听,否则无法连接
    private  final String localDockerHost = SystemUtils.IS_OS_WINDOWS ? "tcp://203.86.235.53:2375" : "unix:///var/run/docker.sock";


    private DockerClient dockerClient = null;

    @PostConstruct
    public  void connectDocker() {dockerClient = DockerClientBuilder.getInstance(localDockerHost).build();
        System.out.println("dockerClient:>>>>>>>>>>>>>"+dockerClient);
    }



    // docker run ...
    public String createContainer(String imageName, String containerName, HostConfig hostConfig, List cmd){CreateContainerResponse container = dockerClient.createContainerCmd(imageName)
                .withName(containerName)
                .withHostConfig(hostConfig)
                .withCmd(cmd)
                .exec();
        return container.getId();}


    public void startContainer(String containerId) {dockerClient.startContainerCmd(containerId).exec();}

    // docker stop containerId
    public void stopContainer(String containerId) {dockerClient.stopContainerCmd(containerId).exec();}


    //docker rm containerId
    public void removeContainer(String containerId) {dockerClient.removeContainerCmd(containerId).exec();}


    //docker inspect containerId
    public InspectContainerResponse.ContainerState inspectContainerStatus(String containerId) {InspectContainerResponse response = dockerClient.inspectContainerCmd(containerId).exec();
        return response.getState();}


    // docker stats --no-stream containerId
    //ContainerStatisticsInfo.java 中只有两个属性 Statistics statistics 和 boolean ok
    public ContainerStatisticsInfo containerState(String containerId) throws InterruptedException {CountDownLatch countDownLatch = new CountDownLatch(1);
        ContainerStatisticsInfo statistics = new ContainerStatisticsInfo();
        InvocationBuilder.AsyncResultCallback callback = new InvocationBuilder.AsyncResultCallback(){
            @Override
            public void onNext(Statistics object) {
                try {statistics.setStatistics(object);
                    statistics.setOk(true);
                } finally {countDownLatch.countDown();
                }
            }
        };
        dockerClient.statsCmd(containerId).withNoStream(true).exec(callback);
        countDownLatch.await(5000, TimeUnit.MILLISECONDS);
        return statistics;
    }
}

以上代码均经过实际测试,可以当作工具类或者 service 直接调用或改造,希望可能帮助到有需要的朋友!

正文完
 0
49ziy
版权声明:本站原创文章,由 49ziy 于2022-09-24发表,共计5566字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
验证码