feat: 优化 Windows 部署与文档
Some checks are pending
Test start.ps1 (Windows) / test-windows (push) Waiting to run
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:
parent
e9c594c3e6
commit
e64a90332c
20
README.md
20
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`
|
||||
|
||||
---
|
||||
|
||||
## 重要更新记录:
|
||||
|
||||
|
||||
@ -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
67
reset-docker-network.ps1
Normal 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
158
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
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user