diff --git a/README.md b/README.md index f594965..5f23d71 100644 --- a/README.md +++ b/README.md @@ -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` + +--- ## 重要更新记录: diff --git a/docker-compose.yml b/docker-compose.yml index 7d614c3..e8907dc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -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 diff --git a/reset-docker-network.ps1 b/reset-docker-network.ps1 new file mode 100644 index 0000000..47a57bb --- /dev/null +++ b/reset-docker-network.ps1 @@ -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 键退出" diff --git a/start.ps1 b/start.ps1 index c6df889..83df958 100644 --- a/start.ps1 +++ b/start.ps1 @@ -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 start(Docker 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 }