Compare commits

7 Commits

Author SHA1 Message Date
523edffc4e Merge pull request 'v1.0.2' (#6) from dev into master
Reviewed-on: #6
2026-04-13 10:28:11 +00:00
Timi
3cc371c53e v1.0.2
All checks were successful
CI / build-deploy (pull_request) Successful in 27s
CI / notify-on-failure (pull_request) Has been skipped
2026-04-13 18:27:29 +08:00
c7ddb1a8b0 Merge pull request 'v1.0.1' (#5) from dev into master
Reviewed-on: #5
2026-04-12 16:17:02 +00:00
45c9fc814a Merge pull request 'v1.0.0' (#4) from dev into master
Reviewed-on: #4
2026-04-09 05:16:04 +00:00
407dc13ac4 Merge pull request 'v1.0.0' (#3) from dev into master
Reviewed-on: #3
2026-04-09 04:09:16 +00:00
0c06bf16c2 Merge pull request 'v1.0.0' (#2) from dev into master
Reviewed-on: #2
2026-04-09 04:03:43 +00:00
1db39e77d3 Merge pull request 'v1.0.0' (#1) from dev into master
Reviewed-on: #1
2026-04-08 08:48:12 +00:00
4 changed files with 88 additions and 19 deletions

View File

@@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.imyeyu.api.modules.system.bean.DockerStatusStore;
import com.imyeyu.api.modules.system.util.DockerEngineClient;
import com.imyeyu.java.TimiJava;
import com.imyeyu.utils.Time;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
@@ -15,12 +16,13 @@ import org.springframework.scheduling.support.PeriodicTrigger;
import org.springframework.stereotype.Service;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* Docker 鐘舵€侀噰闆嗕换鍔?
* Docker 容器状态采集任务
*
* @author Codex
* @since 2026-04-06
@@ -56,20 +58,28 @@ public class DockerStatusTask implements SchedulingConfigurer {
try {
ArrayNode containers = (ArrayNode) dockerEngineClient.getJson("/containers/json", DockerEngineClient.query("all", "true"));
long now = Time.now();
synchronized (dockerStatusStore) {
Set<String> activeIds = new HashSet<>();
Map<String, DockerStatusStore.Container> collectedContainers = new LinkedHashMap<>();
for (JsonNode summary : containers) {
try {
String containerId = getAsString(summary, "Id");
activeIds.add(containerId);
DockerStatusStore.Container container = dockerStatusStore.getContainers().computeIfAbsent(containerId, key -> new DockerStatusStore.Container());
DockerStatusStore.Container container = new DockerStatusStore.Container();
if (TimiJava.isEmpty(container)) {
continue;
}
updateContainerSummary(container, summary);
updateContainerInspect(containerId, container);
updateContainerStats(containerId, container, now);
collectedContainers.put(container.getId(), container);
} catch (Exception e) {
log.error("collect docker container item error", e);
}
}
synchronized (dockerStatusStore) {
Set<String> activeIds = new HashSet<>(collectedContainers.keySet());
for (Map.Entry<String, DockerStatusStore.Container> item : collectedContainers.entrySet()) {
DockerStatusStore.Container container = dockerStatusStore.getContainers().computeIfAbsent(item.getKey(), key -> new DockerStatusStore.Container());
applyCollectedContainer(container, item.getValue());
}
dockerStatusStore.getContainers().entrySet().removeIf(item -> !activeIds.contains(item.getKey()));
}
} catch (Exception e) {
@@ -77,6 +87,39 @@ public class DockerStatusTask implements SchedulingConfigurer {
}
}
private void applyCollectedContainer(DockerStatusStore.Container target, DockerStatusStore.Container source) {
target.setId(source.getId());
target.setName(source.getName());
target.setImage(source.getImage());
target.setImageId(source.getImageId());
target.setCreatedAt(source.getCreatedAt());
target.setState(source.getState());
target.setStatus(source.getStatus());
target.setHealthStatus(source.getHealthStatus());
target.setStartedAt(source.getStartedAt());
target.setFinishedAt(source.getFinishedAt());
target.setExitCode(source.getExitCode());
target.setRestartCount(source.getRestartCount());
target.setOomKilled(source.isOomKilled());
target.setCpuPercent(source.getCpuPercent());
target.setMemoryUsageBytes(source.getMemoryUsageBytes());
target.setMemoryLimitBytes(source.getMemoryLimitBytes());
target.setMemoryPercent(source.getMemoryPercent());
target.setNetworkRxBytes(source.getNetworkRxBytes());
target.setNetworkTxBytes(source.getNetworkTxBytes());
target.setBlockReadBytes(source.getBlockReadBytes());
target.setBlockWriteBytes(source.getBlockWriteBytes());
target.setPids(source.getPids());
target.setUpdatedAt(source.getUpdatedAt());
DockerStatusStore.Point point = source.getHistory().peekLast();
if (point != null) {
target.getHistory().addLast(point);
while (historyLimit < target.getHistory().size()) {
target.getHistory().pollFirst();
}
}
}
private void updateContainerSummary(DockerStatusStore.Container container, JsonNode summary) {
container.setId(getAsString(summary, "Id"));
container.setName(trimContainerName(readFirstArrayText(summary, "Names")));
@@ -108,8 +151,8 @@ public class DockerStatusTask implements SchedulingConfigurer {
if (memoryUsageBytes != null && memoryLimitBytes != null && 0 < memoryLimitBytes) {
memoryPercent = memoryUsageBytes * 100D / memoryLimitBytes;
}
Long networkRxBytes = 0L;
Long networkTxBytes = 0L;
long networkRxBytes = 0L;
long networkTxBytes = 0L;
JsonNode networks = getAsObject(stats, "networks");
if (networks != null) {
for (Map.Entry<String, JsonNode> item : (Iterable<Map.Entry<String, JsonNode>>) networks::fields) {
@@ -118,8 +161,8 @@ public class DockerStatusTask implements SchedulingConfigurer {
networkTxBytes += getAsLong(network, "tx_bytes", 0L);
}
}
Long blockReadBytes = 0L;
Long blockWriteBytes = 0L;
long blockReadBytes = 0L;
long blockWriteBytes = 0L;
JsonNode blkioStats = getAsObject(stats, "blkio_stats");
ArrayNode ioServiceBytes = blkioStats == null ? null : getAsArray(blkioStats, "io_service_bytes_recursive");
if (ioServiceBytes != null) {
@@ -134,7 +177,6 @@ public class DockerStatusTask implements SchedulingConfigurer {
}
}
Integer pids = getNestedInteger(stats, "pids_stats", "current");
container.setCpuPercent(cpuPercent);
container.setMemoryUsageBytes(memoryUsageBytes);
container.setMemoryLimitBytes(memoryLimitBytes);

View File

@@ -28,7 +28,7 @@ public class UpsStatusTask implements SchedulingConfigurer {
private final UpsStatusClient upsStatusClient;
private final UpsStatusStore upsStatusStore;
@Value("${ups.collect-enabled:true}")
@Value("${ups.collect-enabled:false}")
private boolean collectEnabled;
@Value("${ups.collect-rate-ms:60000}")

View File

@@ -18,6 +18,7 @@ import java.net.http.HttpResponse;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Duration;
import java.util.LinkedHashMap;
@@ -73,6 +74,28 @@ public class DockerEngineClient {
}
}
/**
* 判断 Docker Engine 当前是否可访问。
*
* @return 可访问返回 true不可访问返回 false
*/
public boolean isAvailable() {
if (host.startsWith("unix://")) {
String socketPath = host.substring("unix://".length());
return Files.exists(Path.of(socketPath));
}
return true;
}
/**
* 获取 Docker Engine 主机配置。
*
* @return 主机配置字符串
*/
public String getHost() {
return host;
}
private String buildRequestPath(String path, Map<String, String> queryParams) {
StringBuilder builder = new StringBuilder();
builder.append("/");

View File

@@ -1,5 +1,9 @@
server:
shutdown: graceful
# 压缩
compression:
enable: true
min-response-size: 10KB
# 开发环境语言,激活开发配置时,多语言系统始终使用此语言环境
dev: