JAVA通过 Docker Engine REST API 远程采集目标 Docker 服务器的运行信息

Docker Inspector 技术文档

版本:1.0.0 | 基于 Java 21 | 运行时依赖:JDK 21+


一、程序概述

Docker Inspector 是一款轻量级命令行工具,通过 Docker Engine REST API 远程采集目标 Docker 服务器的运行信息,包括:

  • Docker 引擎版本信息(API 版本、引擎版本、Go 运行时版本、系统架构、内核版本)
  • 容器列表与状态(所有容器的运行状态、镜像来源、端口映射、运行时长)
  • 镜像仓库清单(本地所有镜像的标签、大小、创建时间)

程序以"采集 → 格式化输出 → 退出"的一次性模式运行,适用于运维巡检、环境快照、自动化脚本集成等场景。


二、实现原理

2.1 整体架构

复制代码
┌─────────────────────┐          HTTP GET           ┌──────────────────────┐
│   Docker Inspector  │  ─────────────────────────▶  │   Docker Engine API  │
│   (Java 21 CLI)     │  ◀─────────────────────────  │   192.168.3.145:2375 │
└─────────────────────┘        JSON 响应              └──────────────────────┘
        │
        ▼
┌─────────────────────┐
│  解析 JSON → 格式化  │
│  输出到标准输出流     │
└─────────────────────┘

程序的运行流程如下:

  1. 初始化 HTTP 客户端 --- 构建 Java 内置的 HttpClient 实例,配置连接超时
  2. 依次调用三个 REST 端点 --- /version/containers/json?all=true/images/json
  3. 解析 JSON 响应 --- 使用 Jackson 将响应体解析为 JsonNode 树结构
  4. 提取字段并格式化 --- 按固定宽度对齐输出到控制台
  5. 进程退出 --- 所有数据输出完成后,main 方法自然返回,JVM 退出

2.2 Docker Engine REST API

Docker 守护进程暴露的 HTTP API 是本程序的核心数据来源。当 Docker 以 -H tcp://0.0.0.0:2375 方式启动时,外部程序即可通过 HTTP 访问。

本程序使用了以下三个端点:

端点 HTTP 方法 返回内容
/version GET Docker 引擎版本、API 版本、Go 版本、系统架构
/containers/json?all=true GET 所有容器(含已停止)的 ID、名称、镜像、状态、端口映射
/images/json GET 本地所有镜像的 ID、标签、大小、创建时间
/version 响应示例
json 复制代码
{
  "ApiVersion": "1.49",
  "Version": "28.1.1",
  "GoVersion": "go1.23.8",
  "Arch": "amd64",
  "KernelVersion": "6.6.0-102.0.0.8.oe2509.x86_64"
}
/containers/json?all=true 响应示例
json 复制代码
[
  {
    "Id": "9d4a2bb13848...",
    "Names": ["/pascal-ming-iiot"],
    "Image": "pascal-ming-iiot:6.0.0",
    "State": "running",
    "Status": "Up 11 minutes",
    "Ports": [
      { "IP": "0.0.0.0", "PrivatePort": 39999, "PublicPort": 39999, "Type": "tcp" }
    ]
  }
]
/images/json 响应示例
json 复制代码
[
  {
    "Id": "sha256:9a50f2f8bc4c...",
    "RepoTags": ["hirun-node-red:4.1.10-22"],
    "Size": 981495831,
    "Created": 1749050563
  }
]

2.3 为什么选择直接调用 REST API 而非 docker-java SDK

维度 直接调 REST API(本方案) docker-java SDK
依赖体积 仅 Jackson(~1.8 MB) SDK + Netty(~5-8 MB)
版本兼容性 Docker API 向后兼容,极少变动 SDK 版本需与 Docker 版本对齐
学习成本 HTTP + JSON,无额外概念 需学习 SDK 抽象层
可调试性 curl 可直接复现请求 需通过 SDK 内部日志排查
适用场景 只读查询,端点有限 需要创建/删除容器等复杂操作

本程序仅做只读查询,三个端点已足够覆盖全部需求,直接调 REST API 是更轻量、更可控的选择。


三、关键技术组件

3.1 Java 21 HttpClient(java.net.http)

java 复制代码
this.httpClient = HttpClient.newBuilder()
        .connectTimeout(Duration.ofSeconds(10))
        .build();

java.net.http.HttpClient 自 JDK 11 起成为标准 API,JDK 21 中已完全成熟。相比 Apache HttpClient 或 OkHttp,它零外部依赖、与 JDK 生命周期一致、支持 HTTP/2。

本程序使用同步发送模式:

java 复制代码
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

超时设计:连接超时 10 秒、请求超时 15 秒,保证在网络不可达时程序不会无限挂起。

3.2 Jackson JSON 处理

java 复制代码
this.mapper = new ObjectMapper();

// 获取时解析
return mapper.readTree(response.body());   // 返回 JsonNode 树

// 安全读取字段
String apiVersion = version.path("ApiVersion").asText("N/A");

