浅析Unix domain socket是什么、Java如何使用UnixSocket调用Docker API对容器进行操作(jnr-unixsocket的使用)

一、Unix domain socket(UDS)是什么

  Unix domain socket 又叫 IPC(inter-process communication 进程间通信)socket,用于实现同一主机上的进程间通信。

  socket 原本是为网络通讯设计的,但后来在 socket 的框架上发展出一种 IPC 机制,就是 UNIX domain socket。虽然网络 socket 也可用于同一台主机的进程间通讯(通过 loopback 地址 127.0.0.1),但是 UNIX domain socket 用于 IPC 更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC 机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。

  UNIX Domain SOCKET 有 SOKCET_DGRAM(数据包套接字)和 SOCKET_STREAM(流套接字)两种模式,类似于UDP和TCP,但是面向消息的UNIX socket也是可靠的,消息既不会丢失也不会顺序错乱。

  UNIX domain socket 是全双工的,API 接口语义丰富,相比其它 IPC 机制有明显的优越性,目前已成为使用最广泛的 IPC 机制,比如 X Window 服务器和 GUI 程序之间就是通过 UNIX domain socket 通讯的。

  Unix domain socket 是 POSIX 标准中的一个组件,所以不要被名字迷惑,linux 系统也是支持它的。

  使用UNIX Domain Socket的过程和网络socket十分相似,也要先调用socket()创建一个socket文件描述符,address family指定为AF_UNIX,type可以选择SOCK_DGRAM或SOCK_STREAM,protocol参数仍然指定为0即可。

  查了一下资料,不太懂,就能知道是个什么东西,很多东西代码也是用 C 语言写的,有兴趣的自己去查下资料了解吧

二、Java如何使用UnixSocket调用Docker API对容器进行操作

1、docker-api官方文档:https://docs.docker.com/engine/api/v1.27/#operation/ContainerStart

2、使用curl调用docker-api

curl -v --unix-socket /var/run/docker.sock http:/v1.24/containers/json // -v 打印详情命令

curl -XPOST --unix-socket /var/run/docker.sock http://localhost/containers/ea05b10d8bef/stop
// stop-停止容器 start-启动容器 restart-重启容器

3、在 Docker 官网查阅 API 调用方式

  例如:查询正在运行的容器列表,HTTP 方式如下:

$ curl --unix-socket /var/run/docker.sock http:/v1.24/containers/json
[{
  "Id":"ae63e8b89a26f01f6b4b2c9a7817c31a1b6196acf560f66586fbc8809ffcd772",
  "Names":["/tender_wing"],
  "Image":"bfirsh/reticulate-splines",
  ...
}]

4、分析 API 请求的过程

  在本机执行如下命令:

curl -v --unix-socket /var/run/docker.sock http:/v1.24/containers/json

三、Java 调用 Docker API 的代码实现  ——  jnr-unixsocket

1、导入依赖

<!-- 操作docker -->
<dependency>
    <groupId>com.github.jnr</groupId>
    <artifactId>jnr-unixsocket</artifactId>
    <version>0.38.8</version>
</dependency>

2、测试代码

    public static void main(String[] args) {
        // 建立 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();
    }

3、项目代码

    private UnixSocket createUnixSocket() throws IOException {
        // 建立 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);
        return unixSocket;
    }

    @Override
    public void createContainer(String config, String containerName) throws IOException {
        // 建立 Unix Socket 连接
        UnixSocket unixSocket = createUnixSocket();
        // 调用 Docker API
        PrintWriter w = new PrintWriter(unixSocket.getOutputStream());
        w.println("POST /v1.24/containers/create?name=" + containerName + " HTTP/1.1");
        w.println("Host: http");
        w.println("Accept: */*");
        w.println("Content-Type: application/json");
        w.println("Content-Length: " + config.length());
        w.println("");
        w.write(config);
        w.flush();
        // 关闭 Output,否则会导致下面的 read 操作一直阻塞
        unixSocket.shutdownOutput();

        // 获取返回结果
        log.info("---- Create Container " + containerName + " ----");
        BufferedReader br = new BufferedReader(new InputStreamReader(unixSocket.getInputStream()));
        String line;
        while ((line = br.readLine()) != null) {
            log.info(line);
        }
        unixSocket.close();
    }

参考文章:

JAVA调用docker-api对容器进行操作:https://blog.csdn.net/nizhen8698/article/details/116725766

Java 使用 UnixSocket 调用 Docker API:https://www.cnblogs.com/anoyi/p/12249257.html

原文地址:https://www.cnblogs.com/goloving/p/15030686.html