diff --git a/web-api/src/main/java/com/jeesite/modules/utils/DockerUtil.java b/web-api/src/main/java/com/jeesite/modules/utils/DockerUtil.java
index 99726c7..316b7f9 100644
--- a/web-api/src/main/java/com/jeesite/modules/utils/DockerUtil.java
+++ b/web-api/src/main/java/com/jeesite/modules/utils/DockerUtil.java
@@ -5,93 +5,32 @@ import com.jeesite.modules.apps.Module.ContainerInfo;
import com.jeesite.modules.apps.Module.DockerResult;
import com.jeesite.modules.biz.entity.MySftpAccounts;
-import java.io.*;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
-/**
- * Docker 容器管理工具
- *
- * 通过 SSH 连接主机,基于 MySftpAccounts 凭证执行 docker 命令。
- * 支持密码认证和私钥认证。
- */
public class DockerUtil {
private static final int SSH_TIMEOUT = 30000;
- public static DockerResult start(MySftpAccounts accounts, String containerId) {
- return exec(accounts, "docker start " + containerId);
- }
-
- public static DockerResult stop(MySftpAccounts accounts, String containerId) {
- return exec(accounts, "docker stop " + containerId);
- }
-
- public static DockerResult restart(MySftpAccounts accounts, String containerId) {
- return exec(accounts, "docker restart " + containerId);
- }
-
- public static DockerResult getLogs(MySftpAccounts accounts, String containerId,
- int tail, boolean timestamps) {
- String cmd = "docker logs" + (timestamps ? " -t" : "")
- + " --tail " + tail + " " + containerId;
- return exec(accounts, cmd);
- }
-
- public static DockerResult list(MySftpAccounts accounts, boolean all) {
- return exec(accounts, all ? "docker ps -a" : "docker ps");
- }
-
- public static DockerResult inspect(MySftpAccounts accounts, String containerId) {
- return exec(accounts, "docker inspect " + containerId);
- }
-
- public static List listContainers(MySftpAccounts accounts, boolean all) {
- List list = new ArrayList<>();
- String cmd = (all ? "docker ps -a" : "docker ps")
- + " --format \"{{.ID}}|{{.Image}}|{{.Command}}|{{.CreatedAt}}|{{.Status}}|{{.Ports}}|{{.Names}}\"";
- DockerResult r = exec(accounts, cmd);
- if (!r.isSuccess()) {
- return new ArrayList<>();
- }
- for (String line : r.getOutput().split("\n")) {
- if (line.trim().isEmpty()) continue;
- String[] p = line.split("\\|");
- if (p.length < 2) continue;
- ContainerInfo info = new ContainerInfo();
- info.setContainerId(p[0].trim());
- info.setImage(p[1].trim());
- info.setCommand(p.length > 2 ? p[2].trim() : "");
- info.setCreated(p.length > 3 ? p[3].trim() : "");
- info.setStatus(p.length > 4 ? p[4].trim() : "");
- info.setPorts(p.length > 5 ? p[5].trim() : "");
- info.setNames(p.length > 6 ? p[6].trim() : "");
- info.setAccountId(accounts.getAccountId());
- list.add(info);
- }
- return list;
- }
-
- public static DockerResult exec(MySftpAccounts accounts, String command) {
+ private static String runCommand(MySftpAccounts account, String cmd) {
JSch jsch = new JSch();
Session session = null;
ChannelExec channel = null;
+
try {
- int port = accounts.getHostPort() != null ? accounts.getHostPort() : 22;
- session = jsch.getSession(accounts.getUsername(), accounts.getHostIp(), port);
+ int port = account.getHostPort() == null ? 22 : account.getHostPort();
+ session = jsch.getSession(account.getUsername(), account.getHostIp(), port);
session.setTimeout(SSH_TIMEOUT);
- if ("key".equalsIgnoreCase(accounts.getAuthType())
- && accounts.getPrivateKey() != null && !accounts.getPrivateKey().isEmpty()) {
- jsch.addIdentity("temp",
- accounts.getPrivateKey().getBytes(StandardCharsets.UTF_8),
- null, null);
- } else if (accounts.getPassword() != null && !accounts.getPassword().isEmpty()) {
- session.setPassword(accounts.getPassword());
+ // 认证
+ if ("key".equalsIgnoreCase(account.getAuthType()) && account.getPrivateKey() != null) {
+ jsch.addIdentity("temp", account.getPrivateKey().getBytes(StandardCharsets.UTF_8), null, null);
} else {
- return DockerResult.fail("SSH 认证信息不完整:缺少密码或私钥");
+ session.setPassword(account.getPassword());
}
Hashtable config = new Hashtable<>();
@@ -99,46 +38,85 @@ public class DockerUtil {
session.setConfig(config);
session.connect(SSH_TIMEOUT);
+ // 执行命令
channel = (ChannelExec) session.openChannel("exec");
- String finalCmd = (accounts.getRootPath() != null && !accounts.getRootPath().isEmpty())
- ? "cd " + accounts.getRootPath() + " && " + command
- : command;
- channel.setCommand(finalCmd);
- channel.setInputStream(null);
+ String command = account.getRootPath() != null && !account.getRootPath().isEmpty()
+ ? "cd " + account.getRootPath() + " && " + cmd
+ : cmd;
+ channel.setCommand(command);
InputStream in = channel.getInputStream();
- ByteArrayOutputStream errOut = new ByteArrayOutputStream();
- channel.setExtOutputStream(errOut);
-
channel.connect();
- StringBuilder outBuilder = new StringBuilder();
- if (in != null) {
- byte[] buf = new byte[4096];
- int n;
- while ((n = in.read(buf)) != -1) {
- outBuilder.append(new String(buf, 0, n, StandardCharsets.UTF_8));
- }
+ // 读取输出
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ byte[] buf = new byte[4096];
+ int len;
+ while ((len = in.read(buf)) != -1) {
+ out.write(buf, 0, len);
}
- String stdout = outBuilder.toString().trim();
- String stderr = errOut.toString(StandardCharsets.UTF_8).trim();
- int exitCode = channel.getExitStatus();
+ return out.toString(StandardCharsets.UTF_8).trim();
- if (exitCode == 0) {
- return DockerResult.ok(stdout);
- } else {
- return DockerResult.fail("命令执行失败,退出码: " + exitCode,
- stderr.isEmpty() ? stdout : stderr);
- }
-
- } catch (JSchException e) {
- return DockerResult.fail("SSH 连接失败: " + e.getMessage());
- } catch (IOException e) {
- return DockerResult.fail("IO 异常: " + e.getMessage());
+ } catch (Exception e) {
+ return null;
} finally {
- if (channel != null && channel.isConnected()) channel.disconnect();
- if (session != null && session.isConnected()) session.disconnect();
+ if (channel != null) channel.disconnect();
+ if (session != null) session.disconnect();
}
}
-}
+
+ public static List listContainers(MySftpAccounts accounts, boolean all) {
+ List list = new ArrayList<>();
+ String cmd = (all ? "docker ps -a" : "docker ps")
+ + " --format \"{{.ID}}|{{.Image}}|{{.Command}}|{{.CreatedAt}}|{{.Status}}|{{.Ports}}|{{.Names}}\"";
+
+ String output = runCommand(accounts, cmd);
+ if (output == null || output.isBlank()) return list;
+ for (String line : output.split("\\R")) {
+ if (line.isBlank()) continue;
+ String[] arr = line.split("\\|");
+ ContainerInfo info = new ContainerInfo();
+ info.setContainerId(arr.length > 0 ? arr[0].trim() : "");
+ info.setImage(arr.length > 1 ? arr[1].trim() : "");
+ info.setCommand(arr.length > 2 ? arr[2].trim() : "");
+ info.setCreated(arr.length > 3 ? arr[3].trim() : "");
+ info.setStatus(arr.length > 4 ? arr[4].trim() : "");
+ info.setPorts(arr.length > 5 ? arr[5].trim() : "");
+ info.setNames(arr.length > 6 ? arr[6].trim() : "");
+ info.setAccountId(accounts.getAccountId());
+ list.add(info);
+ }
+ return list;
+ }
+ public static DockerResult start(MySftpAccounts accounts, String containerId) {
+ String res = runCommand(accounts, "docker start " + containerId);
+ return res != null ? DockerResult.ok(res) : DockerResult.fail("执行失败");
+ }
+
+ public static DockerResult stop(MySftpAccounts accounts, String containerId) {
+ String res = runCommand(accounts, "docker stop " + containerId);
+ return res != null ? DockerResult.ok(res) : DockerResult.fail("执行失败");
+ }
+
+ public static DockerResult restart(MySftpAccounts accounts, String containerId) {
+ String res = runCommand(accounts, "docker restart " + containerId);
+ return res != null ? DockerResult.ok(res) : DockerResult.fail("执行失败");
+ }
+
+ public static DockerResult getLogs(MySftpAccounts accounts, String containerId, int tail, boolean timestamps) {
+ String cmd = "docker logs " + (timestamps ? "-t " : "") + "--tail " + tail + " " + containerId;
+ String res = runCommand(accounts, cmd);
+ return res != null ? DockerResult.ok(res) : DockerResult.fail("获取日志失败");
+ }
+
+ public static DockerResult list(MySftpAccounts accounts, boolean all) {
+ String res = runCommand(accounts, all ? "docker ps -a" : "docker ps");
+ return res != null ? DockerResult.ok(res) : DockerResult.fail("获取列表失败");
+ }
+
+ public static DockerResult inspect(MySftpAccounts accounts, String containerId) {
+ String res = runCommand(accounts, "docker inspect " + containerId);
+ return res != null ? DockerResult.ok(res) : DockerResult.fail("查询详情失败");
+ }
+}
\ No newline at end of file
diff --git a/web-api/src/main/resources/config/application.yml b/web-api/src/main/resources/config/application.yml
index d5c540c..3edd8e6 100644
--- a/web-api/src/main/resources/config/application.yml
+++ b/web-api/src/main/resources/config/application.yml
@@ -36,12 +36,12 @@ server:
#========= Database settings ==========#
#======================================#
-jdbc:
+jdbc:
type: mysql
driver: com.mysql.cj.jdbc.Driver
- url: jdbc:mysql://192.168.31.182:13306/system?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
- username: dream
- password: info_dream
+ url: jdbc:mysql://127.0.0.1:13306/my_app?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true
+ username: root
+ password: root_dream
testSql: SELECT 1
encrypt:
username: false
@@ -156,7 +156,7 @@ web:
addPathPatterns: >
${frontPath}/**
excludePathPatterns: ~
- core:
+ core:
enabled: true
# 在线API文档
diff --git a/web-vue/packages/biz/views/biz/myDocker/index.vue b/web-vue/packages/biz/views/biz/myDocker/index.vue
index 367db2d..7ed20bf 100644
--- a/web-vue/packages/biz/views/biz/myDocker/index.vue
+++ b/web-vue/packages/biz/views/biz/myDocker/index.vue
@@ -1,21 +1,347 @@
+
+
+
+ 主机列表
+ {{ serverOptions.length }} 台
+
+
+
+
+
+
+
+
+
+
+
+ 主机详情
+ {{ currentServer?.hostName || '-' }}
+
+
+
+
+
+
{{ currentServer.hostName }}
+
{{ currentServer.hostIp }}:{{ currentServer.hostPort }}
+
账号:{{ currentServer.username }}
+
+
+
{{ getServerStatus(currentServer).label }}
+
+
+
+
+
+
+
+
账号标识
+
{{ currentServer.accountId }}
+
+
+
容器总数
+
{{ currentContainers.length }}
+
+
+
运行中
+
{{ runningCount }}
+
+
+
+
+
+
+
+ 容器列表
+ {{ currentContainers.length }} 个容器
+
+
+
+
+
+
+
+
+
+
+ {{ row.status }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
{{ resultContent || '-' }}
+
+
+
+
+