feat: 优化 Windows 部署与文档
Some checks are pending
Test start.ps1 (Windows) / test-windows (push) Waiting to run

- start.ps1: 局域网 IP 自动检测, 部署完成提示默认账户 admin/123456
- start.ps1: 修复 UTF-8 BOM 避免 PowerShell 5.1 解析闪退
- docker-compose: dozzle 容器增加 restart 与 logging 配置
- 新增 reset-docker-network.ps1 网络重置脚本
- README: 顶部增加 Linux/Windows 一键部署命令, Windows 权限说明

Made-with: Cursor
This commit is contained in:
wangbolhr 2026-03-11 14:41:53 +08:00
parent e9c594c3e6
commit e64a90332c
4 changed files with 238 additions and 14 deletions

View File

@ -1,3 +1,23 @@
## 一键部署
### Linux
```bash
git clone https://git.51easyai.com/wangbo/easyai.git && cd easyai && chmod +x start.sh && ./start.sh
```
### Windows
```powershell
git clone https://git.51easyai.com/wangbo/easyai.git; cd easyai; powershell -ExecutionPolicy Bypass -File .\start.ps1
```
> **Windows 脚本权限说明**PowerShell 默认禁止运行脚本,直接双击 `start.ps1` 会闪退。
>
> - **推荐**:使用 `powershell -ExecutionPolicy Bypass -File .\start.ps1` 执行,无需修改系统策略
> - **或**:以管理员身份打开 PowerShell执行 `Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser`,之后可直接运行 `.\start.ps1`
---
## 重要更新记录:

View File

@ -247,6 +247,7 @@ services:
video-edit:
image: registry.cn-shanghai.aliyuncs.com/easyaigc/videoedit:latest
container_name: video-edit
platform: linux/amd64
labels:
- 'com.centurylinklabs.watchtower.enable=true'
volumes:
@ -292,6 +293,12 @@ services:
- ./data:/data
ports:
- 8080:8080
restart: unless-stopped
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "3"
sandbox:
image: registry.cn-shanghai.aliyuncs.com/easyaigc/sandbox:latest
container_name: sandbox

67
reset-docker-network.ps1 Normal file
View File

@ -0,0 +1,67 @@
#Requires -RunAsAdministrator
# WSL 与 Docker 网络配置重置脚本
# 需以管理员身份运行
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$ErrorActionPreference = "Continue"
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " WSL & Docker 网络配置重置" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
# 1. 关闭 WSL
Write-Host "[1/5] 关闭 WSL..." -ForegroundColor Yellow
wsl --shutdown
Start-Sleep -Seconds 3
Write-Host " 完成" -ForegroundColor Green
# 2. 重置 Windows 网络栈(可选,可能需重启)
Write-Host "[2/5] 重置 Windows 网络栈..." -ForegroundColor Yellow
try {
netsh winsock reset 2>$null
netsh int ip reset 2>$null
Write-Host " 完成 (如有提示重启,建议执行)" -ForegroundColor Green
} catch {
Write-Host " 跳过: $($_.Exception.Message)" -ForegroundColor Gray
}
# 3. 清理 Docker 网络
Write-Host "[3/5] 清理 Docker 未使用网络..." -ForegroundColor Yellow
$dockerOk = $false
try {
$null = docker info 2>&1
$dockerOk = $true
} catch { }
if ($dockerOk) {
docker network prune -f 2>$null
Write-Host " 完成" -ForegroundColor Green
} else {
Write-Host " 跳过 (Docker 未运行,请先启动 Docker Desktop)" -ForegroundColor Gray
}
# 4. 清除 Docker 端口代理残留(若有)
Write-Host "[4/5] 检查端口代理..." -ForegroundColor Yellow
$proxies = netsh interface portproxy show all 2>$null
if ($proxies -and $proxies -match "3010|3001|3002|3003") {
Write-Host " 发现相关端口代理,请手动在管理员 CMD 执行:" -ForegroundColor Yellow
Write-Host " netsh interface portproxy reset" -ForegroundColor White
} else {
Write-Host " 无异常端口代理" -ForegroundColor Green
}
# 5. 提示
Write-Host "[5/5] 下一步操作:" -ForegroundColor Yellow
Write-Host ""
Write-Host " 1. 启动 Docker Desktop若已关闭" -ForegroundColor White
Write-Host " 2. 等待 Docker 完全就绪后,执行:" -ForegroundColor White
Write-Host " cd D:\01一键部署包\easyai" -ForegroundColor Cyan
Write-Host " docker compose up -d" -ForegroundColor Cyan
Write-Host ""
Write-Host " 3. 若端口仍不可访问,在 Docker Desktop 中:" -ForegroundColor White
Write-Host " [设置] -> [Troubleshoot] -> [Reset to factory defaults]" -ForegroundColor Cyan
Write-Host " (会清除所有容器/镜像,谨慎使用)" -ForegroundColor Gray
Write-Host ""
Write-Host " 4. 若执行了 netsh winsock/int ip reset建议重启电脑" -ForegroundColor White
Write-Host ""
Read-Host "按 Enter 键退出"

