From 877ab8e850d4cb7d7a03eb7114091ddeab37feae Mon Sep 17 00:00:00 2001 From: fly6516 Date: Sat, 4 Jan 2025 02:23:58 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E5=AE=B9=E5=99=A8=E7=9A=84?= =?UTF-8?q?=E5=A2=9E=E5=88=A0=E6=94=B9=E6=9F=A5=EF=BC=8C=E5=A4=9A=E4=B8=AA?= =?UTF-8?q?=E5=AE=B9=E5=99=A8=E5=88=9B=E5=BB=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- next.config.ts | 12 ++- package.json | 1 + src/actions/createContainers.ts | 105 +++++++++++++------- src/app/page.tsx | 171 ++++++++++++++------------------ 4 files changed, 156 insertions(+), 133 deletions(-) diff --git a/next.config.ts b/next.config.ts index e9ffa30..a8aa782 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,7 +1,17 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { - /* config options here */ + /* config options here */ + webpack(config, { isServer }) { + // 仅在服务器端处理 .node 文件 + if (isServer) { + config.module.rules.push({ + test: /\.node$/, + use: 'node-loader', // 使用 node-loader 处理 .node 文件 + }); + } + return config; + }, }; export default nextConfig; diff --git a/package.json b/package.json index 829fe25..558a84d 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "bun": "^1.1.42", + "cpu-features": "^0.0.10", "dockerode": "^4.0.2", "next": "15.1.3", "react": "^19.0.0", diff --git a/src/actions/createContainers.ts b/src/actions/createContainers.ts index c41a882..916ed8c 100644 --- a/src/actions/createContainers.ts +++ b/src/actions/createContainers.ts @@ -1,67 +1,100 @@ -// app/actions/containerActions.ts +'use server' + import Docker from 'dockerode'; +// 只在服务器端执行的操作 const docker = new Docker({ socketPath: '/var/run/docker.sock' }); -// 批量创建容器 export async function createContainers(count: number, baseName: string, startingPorts: [number, number]) { const [vncStart, sshStart] = startingPorts; const promises = []; + // 只在服务器端加载 cpu-features + if (typeof window === 'undefined') { + try { + const cpuFeatures = require('cpu-features'); // 仅在服务器端加载 + console.log('CPU Features:', cpuFeatures); // 打印所有的 CPU 特性对象 + } catch (error) { + console.error('Error loading cpu-features:', error); + } + } + for (let i = 0; i < count; i++) { const containerName = `${baseName}-${i}`; const vncPort = vncStart + i; const sshPort = sshStart + i; - const container = docker.createContainer({ - Image: 'ubuntu-xfce-vnc-ssh', // 使用你的镜像 - name: containerName, - ExposedPorts: { - '5900/tcp': {}, // VNC 默认端口 - '22/tcp': {}, // SSH/SFTP 默认端口 - }, - HostConfig: { - PortBindings: { - '5900/tcp': [{ HostPort: vncPort.toString() }], - '22/tcp': [{ HostPort: sshPort.toString() }], + try { + const container = await docker.createContainer({ + Image: 'dockerp.com/dcsunset/ubuntu-vnc:latest', // 使用你的镜像 + name: containerName, + ExposedPorts: { + '5900/tcp': {}, // VNC 默认端口 + '22/tcp': {}, // SSH/sSFTP 默认端口 }, - }, - }); + HostConfig: { + PortBindings: { + '5900/tcp': [{ HostPort: vncPort.toString() }], + '22/tcp': [{ HostPort: sshPort.toString() }], + }, + }, + }); - promises.push(container); + promises.push(container); + } catch (error) { + console.error('Error creating container:', error); + throw new Error(`Failed to create container ${containerName}`); + } } return Promise.all(promises); } -// 关闭容器 +// 其他容器操作如 stop、remove 等 export async function stopContainer(containerName: string) { - const container = docker.getContainer(containerName); - await container.stop(); - return { message: `Container ${containerName} stopped successfully.` }; + try { + const container = docker.getContainer(containerName); + await container.stop(); + return { message: `Container ${containerName} stopped successfully.` }; + } catch (error) { + console.error('Error stopping container:', error); + throw new Error(`Failed to stop container ${containerName}`); + } } -// 删除容器 export async function removeContainer(containerName: string) { - const container = docker.getContainer(containerName); - await container.remove(); - return { message: `Container ${containerName} removed successfully.` }; + try { + const container = docker.getContainer(containerName); + await container.remove(); + return { message: `Container ${containerName} removed successfully.` }; + } catch (error) { + console.error('Error removing container:', error); + throw new Error(`Failed to remove container ${containerName}`); + } } -// 获取容器信息 export async function getContainerInfo(containerName: string) { - const container = docker.getContainer(containerName); - const info = await container.inspect(); - return { - containerName: info.Name, - state: info.State.Status, - ports: info.NetworkSettings.Ports, - }; + try { + const container = docker.getContainer(containerName); + const info = await container.inspect(); + return { + containerName: info.Name, + state: info.State.Status, + ports: info.NetworkSettings.Ports, + }; + } catch (error) { + console.error('Error retrieving container info:', error); + throw new Error(`Failed to retrieve info for container ${containerName}`); + } } -// 启动容器 export async function startContainer(containerName: string) { - const container = docker.getContainer(containerName); - await container.start(); - return { message: `Container ${containerName} started successfully.` }; + try { + const container = docker.getContainer(containerName); + await container.start(); + return { message: `Container ${containerName} started successfully.` }; + } catch (error) { + console.error('Error starting container:', error); + throw new Error(`Failed to start container ${containerName}`); + } } diff --git a/src/app/page.tsx b/src/app/page.tsx index 3eee014..396554e 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,101 +1,80 @@ -import Image from "next/image"; +'use client' + +import React, { useState } from 'react'; + +// 引入 Server Actions +import { createContainers, stopContainer, removeContainer, getContainerInfo, startContainer } from '@/actions/createContainers'; export default function Home() { - return ( -
-
- Next.js logo -
    -
  1. - Get started by editing{" "} - - src/app/page.tsx - - . -
  2. -
  3. Save and see your changes instantly.
  4. -
+ const [error, setError] = useState(null); + const [message, setMessage] = useState(null); -
- - Vercel logomark - Deploy now - - - Read our docs - + // 创建容器的函数 + const handleCreateContainers = async () => { + try { + const count = 3; // 创建容器的数量 + const baseName = 'my-container'; // 容器名称前缀 + const startingPorts: [number, number] = [5901, 2201]; // VNC 和 SSH 起始端口 + const containers = await createContainers(count, baseName, startingPorts); + setMessage(`Successfully created ${containers.length} containers.`); + } catch (err: any) { + setError(`Error creating containers: ${err.message}`); + } + }; + + // 停止容器的函数 + const handleStopContainer = async (containerName: string) => { + try { + const result = await stopContainer(containerName); + setMessage(result.message); + } catch (err: any) { + setError(`Error stopping container: ${err.message}`); + } + }; + + // 删除容器的函数 + const handleRemoveContainer = async (containerName: string) => { + try { + const result = await removeContainer(containerName); + setMessage(result.message); + } catch (err: any) { + setError(`Error removing container: ${err.message}`); + } + }; + + // 获取容器信息的函数 + const handleGetContainerInfo = async (containerName: string) => { + try { + const info = await getContainerInfo(containerName); + setMessage(`Container: ${info.containerName}, State: ${info.state}, Ports: ${JSON.stringify(info.ports)}`); + } catch (err: any) { + setError(`Error getting container info: ${err.message}`); + } + }; + + // 启动容器的函数 + const handleStartContainer = async (containerName: string) => { + try { + const result = await startContainer(containerName); + setMessage(result.message); + } catch (err: any) { + setError(`Error starting container: ${err.message}`); + } + }; + + return ( +
+

Container Management

+ {error &&

{error}

} + {message &&

{message}

} + +
+ + + + + +
-
- -
- ); + ); }