ソースを参照

使用 docker-java 实现 docker 操作

reghao 4 年 前
コミット
5b994b4ccf

+ 12 - 6
common/pom.xml

@@ -13,15 +13,21 @@
 
     <dependencies>
         <dependency>
-            <groupId>io.netty</groupId>
-            <artifactId>netty-all</artifactId>
-            <version>4.1.36.Final</version>
+            <groupId>com.github.docker-java</groupId>
+            <artifactId>docker-java</artifactId>
+            <version>3.2.12</version>
         </dependency>
 
         <dependency>
-            <groupId>com.github.jnr</groupId>
-            <artifactId>jnr-unixsocket</artifactId>
-            <version>0.38.8</version>
+            <groupId>com.github.docker-java</groupId>
+            <artifactId>docker-java-transport-httpclient5</artifactId>
+            <version>3.2.12</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.netty</groupId>
+            <artifactId>netty-all</artifactId>
+            <version>4.1.36.Final</version>
         </dependency>
 
         <dependency>

+ 6 - 202
common/src/main/java/cn/reghao/autodop/common/docker/Docker.java

@@ -1,15 +1,11 @@
 package cn.reghao.autodop.common.docker;
 
-import cn.reghao.autodop.common.docker.api.ContainerOps;
 import cn.reghao.autodop.common.docker.api.DockerApi;
-import cn.reghao.autodop.common.docker.api.ImageOps;
 import cn.reghao.autodop.common.docker.po.*;
-import cn.reghao.autodop.common.docker.po.result.Container;
 import cn.reghao.autodop.common.docker.po.result.ContainerInfo;
 import cn.reghao.autodop.common.docker.unixdomain.UnixSocketClient;
 import cn.reghao.autodop.common.docker.unixdomain.HttpClient;
 import cn.reghao.autodop.common.util.ExceptionUtil;
-import cn.reghao.jdkutil.serializer.JsonArrayDeserializer;
 import cn.reghao.jdkutil.serializer.JsonConverter;
 import cn.reghao.jdkutil.security.Base64Util;
 import cn.reghao.autodop.common.util.compression.TarFiles;
@@ -23,7 +19,6 @@ import lombok.extern.slf4j.Slf4j;
 import java.io.*;
 import java.nio.charset.StandardCharsets;
 import java.util.*;
-import java.util.stream.Collectors;
 
 /**
  * Docker 客户端
@@ -32,7 +27,7 @@ import java.util.stream.Collectors;
  * @date 2020-01-13 14:16:38
  */
 @Slf4j