158
start.ps1
View File

@ -1,10 +1,16 @@
#Requires -Version 5.1
#Requires -Version 5.1
# EasyAI Windows 一键部署脚本
# 仅支持 IP 访问(本地/局域网),不含域名与 HTTPS
# 一行命令: git clone https://git.51easyai.com/wangbo/easyai; cd easyai; .\start.ps1
# 设置控制台编码为 UTF-8确保中文正确显示
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$OutputEncoding = [System.Text.Encoding]::UTF8
$ErrorActionPreference = "Stop"
$script:LogFile = Join-Path (if ($PSScriptRoot) { $PSScriptRoot } else { $env:TEMP }) "start.ps1.log"
$script:LogDir = $PSScriptRoot
if (-not $script:LogDir) { $script:LogDir = $env:TEMP }
$script:LogFile = Join-Path $script:LogDir "start.ps1.log"
# 尽早写入启动标记,便于闪退时排查
try { "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] === 脚本加载 ===" | Out-File -FilePath $script:LogFile -Append -Encoding utf8 } catch { }
@ -19,7 +25,12 @@ function Write-Log {
trap {
$errMsg = $_.Exception.Message
$errStack = if ($_.ScriptStackTrace) { " | 堆栈: $($_.ScriptStackTrace)" } else { "" }
Write-Log "错误退出: $errMsg$errStack"
try {
$logPath = $script:LogFile
if (-not $logPath) { $logPath = Join-Path $env:TEMP "start.ps1.log" }
$logLine = "[$(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')] 错误退出: $errMsg$errStack"
Add-Content -Path $logPath -Value $logLine -Encoding UTF8 -ErrorAction SilentlyContinue
} catch { }
try {
Write-Host ""
Write-Host "========================================" -ForegroundColor Red
@ -91,13 +102,29 @@ function Run-DeployQuestions {
Write-Step "已选择本地访问"
}
"2" {
Write-Host " 提示: 可在本机运行 ipconfig 查看 IPv4 地址"
$lanIp = Read-Host "请输入本机局域网 IP 地址"
$lanIp = $lanIp.Trim()
if ([string]::IsNullOrWhiteSpace($lanIp)) {
Write-Err "IP 不能为空"
# 自动获取局域网 IP排除回环和 APIPA 地址)
$detectedIp = $null
try {
$addrs = Get-NetIPAddress -AddressFamily IPv4 -ErrorAction SilentlyContinue | Where-Object {
$_.InterfaceAlias -notlike "*Loopback*" -and
$_.IPAddress -notmatch "^127\." -and
$_.IPAddress -notmatch "^169\.254\."
}
$detectedIp = ($addrs | Sort-Object InterfaceIndex | Select-Object -First 1).IPAddress
} catch { }
if ($detectedIp) {
$defaultHint = "回车使用 [$detectedIp]"
Write-Host " 检测到局域网 IP: $detectedIp"
$inputIp = Read-Host "请输入本机局域网 IP$defaultHint 或手动输入)"
$inputIp = $inputIp.Trim()
$script:DeployIP = if ([string]::IsNullOrWhiteSpace($inputIp)) { $detectedIp } else { $inputIp }
} else {
Write-Host " 提示: 未自动检测到局域网 IP可在本机运行 ipconfig 查看"
$lanIp = Read-Host "请输入本机局域网 IP 地址"
$lanIp = $lanIp.Trim()
if ([string]::IsNullOrWhiteSpace($lanIp)) { Write-Err "IP 不能为空" }
$script:DeployIP = $lanIp
}
$script:DeployIP = $lanIp
Write-Warn "请确保防火墙已放行 3001、3002、3003 端口"
}
default {
@ -152,6 +179,95 @@ function Test-DockerInstalled {
}
}
# 检查 Docker 引擎是否已启动并可响应(带超时,避免 docker info 卡住)
function Test-DockerRunning {
param([int]$TimeoutSeconds = 10)
try {
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = "docker"
$psi.Arguments = "info"
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.UseShellExecute = $false
$psi.CreateNoWindow = $true
$p = [System.Diagnostics.Process]::Start($psi)
$exited = $p.WaitForExit($TimeoutSeconds * 1000)
if (-not $exited) {
try { $p.Kill() } catch { }
return $false
}
return ($p.ExitCode -eq 0)
} catch {
return $false
}
}
# 启动 Docker Desktop 并等待就绪
function Start-DockerDesktopAndWait {
param(
[int]$MaxWaitSeconds = 120,
[int]$CheckIntervalSeconds = 5
)
Write-Step "Docker 未运行,正在启动 Docker Desktop..."
$dockerDesktopPath = "${env:ProgramFiles}\Docker\Docker\Docker Desktop.exe"
if (-not (Test-Path $dockerDesktopPath)) {
$dockerDesktopPath = "${env:ProgramFiles(x86)}\Docker\Docker\Docker Desktop.exe"
}
if (-not (Test-Path $dockerDesktopPath)) {
Write-Warn "未找到 Docker Desktop 可执行文件"
Write-Host "请手动启动 Docker Desktop 后重新运行本脚本。"
return $false
}
# 尝试使用 docker desktop startDocker Desktop 4.38+ 支持)
$useCli = $false
try {
$null = & docker desktop start 2>&1
$useCli = $true
Write-Step "已通过 docker desktop start 发送启动命令"
} catch {
# 回退到直接启动进程
}
if (-not $useCli) {
Start-Process -FilePath $dockerDesktopPath -WindowStyle Hidden
Write-Step "已启动 Docker Desktop 进程"
}
Write-Host "等待 Docker 引擎就绪(最长 $MaxWaitSeconds 秒)..." -ForegroundColor Cyan
$elapsed = 0
while ($elapsed -lt $MaxWaitSeconds) {
Start-Sleep -Seconds $CheckIntervalSeconds
$elapsed += $CheckIntervalSeconds
Write-Host " 已等待 $elapsed 秒..." -NoNewline
if (Test-DockerRunning) {
Write-Host " 完成" -ForegroundColor Green
Write-Ok "Docker 已就绪"
return $true
}
Write-Host ""
}
Write-Warn "等待超时Docker 可能仍在启动中"
Write-Host "请稍后手动执行 docker info 确认,或重新运行本脚本。"
return $false
}
# 确保 Docker 已安装且运行,若未运行则尝试启动
function Ensure-DockerRunning {
if (-not (Test-DockerInstalled)) {
return $false
}
if (Test-DockerRunning) {
Write-Ok "Docker 引擎已运行"
$v = docker --version 2>$null
if ($v) { Write-Host " $v" }
return $true
}
return (Start-DockerDesktopAndWait)
}
function Install-DockerDesktop {
$isWin = ($env:OS -eq "Windows_NT") -or ($PSVersionTable.PSVersion.Major -ge 6 -and $IsWindows)
if (-not $isWin) {
@ -192,8 +308,14 @@ function Test-Docker {
if (Test-DockerInstalled) {
Write-Ok "Docker 已安装"
$v = docker --version 2>$null
if ($v) { Write-Host " $v" }
# 检查并确保 Docker 引擎运行
if (-not (Ensure-DockerRunning)) {
Write-Warn "Docker 未能自动启动"
Write-Host ""
Write-Host "请手动启动 Docker Desktop确认其完全启动后再重新运行本脚本。"
Wait-ForExit
exit 1
}
return
}
@ -258,11 +380,17 @@ function Main {
if ((Test-Path ".env") -and -not $env:DEPLOY_FORCE_RECONFIG -and -not $env:DEPLOY_IP) {
Write-Step "📁 检测到已有 .env 配置"
$reconfigure = Read-Host "是否重新配置访问方式?[y/N]"
if ($reconfigure -notmatch '^[yY]') {
$trimmed = $reconfigure.Trim().ToLower()
$startsWithY = ($trimmed.Length -gt 0) -and ($trimmed[0] -eq [char]121)
if (-not $startsWithY) {
Write-Step "使用现有配置继续..."
# 从现有 .env 读取 IP用于最后输出
$line = Get-Content ".env" | Where-Object { $_ -match '^NUXT_PUBLIC_BASE_APIURL=http://([^:]+):3001' } | Select-Object -First 1
if ($line -match 'http://([^:]+):3001') { $script:DeployIP = $Matches[1] }
$line = Get-Content ".env" -Encoding UTF8 | Where-Object { $_ -like "NUXT_PUBLIC_BASE_APIURL=*" } | Select-Object -First 1
if ($line -and $line -like "*:3001*") {
$prefix = ".*http://"
$suffix = ":3001.*"
$script:DeployIP = ($line -replace $prefix, "" -replace $suffix, "").Trim()
}
$script:DeployModeSkip = $true
}
}
@ -293,6 +421,8 @@ function Main {
Write-Host "================================"
$accessIp = if ($script:DeployIP) { $script:DeployIP } else { "127.0.0.1" }
Write-Host "访问地址: http://${accessIp}:3010"
Write-Host "默认登录账户: admin"
Write-Host "默认登录密码: 123456"
Write-Host ""
Wait-ForExit
}