ObjectMapper.readTree() 将 JSON 字符串解析为树模型(JsonNode),通过 path() 方法安全导航------字段不存在时返回 MissingNode,调用 asText("N/A") 不会抛异常而是返回默认值,避免了大量的 null 检查。

3.3 Java 21 Switch 表达式(Pattern Matching)

java 复制代码
String stateColor = switch (state) {
    case "running" -> { running++; yield "🟢"; }
    case "exited"  -> { stopped++; yield "🔴"; }
    default        -> { stopped++; yield "🟡"; }
};

Java 21 的 switch 表达式支持箭头语法和代码块,允许在分支中执行副作用(running++)并用 yield 返回值,比传统的 switch-case-break 结构更紧凑、更不容易遗漏 break。

3.4 格式化输出

java 复制代码
System.out.printf("║  服务器地址    : %-35s ║%n", DOCKER_HOST + ":" + DOCKER_PORT);

%-35s 表示左对齐、占 35 字符宽度,配合 Unicode 制表符(╔═╗║╚)构建固定宽度的表格边框。

辅助方法:

  • truncate(s, max) --- 超长字符串截断并附加 ..,防止输出溢出
  • formatSize(bytes) --- 字节自动换算为 KB/MB/GB
  • formatTimestamp(unixSeconds) --- Unix 时间戳转本地时间格式

四、程序结构

4.1 文件布局

复制代码
docker-java/
├── pom.xml                                        # Maven 构建配置
├── docs/
│   └── README.md                                  # 本文档
├── src/
│   └── main/
│       └── java/
│           └── com/
│               └── example/
│                   └── DockerInspector.java        # 主类,单文件约 200 行
└── target/
    └── docker-inspector-1.0.0.jar                  # 打包产物(含全部依赖)

4.2 类结构(DockerInspector.java)

复制代码
DockerInspector
├── 常量
│   ├── DOCKER_HOST / DOCKER_PORT / BASE_URL     # 目标服务器地址
│
├── 成员
│   ├── HttpClient httpClient                     # HTTP 客户端(线程安全)
│   └── ObjectMapper mapper                       # JSON 解析器(线程安全)
│
├── 核心方法
│   ├── get(String path) → JsonNode              # 通用 GET 请求封装
│   ├── printDockerVersion()                      # 输出引擎版本信息
│   ├── printContainers()                         # 输出容器列表与状态
│   └── printImages()                             # 输出镜像清单
│
├── 工具方法
│   ├── truncate(String, int) → String           # 字符串截断
│   ├── formatSize(long) → String                # 文件大小格式化
│   └── formatTimestamp(long) → String           # 时间戳格式化
│
└── main(String[] args)                           # 入口,依次调用三个 print 方法

4.3 执行流程

复制代码
main()
  │
  ├── new DockerInspector()
  │     ├── HttpClient.newBuilder().connectTimeout(10s).build()
  │     └── new ObjectMapper()
  │
  ├── printDockerVersion()
  │     ├── GET /version
  │     ├── mapper.readTree(body)
  │     └── printf 输出表格
  │
  ├── printContainers()
  │     ├── GET /containers/json?all=true
  │     ├── mapper.readTree(body)
  │     ├── 遍历数组 → 提取 Id/Name/Image/State/Ports
  │     ├── 统计 running / stopped 数量
  │     └── printf 逐行输出
  │
  ├── printImages()
  │     ├── GET /images/json
  │     ├── mapper.readTree(body)
  │     ├── 遍历数组 → 提取 Id/RepoTags/Size/Created
  │     └── printf 逐行输出
  │
  └── 输出 "信息收集完毕,程序退出。"

4.4 Maven 构建配置要点

xml 复制代码
<!-- pom.xml 关键配置 -->
<properties>
    <maven.compiler.source>21</maven.compiler.source>   <!-- 编译目标 JDK 21 -->
    <maven.compiler.target>21</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>       <!-- 唯一外部依赖 -->
    </dependency>
</dependencies>

<plugins>
    <plugin>
        <artifactId>maven-shade-plugin</artifactId>     <!-- 将依赖打入单一 jar -->
    </plugin>
</plugins>

maven-shade-plugin 将 Jackson 的三个 jar(core / annotations / databind)合并进最终的 docker-inspector-1.0.0.jar,实现"一个 jar 走天下",目标机器只需有 JDK 21 即可直接运行。


五、运行方式

5.1 编译打包

bash 复制代码
mvn clean package -q

产出物:target/docker-inspector-1.0.0.jar(含全部依赖,约 2.1 MB)

5.2 执行

bash 复制代码
# Linux / macOS
java -jar target/docker-inspector-1.0.0.jar

# Windows(解决中文乱码)
java -Dfile.encoding=UTF-8 -Dstdout.encoding=UTF-8 -Dstderr.encoding=UTF-8 \
     -jar target/docker-inspector-1.0.0.jar

5.3 Docker 服务器前置条件

目标 Docker 守护进程需开启 TCP 监听:

