forked from mirror/MCSM-Daemon
Merge pull request #10 from RimuruChan/feature/docker-more-options
Feature/docker more options
This commit is contained in:
commit
32188c8e96
3
.gitignore
vendored
3
.gitignore
vendored
@ -94,3 +94,6 @@ typings/
|
||||
.env
|
||||
|
||||
Note.txt
|
||||
|
||||
# IntelliJ IDEA project files
|
||||
/.idea/*
|
||||
|
30
src/app.ts
30
src/app.ts
@ -20,6 +20,7 @@
|
||||
*/
|
||||
|
||||
import { getVersion, initVersionManager } from "./service/version";
|
||||
|
||||
initVersionManager();
|
||||
const VERSION = getVersion();
|
||||
|
||||
@ -44,6 +45,7 @@ import http from "http";
|
||||
import { Server, Socket } from "socket.io";
|
||||
|
||||
import logger from "./service/log";
|
||||
|
||||
logger.info(`欢迎使用 MCSManager 守护进程`);
|
||||
|
||||
import { globalConfiguration } from "./entity/config";
|
||||
@ -104,7 +106,7 @@ io.on("connection", (socket: Socket) => {
|
||||
});
|
||||
|
||||
// Error report monitoring
|
||||
process.on("uncaughtException", function (err) {
|
||||
process.on("uncaughtException", function(err) {
|
||||
logger.error(`错误报告 (uncaughtException):`, err);
|
||||
});
|
||||
|
||||
@ -125,16 +127,18 @@ console.log("");
|
||||
// 装载 终端界面UI
|
||||
import "./service/ui";
|
||||
|
||||
process.on("SIGINT", function () {
|
||||
try {
|
||||
console.log("\n\n\n\n");
|
||||
logger.warn("SIGINT close process signal detected.");
|
||||
InstanceSubsystem.exit();
|
||||
logger.info("The data is saved, thanks for using, goodbye!");
|
||||
logger.info("Closed.");
|
||||
} catch (err) {
|
||||
logger.error("ERROR:", err);
|
||||
} finally {
|
||||
process.exit(0);
|
||||
}
|
||||
['SIGINT', 'SIGQUIT'].forEach(function (sig) {
|
||||
process.on(sig, function () {
|
||||
try {
|
||||
console.log("\n\n\n\n");
|
||||
logger.warn(`${sig} close process signal detected.`);
|
||||
InstanceSubsystem.exit();
|
||||
logger.info("The data is saved, thanks for using, goodbye!");
|
||||
logger.info("Closed.");
|
||||
} catch (err) {
|
||||
logger.error("ERROR:", err);
|
||||
} finally {
|
||||
process.exit(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -52,7 +52,12 @@ class DockerProcessAdapter extends EventEmitter implements IInstanceProcess {
|
||||
public async start() {
|
||||
await this.container.start();
|
||||
this.pid = this.container.id;
|
||||
const stream = (this.stream = await this.container.attach({ stream: true, stdout: true, stderr: true, stdin: true }));
|
||||
const stream = (this.stream = await this.container.attach({
|
||||
stream: true,
|
||||
stdout: true,
|
||||
stderr: true,
|
||||
stdin: true
|
||||
}));
|
||||
stream.on("data", (data) => this.emit("data", data));
|
||||
stream.on("error", (data) => this.emit("data", data));
|
||||
this.wait();
|
||||
@ -70,12 +75,13 @@ class DockerProcessAdapter extends EventEmitter implements IInstanceProcess {
|
||||
public async destroy() {
|
||||
try {
|
||||
await this.container.remove();
|
||||
} catch (error) {}
|
||||
} catch (error) {
|
||||
}
|
||||
}
|
||||
|
||||
private wait() {
|
||||
this.container.wait(async (v) => {
|
||||
this.destroy();
|
||||
await this.destroy();
|
||||
this.emit("exit", v);
|
||||
});
|
||||
}
|
||||
@ -87,8 +93,10 @@ export default class DockerStartCommand extends InstanceCommand {
|
||||
}
|
||||
|
||||
async exec(instance: Instance, source = "Unknown") {
|
||||
if (!instance.config.startCommand || !instance.config.cwd || !instance.config.ie || !instance.config.oe) return instance.failure(new StartupDockerProcessError("启动命令,输入输出编码或工作目录为空值"));
|
||||
if (!fs.existsSync(instance.absoluteCwdPath())) return instance.failure(new StartupDockerProcessError("工作目录并不存在"));
|
||||
if (!instance.config.startCommand || !instance.config.cwd || !instance.config.ie || !instance.config.oe)
|
||||
return instance.failure(new StartupDockerProcessError("启动命令,输入输出编码或工作目录为空值"));
|
||||
if (!fs.existsSync(instance.absoluteCwdPath()))
|
||||
return instance.failure(new StartupDockerProcessError("工作目录并不存在"));
|
||||
|
||||
try {
|
||||
// 锁死实例
|
||||
@ -151,13 +159,22 @@ export default class DockerStartCommand extends InstanceCommand {
|
||||
// Note: 检验
|
||||
}
|
||||
|
||||
// 容器名校验
|
||||
let containerName = instance.config.docker.containerName;
|
||||
if (containerName && (containerName.length > 64 || containerName.length < 2)) {
|
||||
throw new Error(`非法的容器名: ${containerName}`);
|
||||
}
|
||||
|
||||
// 输出启动日志
|
||||
logger.info("----------------");
|
||||
logger.info(`会话 ${source}: 请求开启实例`);
|
||||
logger.info(`实例标识符: [${instance.instanceUuid}]`);
|
||||
logger.info(`容器名称: [${containerName}]`);
|
||||
logger.info(`启动命令: ${commandList.join(" ")}`);
|
||||
logger.info(`工作目录: ${cwd}`);
|
||||
logger.info(`端口: ${JSON.stringify(publicPortArray)}`);
|
||||
logger.info(`网络模式: ${instance.config.docker.networkMode}`);
|
||||
logger.info(`端口映射: ${JSON.stringify(publicPortArray)}`);
|
||||
logger.info(`网络别名: ${JSON.stringify(instance.config.docker.networkAliases)}`);
|
||||
if (maxMemory) logger.info(`内存限制: ${maxMemory} MB`);
|
||||
logger.info(`类型: Docker 容器`);
|
||||
logger.info("----------------");
|
||||
@ -165,6 +182,7 @@ export default class DockerStartCommand extends InstanceCommand {
|
||||
// 开始 Docker 容器创建并运行
|
||||
const docker = new Docker();
|
||||
const container = await docker.createContainer({
|
||||
name: containerName,
|
||||
Image: instance.config.docker.image,
|
||||
AttachStdin: true,
|
||||
AttachStdout: true,
|
||||
@ -183,7 +201,15 @@ export default class DockerStartCommand extends InstanceCommand {
|
||||
CpusetCpus: cpusetCpus,
|
||||
CpuPeriod: cpuPeriod,
|
||||
CpuQuota: cpuQuota,
|
||||
PortBindings: publicPortArray
|
||||
PortBindings: publicPortArray,
|
||||
NetworkMode: instance.config.docker.networkMode
|
||||
},
|
||||
NetworkingConfig: {
|
||||
EndpointsConfig: {
|
||||
[instance.config.docker.networkMode]: {
|
||||
"Aliases": instance.config.docker.networkAliases
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -52,10 +52,12 @@ export default class InstanceConfig {
|
||||
|
||||
// Extend
|
||||
public docker: IDockerConfig = {
|
||||
containerName: "",
|
||||
image: "",
|
||||
ports: [],
|
||||
memory: null,
|
||||
networkMode: "bridge",
|
||||
networkAliases: [],
|
||||
cpusetCpus: "",
|
||||
cpuUsage: null,
|
||||
maxSpace: null,
|
||||
|
@ -125,6 +125,7 @@ export default class Instance extends EventEmitter {
|
||||
configureEntityParams(this.config, cfg, "endTime", String);
|
||||
configureEntityParams(this.config, cfg, "fileCode", String);
|
||||
if (cfg.docker) {
|
||||
configureEntityParams(this.config.docker, cfg.docker, "containerName", String);
|
||||
configureEntityParams(this.config.docker, cfg.docker, "image", String);
|
||||
configureEntityParams(this.config.docker, cfg.docker, "memory", Number);
|
||||
configureEntityParams(this.config.docker, cfg.docker, "ports");
|
||||
@ -132,6 +133,7 @@ export default class Instance extends EventEmitter {
|
||||
configureEntityParams(this.config.docker, cfg.docker, "io", Number);
|
||||
configureEntityParams(this.config.docker, cfg.docker, "network", Number);
|
||||
configureEntityParams(this.config.docker, cfg.docker, "networkMode", String);
|
||||
configureEntityParams(this.config.docker, cfg.docker, "networkAliases");
|
||||
configureEntityParams(this.config.docker, cfg.docker, "cpusetCpus", String);
|
||||
configureEntityParams(this.config.docker, cfg.docker, "cpuUsage", Number);
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import { EventEmitter } from "events";
|
||||
|
||||
// interface of docker config
|
||||
export interface IDockerConfig {
|
||||
containerName: string;
|
||||
image: string;
|
||||
memory: number; //以字节为单位的内存限制。
|
||||
ports: string[];
|
||||
@ -30,6 +31,7 @@ export interface IDockerConfig {
|
||||
network: number;
|
||||
io: number;
|
||||
networkMode: string;
|
||||
networkAliases: string[];
|
||||
cpusetCpus: string; //允许执行的 CPU(例如0-3,,0,1)
|
||||
cpuUsage: number;
|
||||
}
|
||||
|
@ -30,8 +30,8 @@ import os from "os";
|
||||
|
||||
// 获取本系统镜像列表
|
||||
routerApp.on("environment/images", async (ctx, data) => {
|
||||
if (os.platform() === "win32") return protocol.responseError(ctx, "[Unsupported] Windows 系统暂不支持此功能");
|
||||
try {
|
||||
if (os.platform() === "win32") return protocol.responseError(ctx, "[Unsupported] Windows 系统暂不支持此功能");
|
||||
const docker = new DockerManager().getDocker();
|
||||
const result = await docker.listImages();
|
||||
protocol.response(ctx, result);
|
||||
@ -51,6 +51,18 @@ routerApp.on("environment/containers", async (ctx, data) => {
|
||||
}
|
||||
});
|
||||
|
||||
// 获取本系统网络列表
|
||||
routerApp.on("environment/networkModes", async (ctx, data) => {
|
||||
if (os.platform() === "win32") return protocol.responseError(ctx, "[Unsupported] Windows 系统暂不支持此功能");
|
||||
try {
|
||||
const docker = new DockerManager().getDocker();
|
||||
const result = await docker.listNetworks();
|
||||
protocol.response(ctx, result);
|
||||
} catch (error) {
|
||||
protocol.responseError(ctx, error);
|
||||
}
|
||||
});
|
||||
|
||||
// 创建镜像
|
||||
routerApp.on("environment/new_image", async (ctx, data) => {
|
||||
if (os.platform() === "win32") return protocol.responseError(ctx, "[Unsupported] Windows 系统暂不支持此功能");
|
||||
|
Loading…
Reference in New Issue
Block a user