koishi-plugin-docker-control 0.0.6 → 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commands/cluster.d.ts +5 -0
- package/lib/commands/cluster.js +294 -0
- package/lib/commands/control.js +4 -4
- package/lib/commands/index.js +34 -7
- package/lib/commands/list.js +1 -1
- package/lib/commands/logs.js +1 -1
- package/lib/commands/resources.d.ts +5 -0
- package/lib/commands/resources.js +270 -0
- package/lib/commands/update.d.ts +5 -0
- package/lib/commands/update.js +179 -0
- package/lib/service/node.d.ts +127 -0
- package/lib/service/node.js +465 -0
- package/lib/utils/render.d.ts +99 -0
- package/lib/utils/render.js +421 -0
- package/package.json +1 -1
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerClusterCommands = registerClusterCommands;
|
|
4
|
+
const logger_1 = require("../utils/logger");
|
|
5
|
+
const render_1 = require("../utils/render");
|
|
6
|
+
function registerClusterCommands(ctx, getService, config) {
|
|
7
|
+
const useImageOutput = config?.imageOutput === true;
|
|
8
|
+
/**
|
|
9
|
+
* 查看集群信息
|
|
10
|
+
*/
|
|
11
|
+
ctx.command('docker.cluster [selector]', '查看 Swarm 集群信息')
|
|
12
|
+
.alias('集群', 'swarm', 'docker集群')
|
|
13
|
+
.action(async (_, selector) => {
|
|
14
|
+
logger_1.commandLogger.debug(`docker.cluster 被调用: selector=${selector}`);
|
|
15
|
+
const service = getService();
|
|
16
|
+
if (!service)
|
|
17
|
+
return '❌ 服务未初始化';
|
|
18
|
+
const nodes = service.getNodesBySelector(selector || '');
|
|
19
|
+
if (nodes.length === 0)
|
|
20
|
+
return `❌ 未找到节点: ${selector}`;
|
|
21
|
+
const lines = [];
|
|
22
|
+
for (const node of nodes) {
|
|
23
|
+
if (node.status !== 'connected') {
|
|
24
|
+
lines.push(`=== ${node.name} ===`);
|
|
25
|
+
lines.push(' (未连接)');
|
|
26
|
+
lines.push('');
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
// 检查是否在 Swarm 模式
|
|
30
|
+
const isSwarm = await node.isSwarmMode();
|
|
31
|
+
if (!isSwarm) {
|
|
32
|
+
lines.push(`=== ${node.name} ===`);
|
|
33
|
+
lines.push(' (不在 Swarm 模式)');
|
|
34
|
+
lines.push('');
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const swarmInfo = await node.getSwarmInfo();
|
|
38
|
+
if (!swarmInfo) {
|
|
39
|
+
lines.push(`=== ${node.name} ===`);
|
|
40
|
+
lines.push(' (无法获取集群信息)');
|
|
41
|
+
lines.push('');
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
lines.push(`=== ${node.name} ===`);
|
|
45
|
+
lines.push(` 集群 ID: ${swarmInfo.id}`);
|
|
46
|
+
lines.push(` 集群名称: ${swarmInfo.name}`);
|
|
47
|
+
lines.push(` 创建时间: ${swarmInfo.createdAt}`);
|
|
48
|
+
lines.push(` 更新时间: ${swarmInfo.updatedAt}`);
|
|
49
|
+
lines.push('');
|
|
50
|
+
}
|
|
51
|
+
return lines.join('\n').trim();
|
|
52
|
+
});
|
|
53
|
+
/**
|
|
54
|
+
* 查看集群节点列表
|
|
55
|
+
*/
|
|
56
|
+
ctx.command('docker.cluster.nodes [selector]', '查看 Swarm 集群节点')
|
|
57
|
+
.alias('集群节点', 'swarm节点', 'swarm节点')
|
|
58
|
+
.option('format', '-f <format> 输出格式: simple|image', { fallback: null })
|
|
59
|
+
.action(async ({ options }, selector) => {
|
|
60
|
+
logger_1.commandLogger.debug(`docker.cluster.nodes 被调用: selector=${selector}, format=${options.format}`);
|
|
61
|
+
const service = getService();
|
|
62
|
+
if (!service)
|
|
63
|
+
return '❌ 服务未初始化';
|
|
64
|
+
const nodes = service.getNodesBySelector(selector || '');
|
|
65
|
+
if (nodes.length === 0)
|
|
66
|
+
return `❌ 未找到节点: ${selector}`;
|
|
67
|
+
const format = options.format || (useImageOutput ? 'image' : 'simple');
|
|
68
|
+
// 图片渲染模式
|
|
69
|
+
if (format === 'image') {
|
|
70
|
+
if (!ctx.puppeteer)
|
|
71
|
+
return '❌ 未安装 puppeteer 插件';
|
|
72
|
+
try {
|
|
73
|
+
const results = [];
|
|
74
|
+
for (const node of nodes) {
|
|
75
|
+
if (node.status !== 'connected')
|
|
76
|
+
continue;
|
|
77
|
+
const isSwarm = await node.isSwarmMode();
|
|
78
|
+
if (!isSwarm)
|
|
79
|
+
continue;
|
|
80
|
+
const swarmNodes = await node.getSwarmNodes();
|
|
81
|
+
if (swarmNodes.length > 0) {
|
|
82
|
+
results.push({ node, swarmNodes });
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
if (results.length === 0)
|
|
86
|
+
return '❌ 未找到任何 Swarm 集群节点';
|
|
87
|
+
const html = (0, render_1.generateSwarmNodesHtml)(results, '集群节点');
|
|
88
|
+
return await (0, render_1.renderToImage)(ctx, html);
|
|
89
|
+
}
|
|
90
|
+
catch (e) {
|
|
91
|
+
logger_1.commandLogger.error(`获取集群节点失败: ${e.message}`);
|
|
92
|
+
return `❌ 错误: ${e.message}`;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// 文字模式
|
|
96
|
+
const lines = [];
|
|
97
|
+
for (const node of nodes) {
|
|
98
|
+
if (node.status !== 'connected') {
|
|
99
|
+
lines.push(`=== ${node.name} ===`);
|
|
100
|
+
lines.push(' (未连接)');
|
|
101
|
+
lines.push('');
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const isSwarm = await node.isSwarmMode();
|
|
105
|
+
if (!isSwarm) {
|
|
106
|
+
lines.push(`=== ${node.name} ===`);
|
|
107
|
+
lines.push(' (不在 Swarm 模式)');
|
|
108
|
+
lines.push('');
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
const swarmNodes = await node.getSwarmNodes();
|
|
112
|
+
lines.push(`=== ${node.name} (${swarmNodes.length} 个节点) ===`);
|
|
113
|
+
if (swarmNodes.length === 0) {
|
|
114
|
+
lines.push(' (无节点)');
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
for (const n of swarmNodes) {
|
|
118
|
+
const shortId = n.ID.slice(0, 12);
|
|
119
|
+
const isLeader = n.ManagerStatus?.Leader ? ' 👑' : '';
|
|
120
|
+
const statusIcon = n.Status.State === 'ready' ? '🟢' : '🔴';
|
|
121
|
+
lines.push(` ${isLeader}${n.Hostname} (${n.Role})`);
|
|
122
|
+
lines.push(` ID: ${shortId}`);
|
|
123
|
+
lines.push(` 状态: ${statusIcon} ${n.Status.State} | 可用性: ${n.Availability}`);
|
|
124
|
+
lines.push(` 地址: ${n.Status.Addr}`);
|
|
125
|
+
if (n.ManagerStatus?.Reachability) {
|
|
126
|
+
lines.push(` 管理可达性: ${n.ManagerStatus.Reachability}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
lines.push('');
|
|
131
|
+
}
|
|
132
|
+
return lines.join('\n').trim();
|
|
133
|
+
});
|
|
134
|
+
/**
|
|
135
|
+
* 查看集群服务列表
|
|
136
|
+
*/
|
|
137
|
+
ctx.command('docker.cluster.services [selector]', '查看 Swarm 集群服务')
|
|
138
|
+
.alias('集群服务', 'swarm服务', '集群services')
|
|
139
|
+
.option('format', '-f <format> 输出格式: simple|image', { fallback: null })
|
|
140
|
+
.action(async ({ options }, selector) => {
|
|
141
|
+
logger_1.commandLogger.debug(`docker.cluster.services 被调用: selector=${selector}, format=${options.format}`);
|
|
142
|
+
const service = getService();
|
|
143
|
+
if (!service)
|
|
144
|
+
return '❌ 服务未初始化';
|
|
145
|
+
const nodes = service.getNodesBySelector(selector || '');
|
|
146
|
+
if (nodes.length === 0)
|
|
147
|
+
return `❌ 未找到节点: ${selector}`;
|
|
148
|
+
const format = options.format || (useImageOutput ? 'image' : 'simple');
|
|
149
|
+
// 图片渲染模式
|
|
150
|
+
if (format === 'image') {
|
|
151
|
+
if (!ctx.puppeteer)
|
|
152
|
+
return '❌ 未安装 puppeteer 插件';
|
|
153
|
+
try {
|
|
154
|
+
const results = [];
|
|
155
|
+
for (const node of nodes) {
|
|
156
|
+
if (node.status !== 'connected')
|
|
157
|
+
continue;
|
|
158
|
+
const isSwarm = await node.isSwarmMode();
|
|
159
|
+
if (!isSwarm)
|
|
160
|
+
continue;
|
|
161
|
+
const services = await node.getSwarmServices();
|
|
162
|
+
if (services.length > 0) {
|
|
163
|
+
results.push({ node, services });
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (results.length === 0)
|
|
167
|
+
return '❌ 未找到任何 Swarm 服务';
|
|
168
|
+
const html = (0, render_1.generateSwarmServicesHtml)(results, '集群服务');
|
|
169
|
+
return await (0, render_1.renderToImage)(ctx, html);
|
|
170
|
+
}
|
|
171
|
+
catch (e) {
|
|
172
|
+
logger_1.commandLogger.error(`获取集群服务失败: ${e.message}`);
|
|
173
|
+
return `❌ 错误: ${e.message}`;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// 文字模式
|
|
177
|
+
const lines = [];
|
|
178
|
+
for (const node of nodes) {
|
|
179
|
+
if (node.status !== 'connected') {
|
|
180
|
+
lines.push(`=== ${node.name} ===`);
|
|
181
|
+
lines.push(' (未连接)');
|
|
182
|
+
lines.push('');
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const isSwarm = await node.isSwarmMode();
|
|
186
|
+
if (!isSwarm) {
|
|
187
|
+
lines.push(`=== ${node.name} ===`);
|
|
188
|
+
lines.push(' (不在 Swarm 模式)');
|
|
189
|
+
lines.push('');
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
const services = await node.getSwarmServices();
|
|
193
|
+
lines.push(`=== ${node.name} (${services.length} 个服务) ===`);
|
|
194
|
+
if (services.length === 0) {
|
|
195
|
+
lines.push(' (无服务)');
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
for (const s of services) {
|
|
199
|
+
const shortId = s.ID.slice(0, 12);
|
|
200
|
+
const imageName = s.Image.split('@')[0];
|
|
201
|
+
lines.push(` ${s.Name}`);
|
|
202
|
+
lines.push(` ID: ${shortId} | 副本: ${s.Replicas} | 镜像: ${imageName}`);
|
|
203
|
+
if (s.Ports !== '-') {
|
|
204
|
+
lines.push(` 端口: ${s.Ports}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
lines.push('');
|
|
209
|
+
}
|
|
210
|
+
return lines.join('\n').trim();
|
|
211
|
+
});
|
|
212
|
+
/**
|
|
213
|
+
* 查看集群服务任务
|
|
214
|
+
*/
|
|
215
|
+
ctx.command('docker.cluster.ps <selector> <service>', '查看 Swarm 服务任务')
|
|
216
|
+
.alias('集群任务', 'swarm任务', 'swarmps', '集群ps')
|
|
217
|
+
.option('format', '-f <format> 输出格式: simple|image', { fallback: null })
|
|
218
|
+
.action(async ({ options }, selector, serviceName) => {
|
|
219
|
+
logger_1.commandLogger.debug(`docker.cluster.ps 被调用: selector=${selector}, service=${serviceName}`);
|
|
220
|
+
const service = getService();
|
|
221
|
+
if (!service)
|
|
222
|
+
return '❌ 服务未初始化';
|
|
223
|
+
if (!serviceName) {
|
|
224
|
+
return '⚠️ 请指定服务名称\n例如: 集群任务 yun my-service';
|
|
225
|
+
}
|
|
226
|
+
const nodes = service.getNodesBySelector(selector || '');
|
|
227
|
+
if (nodes.length === 0)
|
|
228
|
+
return `❌ 未找到节点: ${selector}`;
|
|
229
|
+
const format = options.format || (useImageOutput ? 'image' : 'simple');
|
|
230
|
+
// 图片渲染模式
|
|
231
|
+
if (format === 'image') {
|
|
232
|
+
if (!ctx.puppeteer)
|
|
233
|
+
return '❌ 未安装 puppeteer 插件';
|
|
234
|
+
try {
|
|
235
|
+
const results = [];
|
|
236
|
+
for (const node of nodes) {
|
|
237
|
+
if (node.status !== 'connected')
|
|
238
|
+
continue;
|
|
239
|
+
const isSwarm = await node.isSwarmMode();
|
|
240
|
+
if (!isSwarm)
|
|
241
|
+
continue;
|
|
242
|
+
const tasks = await node.getSwarmTasks(serviceName);
|
|
243
|
+
if (tasks.length > 0) {
|
|
244
|
+
results.push({ node, serviceName, tasks });
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
if (results.length === 0)
|
|
248
|
+
return `❌ 未找到服务 "${serviceName}" 的任务`;
|
|
249
|
+
const html = (0, render_1.generateSwarmTasksHtml)(results, `集群任务 - ${serviceName}`);
|
|
250
|
+
return await (0, render_1.renderToImage)(ctx, html);
|
|
251
|
+
}
|
|
252
|
+
catch (e) {
|
|
253
|
+
logger_1.commandLogger.error(`获取集群任务失败: ${e.message}`);
|
|
254
|
+
return `❌ 错误: ${e.message}`;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
// 文字模式
|
|
258
|
+
const lines = [];
|
|
259
|
+
for (const node of nodes) {
|
|
260
|
+
if (node.status !== 'connected') {
|
|
261
|
+
lines.push(`=== ${node.name} ===`);
|
|
262
|
+
lines.push(' (未连接)');
|
|
263
|
+
lines.push('');
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
const isSwarm = await node.isSwarmMode();
|
|
267
|
+
if (!isSwarm) {
|
|
268
|
+
lines.push(`=== ${node.name} ===`);
|
|
269
|
+
lines.push(' (不在 Swarm 模式)');
|
|
270
|
+
lines.push('');
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
const tasks = await node.getSwarmTasks(serviceName);
|
|
274
|
+
lines.push(`=== ${node.name} (${tasks.length} 个任务) ===`);
|
|
275
|
+
if (tasks.length === 0) {
|
|
276
|
+
lines.push(` (服务 "${serviceName}" 无任务或不存在)`);
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
for (const t of tasks) {
|
|
280
|
+
const shortId = t.ID.slice(0, 12);
|
|
281
|
+
const statusIcon = t.Status.State === 'running' ? '🟢' :
|
|
282
|
+
t.Status.State === 'pending' ? '⏳' :
|
|
283
|
+
t.Status.State === 'failed' ? '❌' : '⚪';
|
|
284
|
+
lines.push(` ${statusIcon} Slot ${t.Slot} | ${t.Status.State}`);
|
|
285
|
+
lines.push(` ID: ${shortId}`);
|
|
286
|
+
lines.push(` 节点: ${t.NodeID} | 期望状态: ${t.DesiredState}`);
|
|
287
|
+
lines.push(` 时间: ${t.Status.Since}`);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
lines.push('');
|
|
291
|
+
}
|
|
292
|
+
return lines.join('\n').trim();
|
|
293
|
+
});
|
|
294
|
+
}
|
package/lib/commands/control.js
CHANGED
|
@@ -48,7 +48,7 @@ function registerControlCommands(ctx, getService, config) {
|
|
|
48
48
|
*/
|
|
49
49
|
ctx
|
|
50
50
|
.command('docker.start <selector> <container>', '启动容器')
|
|
51
|
-
.alias('
|
|
51
|
+
.alias('容器启动', '启动', '容器开启')
|
|
52
52
|
.option('async', '-a 异步执行,不等待结果', { fallback: false })
|
|
53
53
|
.action(async ({ options }, selector, container) => {
|
|
54
54
|
logger_1.commandLogger.debug(`docker.start 被调用: selector=${selector}, container=${container}`);
|
|
@@ -97,7 +97,7 @@ function registerControlCommands(ctx, getService, config) {
|
|
|
97
97
|
*/
|
|
98
98
|
ctx
|
|
99
99
|
.command('docker.stop <selector> <container>', '停止容器')
|
|
100
|
-
.alias('
|
|
100
|
+
.alias('容器停止', '停止', '容器关闭')
|
|
101
101
|
.option('async', '-a 异步执行,不等待结果', { fallback: false })
|
|
102
102
|
.action(async ({ options }, selector, container) => {
|
|
103
103
|
logger_1.commandLogger.debug(`docker.stop 被调用: selector=${selector}, container=${container}`);
|
|
@@ -140,7 +140,7 @@ function registerControlCommands(ctx, getService, config) {
|
|
|
140
140
|
*/
|
|
141
141
|
ctx
|
|
142
142
|
.command('docker.restart <selector> <container>', '重启容器')
|
|
143
|
-
.alias('
|
|
143
|
+
.alias('容器重启', '重启')
|
|
144
144
|
.option('async', '-a 异步执行,不等待结果', { fallback: false })
|
|
145
145
|
.action(async ({ options }, selector, container) => {
|
|
146
146
|
logger_1.commandLogger.debug(`docker.restart 被调用: selector=${selector}, container=${container}`);
|
|
@@ -183,7 +183,7 @@ function registerControlCommands(ctx, getService, config) {
|
|
|
183
183
|
*/
|
|
184
184
|
ctx
|
|
185
185
|
.command('docker.inspect <selector> <container>', '查看容器详情')
|
|
186
|
-
.alias('
|
|
186
|
+
.alias('容器详情', '容器检查', '检查')
|
|
187
187
|
.action(async (_, selector, container) => {
|
|
188
188
|
const service = getService();
|
|
189
189
|
if (!service) {
|
package/lib/commands/index.js
CHANGED
|
@@ -5,6 +5,9 @@ const list_1 = require("./list");
|
|
|
5
5
|
const control_1 = require("./control");
|
|
6
6
|
const logs_1 = require("./logs");
|
|
7
7
|
const compose_1 = require("./compose");
|
|
8
|
+
const resources_1 = require("./resources");
|
|
9
|
+
const update_1 = require("./update");
|
|
10
|
+
const cluster_1 = require("./cluster");
|
|
8
11
|
const render_1 = require("../utils/render");
|
|
9
12
|
/**
|
|
10
13
|
* 注册所有指令
|
|
@@ -15,6 +18,9 @@ function registerCommands(ctx, getService, config) {
|
|
|
15
18
|
(0, control_1.registerControlCommands)(ctx, getService, config);
|
|
16
19
|
(0, logs_1.registerLogsCommand)(ctx, getService, config);
|
|
17
20
|
(0, compose_1.registerComposeCommand)(ctx, getService, config);
|
|
21
|
+
(0, resources_1.registerResourceCommands)(ctx, getService, config);
|
|
22
|
+
(0, update_1.registerUpdateCommands)(ctx, getService);
|
|
23
|
+
(0, cluster_1.registerClusterCommands)(ctx, getService, config);
|
|
18
24
|
// 注册辅助指令
|
|
19
25
|
registerHelperCommands(ctx, getService, config);
|
|
20
26
|
}
|
|
@@ -26,7 +32,7 @@ function registerHelperCommands(ctx, getService, config) {
|
|
|
26
32
|
/**
|
|
27
33
|
* 查看节点列表
|
|
28
34
|
*/
|
|
29
|
-
ctx.command('docker.nodes', '查看节点').alias('
|
|
35
|
+
ctx.command('docker.nodes', '查看节点').alias('节点列表', '节点').action(async () => {
|
|
30
36
|
const service = getService();
|
|
31
37
|
if (!service) {
|
|
32
38
|
return 'Docker 服务未初始化';
|
|
@@ -58,7 +64,7 @@ function registerHelperCommands(ctx, getService, config) {
|
|
|
58
64
|
*/
|
|
59
65
|
ctx
|
|
60
66
|
.command('docker.node <selector>', '查看节点详情')
|
|
61
|
-
.alias('
|
|
67
|
+
.alias('节点详情', '查看节点')
|
|
62
68
|
.action(async (_, selector) => {
|
|
63
69
|
const service = getService();
|
|
64
70
|
if (!service) {
|
|
@@ -116,7 +122,7 @@ function registerHelperCommands(ctx, getService, config) {
|
|
|
116
122
|
*/
|
|
117
123
|
ctx
|
|
118
124
|
.command('docker.find <container>', '搜索容器')
|
|
119
|
-
.alias('
|
|
125
|
+
.alias('查找容器', '搜索', '查找')
|
|
120
126
|
.option('all', '-a 包含已停止的容器', { fallback: false })
|
|
121
127
|
.action(async ({ options }, container) => {
|
|
122
128
|
const service = getService();
|
|
@@ -145,7 +151,7 @@ function registerHelperCommands(ctx, getService, config) {
|
|
|
145
151
|
*/
|
|
146
152
|
ctx
|
|
147
153
|
.command('docker.exec <container> <cmd>', '在容器中执行命令')
|
|
148
|
-
.alias('
|
|
154
|
+
.alias('容器执行', '执行')
|
|
149
155
|
.option('node', '-n <node> 指定节点', { fallback: '' })
|
|
150
156
|
.action(async ({ options }, container, cmd) => {
|
|
151
157
|
const service = getService();
|
|
@@ -183,7 +189,7 @@ function registerHelperCommands(ctx, getService, config) {
|
|
|
183
189
|
/**
|
|
184
190
|
* 查看帮助
|
|
185
191
|
*/
|
|
186
|
-
ctx.command('docker.help', '查看帮助').alias('
|
|
192
|
+
ctx.command('docker.help', '查看帮助').alias('帮助').action(async () => {
|
|
187
193
|
return [
|
|
188
194
|
'=== Docker Control 帮助 ===',
|
|
189
195
|
'',
|
|
@@ -191,8 +197,8 @@ function registerHelperCommands(ctx, getService, config) {
|
|
|
191
197
|
' docker.nodes - 查看节点列表',
|
|
192
198
|
' docker.node <节点> - 查看节点详情',
|
|
193
199
|
'',
|
|
194
|
-
'【容器操作】
|
|
195
|
-
' docker.ls <节点> - 列出容器',
|
|
200
|
+
'【容器操作】',
|
|
201
|
+
' docker.ls <节点> - 列出容器 [-f image]',
|
|
196
202
|
' docker.start <节点> <容器> - 启动容器',
|
|
197
203
|
' docker.stop <节点> <容器> - 停止容器',
|
|
198
204
|
' docker.restart <节点> <容器> - 重启容器',
|
|
@@ -200,11 +206,32 @@ function registerHelperCommands(ctx, getService, config) {
|
|
|
200
206
|
' docker.inspect <节点> <容器> - 查看容器详情',
|
|
201
207
|
' docker.exec <节点> <容器> <命令> - 在容器内执行命令',
|
|
202
208
|
'',
|
|
209
|
+
'【更新操作】',
|
|
210
|
+
' docker.check <节点> <容器> - 检查镜像更新',
|
|
211
|
+
' docker.update <节点> <容器> [-b] - 更新容器 (-b 备份)',
|
|
212
|
+
' docker.backup <节点> <容器> [tag] - 备份容器为镜像',
|
|
213
|
+
' docker.set <节点> <容器> -e KEY=VALUE - 修改环境变量',
|
|
214
|
+
'',
|
|
215
|
+
'【集群操作】',
|
|
216
|
+
' docker.cluster [节点] - 查看 Swarm 集群信息',
|
|
217
|
+
' docker.cluster.nodes [节点] - 查看集群节点 [-f image]',
|
|
218
|
+
' docker.cluster.services [节点] - 查看集群服务 [-f image]',
|
|
219
|
+
' docker.cluster.ps <节点> <服务> - 查看服务任务 [-f image]',
|
|
220
|
+
'',
|
|
221
|
+
'【资源操作】',
|
|
222
|
+
' docker.images <节点> - 查看镜像列表 [-f image]',
|
|
223
|
+
' docker.networks <节点> - 查看网络列表 [-f image]',
|
|
224
|
+
' docker.volumes <节点> - 查看存储卷列表 [-f image]',
|
|
225
|
+
'',
|
|
203
226
|
'【节点选择器】',
|
|
204
227
|
' all - 所有节点',
|
|
205
228
|
' @标签 - 指定标签的节点',
|
|
206
229
|
' 节点ID/名称 - 指定单个节点',
|
|
207
230
|
'',
|
|
231
|
+
'【输出格式】',
|
|
232
|
+
' -f simple - 文本格式(默认)',
|
|
233
|
+
' -f image - 图片格式(需要 puppeteer 插件)',
|
|
234
|
+
'',
|
|
208
235
|
'【通知事件类型】',
|
|
209
236
|
' container.start/stop/restart/die',
|
|
210
237
|
' container.health_status',
|
package/lib/commands/list.js
CHANGED
|
@@ -8,7 +8,7 @@ function registerListCommand(ctx, getService, config) {
|
|
|
8
8
|
const useImageOutput = config?.imageOutput === true;
|
|
9
9
|
ctx
|
|
10
10
|
.command('docker.ls [selector]', '列出容器')
|
|
11
|
-
.alias('
|
|
11
|
+
.alias('容器列表', '查看容器', '列表')
|
|
12
12
|
.option('all', '-a 列出所有容器,包括已停止', { fallback: false })
|
|
13
13
|
.option('format', '-f <format> 输出格式: simple|detail|json|image', {
|
|
14
14
|
fallback: null, // 由 config.imageOutput 决定
|
package/lib/commands/logs.js
CHANGED
|
@@ -16,7 +16,7 @@ function registerLogsCommand(ctx, getService, config) {
|
|
|
16
16
|
const useImageOutput = config?.imageOutput === true;
|
|
17
17
|
ctx
|
|
18
18
|
.command('docker.logs <node> <container>', '查看容器日志')
|
|
19
|
-
.alias('
|
|
19
|
+
.alias('容器日志', '查看日志', '日志')
|
|
20
20
|
.option('lines', '-n <lines:number> 显示最后 N 行')
|
|
21
21
|
.option('timestamp', '-t 显示时间戳')
|
|
22
22
|
.option('all', '-a 显示全部(不截断)')
|