bash 复制代码
# /etc/docker/daemon.json 或 dockerd 启动参数
{
  "hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2375"]
}

或在 systemd 服务文件中设置:

ini 复制代码
# /etc/systemd/system/docker.service.d/override.conf
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// -H tcp://0.0.0.0:2375

安全提示:2375 端口无认证,生产环境建议启用 TLS(2376 端口)并配置客户端证书。


六、扩展功能展望

6.1 命令行参数化

当前服务器地址硬编码在常量中,可改为命令行参数或配置文件驱动:

bash 复制代码
# 目标形态
docker-inspector --host 192.168.3.145 --port 2375
docker-inspector --config servers.yml

技术方案:引入 picocli(零依赖、注解驱动的命令行解析框架)替代硬编码常量,支持 --host--port--output json 等参数。

6.2 多服务器批量巡检

支持同时连接多台 Docker 服务器,并发采集后汇总输出:

bash 复制代码
docker-inspector --host 192.168.3.145,192.168.3.146,192.168.3.147 --port 2375

技术方案:使用 HttpClient + CompletableFuture 并发请求,或结构化并发(Java 21 StructuredTaskScope)等待全部完成后再格式化输出。

6.3 输出格式扩展

当前仅支持控制台文本输出,可扩展为多格式:

格式 适用场景 实现方式
JSON 程序间集成、管道传参 Jackson ObjectMapper.writeValueAsString()
CSV 导入 Excel / 数据分析 简单字符串拼接或 OpenCSV
HTML 邮件报告 模板引擎(FreeMarker / Thymeleaf)
YAML 配置管理集成 Jackson YAML 模块

6.4 TLS 安全连接

生产环境的 Docker API 通常需要客户端证书认证:

bash 复制代码
docker-inspector --host 192.168.3.145 --port 2376 \
                 --tls \
                 --cert client-cert.pem \
                 --key client-key.pem \
                 --ca ca.pem

技术方案:通过 SSLContext 加载 PEM 证书,注入 HttpClient.newBuilder().sslContext(ctx),将连接模式从 HTTP 升级为 HTTPS + mTLS。

6.5 容器日志与健康检查

在版本/容器/镜像基础上,增加更多数据维度:

  • 容器日志尾部GET /containers/{id}/logs?tail=50,快速查看最近日志
  • 容器资源统计GET /containers/{id}/stats?stream=false,CPU / 内存 / 网络实时数据
  • 健康检查状态 :从容器详情的 State.Health 字段读取,识别 unhealthy 容器
  • 容器环境变量GET /containers/{id}/jsonConfig.Env,用于配置审计(需脱敏)

6.6 持续监控模式

将一次性采集改为定时轮询,实现简易监控:

bash 复制代码
docker-inspector --host 192.168.3.145 --watch --interval 30s

技术方案:ScheduledExecutorService 定时触发采集,终端清屏重绘;或将数据推送至 Prometheus Pushgateway / InfluxDB,接入 Grafana 展示。

6.7 Docker Compose / Stack 服务分组

当前输出是扁平的容器列表,可按 Compose 项目或 Swarm Stack 分组展示:

复制代码
[project: hirun-iiot]
  ├── pascal-ming-iiot:6.0.0     running   39999/tcp
  ├── pascal-ming-dbsync:6.0.0         exited
  ├── pascal-ming-xxljob:6.0.0         running   30020/tcp
  └── nodered:4.1.10-22          running   1880/tcp

[project: monitoring]
  ├── prometheus:v2.54.1         running   29090/tcp
  ├── grafana:11.2.0             running   23000/tcp
  └── node-exporter:v1.8.2       running   29100/tcp

实现方式:从容器 Labels 中读取 com.docker.compose.project 进行分组。

6.8 告警与通知

增加阈值检测,发现异常自动通知:

  • 容器处于 exited / restarting 状态超过 N 分钟
  • 镜像版本落后于 Registry 最新版本
  • 磁盘占用超过阈值(通过 Docker system df)

通知渠道:企业微信 / 钉钉 / 邮件 / Webhook。


七、已知限制

限制项 说明
仅支持 HTTP 当前不支持 HTTPS/TLS,生产环境需启用 TLS 时需改造
无认证机制 2375 端口无认证,程序也未实现 Basic Auth 或 Token 认证
中文 Windows 终端乱码 Windows 默认 GBK 编码,需加 -Dfile.encoding=UTF-8 运行参数
无交互能力 纯输出程序,不支持过滤、搜索、选择性查看
单一服务器 当前仅支持连接一台服务器,不支持批量

八、依赖清单

依赖 版本 用途 许可证
Jackson Databind 2.17.2 JSON 解析 Apache 2.0
Jackson Core 2.17.2 JSON 底层引擎 Apache 2.0
Jackson Annotations 2.17.2 JSON 注解支持 Apache 2.0
Java HttpClient (JDK) 21 HTTP 通信 Oracle BCL

所有 Jackson 依赖通过 Maven 传递依赖自动引入,无需手动声明。