-public class Docker implements ImageOps, ContainerOps, AutoCloseable {
+public class Docker implements AutoCloseable {
     private HttpClient client = new HttpClient(new UnixSocketClient());
     private TextFile textFile = new TextFile();
 
@@ -41,13 +36,6 @@ public class Docker implements ImageOps, ContainerOps, AutoCloseable {
         client.close();
     }
 
-    /**
-     * 检测 Docker 的响应
-     *
-     * @param
-     * @return
-     * @date 2021-02-08 下午2:08
-     */
     private String checkResponse(FullHttpResponse response) throws DockerException {
         if (response != null) {
             int statusCode = response.status().code();
@@ -68,27 +56,18 @@ public class Docker implements ImageOps, ContainerOps, AutoCloseable {
         }
     }
 
-    /**
-     * 根据容器名字找出容器 ID
-     *
-     * @param
-     * @return
-     * @date 2021-02-25 上午10:31
-     */
     public String getIdByName(String name) throws DockerException {
-        String wrappedName = "/" + name;
+        /*String wrappedName = "/" + name;
         List<Container> containers = ps(true);
         for (Container container : containers) {
             Set<String> names = new HashSet<>(container.getNames());
             if (names.contains(wrappedName)) {
                 return container.getId();
             }
-        }
+        }*/
         return null;
     }
 
-    /* image 操作 */
-    @Override
     public void build(String repoTag, String compileHome, String dockerfile) throws Exception {
         String uri = DockerApi.buildPost + "?t=" + repoTag;
         if (dockerfile != null) {
@@ -113,7 +92,6 @@ public class Docker implements ImageOps, ContainerOps, AutoCloseable {
         checkResponse(response);
     }
 
-    @Override
     public void push(String image) throws DockerException {
         String uri = DockerApi.pushPost.replace("{}", image);
 
@@ -137,8 +115,7 @@ public class Docker implements ImageOps, ContainerOps, AutoCloseable {
         }
     }
 
-    @Override
-    public void pull(String repoTag) throws DockerException {
+    public void pull(String repoTag) throws DockerException, InterruptedException {
         String params = "?fromImage=" + repoTag;
         String uri = DockerApi.pullPost + params;
 
@@ -150,34 +127,6 @@ public class Docker implements ImageOps, ContainerOps, AutoCloseable {
         }
     }
 
-    @Override
-    public void rmImage(String repoTag) throws DockerException {
-        String uri = DockerApi.rmImageDelete.replace("{}", repoTag);
-        try {
-            FullHttpResponse response = client.post(uri, null);
-            checkResponse(response);
-        } catch (IOException | InterruptedException e) {
-            throw new DockerException(ExceptionUtil.errorMsg(e));
-        }
-    }
-
-    @Override
-    public String inspectImage(String image) throws DockerException {
-        String uri = DockerApi.inspectImageGet.replace("{}", image);
-        try {
-            FullHttpResponse response = client.get(uri, null);
-            if (response != null) {
-                return response.content().toString(StandardCharsets.UTF_8);
-            } else {
-                throw new DockerException("请求 " + uri + " 的响应是 NULL");
-            }
-        } catch (IOException | InterruptedException e) {
-            throw new DockerException(ExceptionUtil.errorMsg(e));
-        }
-    }
-
-    /* container 操作 */
-    @Override
     public String run(String containerName, Config config) throws DockerException {
         stopAndDelete(containerName);
         //config.setImage(repoTag);
@@ -186,15 +135,8 @@ public class Docker implements ImageOps, ContainerOps, AutoCloseable {
         return containerId;
     }
 
-    /**
-     * 停止并删除容器
-     *
-     * @param
-     * @return
-     * @date 2020-03-13 下午10:16
-     */
     private void stopAndDelete(String containerName) throws DockerException {
-        List<Container> containers = ps(true);
+        /*List<Container> containers = ps(true);
         String name = "/" + containerName;
         for (Container container : containers) {
             Set<String> names = new HashSet<>(container.getNames());
@@ -206,7 +148,7 @@ public class Docker implements ImageOps, ContainerOps, AutoCloseable {
                 }
                 rmContainer(id);
             }
-        }
+        }*/
     }
 
     private String create(String containerName, Config config) throws DockerException {
@@ -230,7 +172,6 @@ public class Docker implements ImageOps, ContainerOps, AutoCloseable {
         throw new DockerException("请求 " + uri + " 创建容器失败");
     }
 
-    @Override
     public void start(String containerId) throws DockerException {
         String uri = DockerApi.startPost.replace("{}", containerId);
         try {
@@ -241,7 +182,6 @@ public class Docker implements ImageOps, ContainerOps, AutoCloseable {
         }
     }
 
-    @Override
     public void restart(String containerId) throws DockerException {
         String uri = DockerApi.restartPost.replace("{}", containerId);
         try {
@@ -252,7 +192,6 @@ public class Docker implements ImageOps, ContainerOps, AutoCloseable {
         }
     }
 
-    @Override
     public void stop(String containerId) throws DockerException {
         String uri = DockerApi.stopPost.replace("{}", containerId);
         try {
@@ -263,121 +202,6 @@ public class Docker implements ImageOps, ContainerOps, AutoCloseable {
         }
     }
 
-    @Override
-    public void rmContainer(String containerId) throws DockerException {
-        String uri = DockerApi.rmContainerDelete.replace("{}", containerId);
-        try {
-            FullHttpResponse response = client.delete(uri, null);
-            checkResponse(response);
-        } catch (IOException | InterruptedException e) {
-            throw new DockerException(ExceptionUtil.errorMsg(e));
-        }
-    }
-
-    /**
-     * 控制台日志
-     *
-     * @param
-     * @return
-     * @date 2020-05-19 上午10:26
-     */
-    @Override
-    public List<String> consoleLog(String containerId, String logLevel) throws DockerException {
-        String uri = DockerApi.logsGet.replace("{}", containerId);
-        FullHttpResponse response;
-        // TODO 处理乱码
-            /*switch (LogLevel.valueOf(logLevel)) {
-                case info:
-                    // 标准输出
-                    String params = "?stdout=true&tail=1000";
-                    response = client.get(uri + params, null);
-                    if (response != null) {
-                        String stdout = response.content().toString(StandardCharsets.UTF_8);
-                        return Arrays.asList(stdout.split(System.lineSeparator()));
-                    } else {
-                        throw new DockerException("请求 " + uri + " 的响应是 NULL");
-                    }
-                case error:
-                    // 标准错误
-                    params = "?stderr=true&tail=1000";
-                    response = client.get(uri + params, null);
-                    if (response != null) {
-                        String stderr = response.content().toString(StandardCharsets.UTF_8);
-                        return Arrays.asList(stderr.split(System.lineSeparator()));
-                    } else {
-                        throw new DockerException("请求 " + uri + " 的响应是 NULL");
-                    }
-                default:
-                    throw new DockerException("日志级别 " + logLevel + " 不存在");
-            }*/
-        return Collections.emptyList();
-    }
-
-    /**
-     * 目录中的文件列表,只返回最近 10 天的日志文件
-     * 需要保证日志文件名的格式类似于 2020-01-01.log
-     *
-     * @param
-     * @return
-     * @date 2020-05-19 上午10:26
-     */
-    public List<String> fileList(String containerId, String dirPath) throws DockerException {
-        String logDirPath = rootfs(containerId) + dirPath;
-        File logDir = new File(logDirPath);
-        if (logDir.exists()) {
-            List<String> list = Arrays.stream(Objects.requireNonNull(logDir.listFiles()))
-                    .map(File::getName)
-                    .collect(Collectors.toList());
-
-            // 只返回最近 10 天的日志文件
-            if (list.size() > 10) {
-                list.sort(Comparator.reverseOrder());
-                return list.subList(0, 10);
-            }
-            return list;
-        } else {
-            return new ArrayList<>();
-        }
-    }
-
-    /**
-     * 文件日志
-     *
-     * @param
-     * @return
-     * @date 2020-05-19 上午10:26
-     */
-    @Override
-    public List<String> fileLog(String containerId, String logPath) throws DockerException {
-        String logFilePath = rootfs(containerId) + logPath;
-        File logFile = new File(logFilePath);
-        if (!logFile.exists()) {
-            throw new DockerException(logFilePath + " 文件不存在");
-        } else if (logFile.isDirectory()) {
-            throw new DockerException(logFilePath + " 是一个文件");
-        } else {
-            try {
-                return textFile.tailRead(logFilePath, 1000);
-            } catch (IOException e) {
-                throw new DockerException(ExceptionUtil.errorMsg(e));
-            }
-        }
-    }
-
-    @Override
-    public List<Container> ps(boolean isAll) throws DockerException {
-        String uri = DockerApi.psGet + "?all=" + isAll;
-        try {
-            FullHttpResponse response = client.get(uri, null);
-            String result = checkResponse(response);
-            JsonArrayDeserializer<Container> jsonArrayDeserializer = new JsonArrayDeserializer<>();
-            return jsonArrayDeserializer.fromJsonArray(result, Container.class);
-        } catch (IOException | InterruptedException e) {
-            throw new DockerException(ExceptionUtil.errorMsg(e));
-        }
-    }
-
-    @Override
     public ContainerInfo inspectContainer(String contianerId) throws DockerException {
         String uri = DockerApi.inspectContainerGet.replace("{}", contianerId);
         try {
@@ -392,24 +216,4 @@ public class Docker implements ImageOps, ContainerOps, AutoCloseable {
             throw new DockerException(ExceptionUtil.errorMsg(e));
         }
     }
-
-    @Override
-    public String rootfs(String containerId) throws DockerException {
-        ContainerInfo containerInfo = inspectContainer(containerId);
-        // 容器停止后 mergedDir 不再存在
-        return containerInfo.getGraphDriver().getData().getMergedDir();
-    }
-
-    // TODO 待实现 docker cp
-    public void archive(String containerId) {
-        String uri = "http://v1.4.0/containers/32487cddf5d5/archive?path=/";
-        try {
-            FullHttpResponse response = client.get(uri, null);
-            if (response != null) {
-                String result =  response.content().toString(StandardCharsets.UTF_8);
-            }
-        } catch (IOException | InterruptedException e) {
-            e.printStackTrace();
-        }
-    }
 }

+ 187 - 0
common/src/main/java/cn/reghao/autodop/common/docker/DockerImpl.java

@@ -0,0 +1,187 @@
+package cn.reghao.autodop.common.docker;
+
+import cn.reghao.autodop.common.docker.api.Docker;
+import cn.reghao.autodop.common.docker.po.Config;
+import cn.reghao.autodop.common.docker.po.result.ContainerInfo;
+import cn.reghao.autodop.common.util.ExceptionUtil;
+import cn.reghao.jdkutil.text.TextFile;
+import com.github.dockerjava.api.DockerClient;
+import com.github.dockerjava.api.command.*;
+import com.github.dockerjava.api.model.Container;
+import com.github.dockerjava.api.model.HostConfig;
+import com.github.dockerjava.core.DefaultDockerClientConfig;
+import com.github.dockerjava.core.DockerClientConfig;
+import com.github.dockerjava.core.DockerClientImpl;
+import com.github.dockerjava.core.command.PushImageResultCallback;
+import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
+import com.github.dockerjava.transport.DockerHttpClient;
+
+import java.io.File;
+import java.io.IOException;
+import java.time.Duration;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Docker 客户端
+ *
+ * @author reghao
+ * @date 2021-10-27 03:41:38
+ */
+public class DockerImpl implements Docker {
+    private final DockerClient dockerClient;
+    private final TextFile textFile = new TextFile();
+
+    public DockerImpl() {
+        DockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder()
+                .withDockerHost("unix:///var/run/docker.sock")
+                .withDockerTlsVerify(false)
+                //.withDockerCertPath("/home/user/.docker")
+                //.withRegistryUsername(registryUser)
+                //.withRegistryPassword(registryPass)
+                //.withRegistryEmail(registryMail)
+                //.withRegistryUrl(registryUrl)
+                .build();
+
+        DockerHttpClient httpClient = new ApacheDockerHttpClient.Builder()
+                .dockerHost(config.getDockerHost())
+                .sslConfig(config.getSSLConfig())
+                .maxConnections(100)
+                .connectionTimeout(Duration.ofSeconds(30))
+                .responseTimeout(Duration.ofSeconds(45))
+                .build();
+
+        this.dockerClient = DockerClientImpl.getInstance(config, httpClient);
+    }
+
+    public void build(String repoTag, String compileHome, String dockerfileContent) throws DockerException {
+        String dockerfilePath = compileHome + "/Dockerfile.tmp";
+        try {
+            textFile.write(new File(dockerfilePath), dockerfileContent);
+
+            dockerClient.buildImageCmd()
+                    .withDockerfilePath(dockerfilePath)
+                    .withTags(Set.of(repoTag.split(":")[1]))
+                    .exec(new BuildImageResultCallback()).awaitCompletion();
+        } catch (IOException | InterruptedException e) {
+            throw new DockerException(ExceptionUtil.errorMsg(e));
+        }
+    }
+
+    public void push(String image) throws DockerException {
+        try {
+            dockerClient.pushImageCmd(image).exec(new PushImageResultCallback()).awaitCompletion();
+        } catch (InterruptedException e) {
+            throw new DockerException(ExceptionUtil.errorMsg(e));
+        }
+        /*dockerClient.pushImageCmd(image).exec(new ResultCallback<PushResponseItem>() {
+            @Override
+            public void onStart(Closeable closeable) {
+
+            }
+
+            @Override
+            public void onNext(PushResponseItem object) {
+                System.out.println(object.getStatus());
+            }
+
+            @Override
+            public void onError(Throwable throwable) {
+
+            }
+
+            @Override
+            public void onComplete() {
+
+            }
+
+            @Override
+            public void close() throws IOException {
+
+            }
+        }).onComplete();*/
+    }
+
+    public void pull(String image) throws DockerException {
+        try {
+            dockerClient.pullImageCmd(image).exec(new PullImageResultCallback()).awaitCompletion();
+        } catch (InterruptedException e) {
+            throw new DockerException(ExceptionUtil.errorMsg(e));
+        }
+        /*dockerClient.pullImageCmd(image).exec(new ResultCallback<PullResponseItem>() {
+            public void onStart(Closeable closeable) {
+                System.out.println("开始下载!");
+            }
+
+            public void onNext(PullResponseItem object) {
+                // 实时显示出下载信息
+                System.out.println(object.getStatus());
+            }
+
+            public void onError(Throwable throwable) {
+                throwable.printStackTrace();
+            }
+
+            public void onComplete() {
+                System.out.println("下载完毕!");
+            }
+
+            public void close() throws IOException {
+                System.out.println("下载完毕...");
+            }
+        }).onComplete();*/
+    }
+
+    public String getContainerIdByName(String containerName) throws DockerException {
+        List<Container> list = dockerClient.listContainersCmd()
+                .withNameFilter(List.of(containerName))
+                .exec();
+        if (list.size() != 1) {
+            String msg = String.format("名字为 %s 的容器不存在", containerName);
+            throw new DockerException(msg);
+        }
+
+        return list.get(0).getId();
+    }
+
+    public void stopAndDelete(String containerName) throws DockerException {
+        String containerId = getContainerIdByName(containerName);
+        dockerClient.stopContainerCmd(containerId).exec();
+        dockerClient.removeContainerCmd(containerId).exec();
+    }
+
+    public String createAndRun(String containerName, Config config) throws DockerException {
+        stopAndDelete(containerName);
+
+        HostConfig hostConfig;
+        CreateContainerResponse response = dockerClient.createContainerCmd(config.getImage())
+                .withName(containerName)
+                .withEnv(Collections.emptyList())
+                .exec();
+
+        String containerId1 = response.getId();
+        dockerClient.startContainerCmd(containerId1).exec();
+        return containerId1;
+    }
+
+    public InspectContainerResponse inspectContainer(String containerId) {
+        return dockerClient.inspectContainerCmd(containerId).exec();
+    }
+
+    public void restart(String containerId) {
+        dockerClient.stopContainerCmd(containerId).exec();
+    }
+
+    public void stop(String containerId) {
+        dockerClient.startContainerCmd(containerId).exec();
+    }
+
+    public void start(String containerId) {
+        dockerClient.restartContainerCmd(containerId).exec();
+    }
+
+    public static void main(String[] args) {
+        Docker docker = new DockerImpl();
+    }
+}

+ 0 - 76
common/src/main/java/cn/reghao/autodop/common/docker/api/ContainerOps.java

@@ -1,76 +0,0 @@
-package cn.reghao.autodop.common.docker.api;
-
-import cn.reghao.autodop.common.docker.po.Config;
-import cn.reghao.autodop.common.docker.po.result.Container;
-import cn.reghao.autodop.common.docker.DockerException;
-import cn.reghao.autodop.common.docker.po.result.ContainerInfo;
-
-import java.util.List;
-
-/**
- * docker 容器操作接口
- *
- * @author reghao
- * @date 2019-12-10 17:48:22
- */
-public interface ContainerOps {
-    /**
-     * 运行镜像
-     *
-     * @param containerName 容器运行时的名字
-     * @param config 容器运行时配置
-     * @return 容器 ID
-     * @date 2020-01-11 下午9:37
-     */
-    String run(String containerName, Config config) throws DockerException;
-
-    void start(String containerId) throws DockerException;
-    void restart(String containerId) throws DockerException;
-    void stop(String containerId) throws DockerException;
-    void rmContainer(String containerId) throws DockerException;
-
-    /**
-     * 控制台日志内容
-     *
-     * @param
-     * @return
-     * @date 2020-05-19 上午10:57
-     */
-    List<String> consoleLog(String containerId, String logLevel) throws DockerException;
-
-    /**
-     * 文件日志内容
-     *
-     * @param
-     * @return
-     * @date 2020-05-19 上午10:58
-     */
-    List<String> fileLog(String containerId, String logPath) throws DockerException;
-
-    /**
-     * 查看容器状态
-     *
-     * @param isAll 是否查看所有的容器
-     * @return 容器列表
-     * @date 2020-01-19 下午1:38
-     */
-    List<Container> ps(boolean isAll) throws DockerException;
-
-    /**
-     * 查看容器的详细信息
-     *
-     * @param containerId 容器 ID
-     * @return 容器详细信息
-     * @date 2020-01-19 下午1:39
-     */
-    ContainerInfo inspectContainer(String containerId) throws DockerException;
-
-    /**
-     * 容器映射到宿主机上的根目录
-     *
-     * @param
-     * @return
-     * @date 2020-03-13 下午10:36
-     */
-    String rootfs(String containerId) throws DockerException;
-}

+ 25 - 0
common/src/main/java/cn/reghao/autodop/common/docker/api/Docker.java

@@ -0,0 +1,25 @@
+package cn.reghao.autodop.common.docker.api;
+
+import cn.reghao.autodop.common.docker.DockerException;
+import cn.reghao.autodop.common.docker.po.Config;
+import cn.reghao.autodop.common.docker.po.result.ContainerInfo;
+import com.github.dockerjava.api.command.InspectContainerResponse;
+
+/**
+ * Docker 客户端
+ *
+ * @author reghao
+ * @date 2021-10-27 04:17:38
+ */
+public interface Docker {
+    void build(String repoTag, String compileHome, String dockerfileContent) throws DockerException;
+    void push(String image) throws DockerException;
+    void pull(String repoTag) throws DockerException;
+    String getContainerIdByName(String containerName) throws DockerException;
+    void stopAndDelete(String containerName) throws DockerException;
+    String createAndRun(String containerName, Config config) throws DockerException;
+    void start(String containerId);
+    void restart(String containerId);
+    void stop(String containerId);
+    InspectContainerResponse inspectContainer(String containerId);
+}

+ 0 - 35
common/src/main/java/cn/reghao/autodop/common/docker/api/ImageOps.java

@@ -1,35 +0,0 @@
-package cn.reghao.autodop.common.docker.api;
-
-import cn.reghao.autodop.common.docker.DockerException;
-
-/**
- * docker 镜像操作接口
- *
- * @author reghao
- * @date 2019-12-10 17:48:08
- */
-public interface ImageOps {
-    /**
-     * 构建 Docker 镜像
-     *
-     * @param image repository:tag 格式的字符串
-     * @param compileHome Dockerfile 所在目录的绝对路径
-     * @param dockerfile Dockerfile 文件(可选)
-     *
-     * @date 2019-12-10 下午6:08
-     */
-    void build(String image, String compileHome, String dockerfile) throws Exception;
-
-    void push(String image) throws DockerException, InterruptedException;
-    void pull(String image) throws DockerException;
-    void rmImage(String image) throws DockerException;
-
-    /**
-     * 获取 image 的详细信息
-     *
-     * @param image repository:tag 格式的字符串或 image id
-     * @return 镜像详细信息
-     * @date 2020-01-15 下午9:24
-     */
-    String inspectImage(String image) throws DockerException;
-}

+ 0 - 64
common/src/main/java/cn/reghao/autodop/common/docker/unixdomain/UnixDomainSocket.java

@@ -1,64 +0,0 @@
-package cn.reghao.autodop.common.docker.unixdomain;
-
-import jnr.unixsocket.UnixSocket;
-import jnr.unixsocket.UnixSocketAddress;
-import jnr.unixsocket.UnixSocketChannel;
-
-import java.io.*;
-import java.net.URI;
-import java.net.http.HttpClient;
-import java.net.http.HttpRequest;
-
-/**
- * @author reghao
- * @date 2021-10-17 15:55:46
- */
-public class UnixDomainSocket {
-    static final String sock = "/var/run/docker.sock";
-    static final File sockFile;
-    static {
-        sockFile  = new File(sock);
-    }
-
-    UnixSocket unixSocket() throws IOException {
-        UnixSocketAddress address = new UnixSocketAddress(sockFile);
-        UnixSocketChannel channel = UnixSocketChannel.open(address);
-        return new UnixSocket(channel);
-    }
-
-    public static void main(String[] args) throws IOException {
-        String uri = "http://v1.24/containers/json";
-        HttpRequest httpRequest = HttpRequest.newBuilder()
-                .GET()
-                .uri(URI.create(uri))
-                .version(HttpClient.Version.HTTP_1_1)
-                .header("Host", "http")
-                .header("Accept", "*/*")
-                .build();
-
-        // 建立 Unix Socket 连接
-        File sockFile = new File("/var/run/docker.sock");
-        UnixSocketAddress address = new UnixSocketAddress(sockFile);
-        UnixSocketChannel channel = UnixSocketChannel.open(address);
-        UnixSocket unixSocket = new UnixSocket(channel);
-
-        // 调用 Docker API
-        PrintWriter w = new PrintWriter(unixSocket.getOutputStream());
-        w.println("GET /v1.24/containers/json HTTP/1.1");
-        w.println("Host: http");
-        w.println("Accept: */*");
-        w.println("");
-        w.flush();
-        // 关闭 Output,否则会导致下面的 read 操作一直阻塞
-        unixSocket.shutdownOutput();
-
-        // 获取返回结果
-        System.out.println("---- Docker Response ----");
-        BufferedReader br = new BufferedReader(new InputStreamReader(unixSocket.getInputStream()));
-        String line;
-        while ((line = br.readLine()) != null){
-            System.out.println(line);
-        }
-        unixSocket.close();
-    }
-}