提交 8741f56e authored 作者: 陈泽健's avatar 陈泽健

feat(script): 添加远程更新脚本功能

- 新增远程容器更新脚本(remote_container_update_win.ps1),支持Windows环境执行
- 实现自动连接指定服务器功能,支持预设服务器列表和手动输入模式
- 添加容器类型选择功能,支持ujava、uemqx、uredis、upython、unacos、unginx六种容器
- 集成文件传输功能,自动传输镜像文件和部署脚本到目标服务器
- 实现平台类型自动检测,区分新统一平台和传统平台
- 添加架构校验功能,确保目标服务器为x86架构
- 集成版本校验机制,避免重复更新相同版本的容器
- 支持EMQX和Nginx配置文件同步功能
- 实现部署完成后的自动清理机制
- 添加详细的日志记录和审计功能,便于问题排查
- 更新需求文档,详细描述远程程序更新脚本的功能需求
- 添加备份机制,在更新前自动备份原有数据和文件
- 实现根据不同系统类型和更新类型的差异化更新策略
上级 019b8201
<#
功能:Windows 端远程更新入口脚本(实现 PRD 3.1、3.2)
依赖:PuTTY 的 plink.exe / pscp.exe
#>
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
function Write-Info($msg) { Write-Host "[INFO] $msg" -ForegroundColor Cyan }
function Write-Warn($msg) { Write-Host "[WARN] $msg" -ForegroundColor Yellow }
function Write-Err ($msg) { Write-Host "[ERROR] $msg" -ForegroundColor Red }
function Read-NonEmpty([string]$prompt, [string]$default = "") {
while ($true) {
if ($default) {
$v = Read-Host "$prompt (默认: $default)"
if ([string]::IsNullOrWhiteSpace($v)) { return $default }
return $v
} else {
$v = Read-Host $prompt
if (-not [string]::IsNullOrWhiteSpace($v)) { return $v }
}
}
}
function Read-Choice([string]$prompt, [string[]]$choices) {
Write-Host $prompt
for ($i=0; $i -lt $choices.Count; $i++) {
Write-Host " [$($i+1)] $($choices[$i])"
}
while ($true) {
$sel = Read-Host "请输入序号(1-$($choices.Count))"
if ($sel -match '^\d+$') {
$idx = [int]$sel - 1
if ($idx -ge 0 -and $idx -lt $choices.Count) { return $choices[$idx] }
}
Write-Warn "输入无效,请重新输入。"
}
}
function Find-Tool([string]$name) {
$cmd = Get-Command $name -ErrorAction SilentlyContinue
if ($cmd) { return $cmd.Source }
$local = Join-Path $PSScriptRoot $name
if (Test-Path $local) { return $local }
return $null
}
function Require-PuttyTools {
$plink = Find-Tool "plink.exe"
$pscp = Find-Tool "pscp.exe"
if (-not $plink -or -not $pscp) {
Write-Err "未找到 plink.exe/pscp.exe。请安装 PuTTY 并加入 PATH,或将 plink.exe/pscp.exe 放在脚本同目录。"
throw "Missing PuTTY tools"
}
return @{ plink=$plink; pscp=$pscp }
}
function Invoke-PlinkCommand {
param(
[Parameter(Mandatory=$true)][string]$PlinkPath,
[Parameter(Mandatory=$true)][string]$HostName,
[Parameter(Mandatory=$true)][int]$Port,
[Parameter(Mandatory=$true)][string]$User,
[Parameter(Mandatory=$true)][string]$Password,
[Parameter(Mandatory=$true)][string]$Command
)
$args = @(
"-batch",
"-no-antispoof",
"-ssh",
"-P", "$Port",
"-l", $User,
"-pw", $Password,
$HostName,
$Command
)
Write-Info "远端执行: $Command"
$p = Start-Process -FilePath $PlinkPath -ArgumentList $args -NoNewWindow -Wait -PassThru
if ($p.ExitCode -ne 0) {
throw "plink 执行失败,ExitCode=$($p.ExitCode)。命令:$Command"
}
}
function Invoke-PscpUpload {
param(
[Parameter(Mandatory=$true)][string]$PscpPath,
[Parameter(Mandatory=$true)][string]$HostName,
[Parameter(Mandatory=$true)][int]$Port,
[Parameter(Mandatory=$true)][string]$User,
[Parameter(Mandatory=$true)][string]$Password,
[Parameter(Mandatory=$true)][string[]]$LocalFiles,
[Parameter(Mandatory=$true)][string]$RemoteDir
)
foreach ($lf in $LocalFiles) {
if (-not (Test-Path $lf)) {
throw "本地文件不存在:$lf"
}
}
if ($RemoteDir.EndsWith("/") -eq $false) { $RemoteDir = "$RemoteDir/" }
$remoteTarget = ("{0}@{1}:{2}" -f $User, $HostName, $RemoteDir)
foreach ($lf in $LocalFiles) {
$args = @(
"-batch",
"-P", "$Port",
"-pw", $Password,
$lf,
$remoteTarget
)
Write-Info "上传: $(Split-Path $lf -Leaf) -> $RemoteDir"
$p = Start-Process -FilePath $PscpPath -ArgumentList $args -NoNewWindow -Wait -PassThru
if ($p.ExitCode -ne 0) {
throw "pscp 上传失败,ExitCode=$($p.ExitCode)。文件:$lf"
}
}
}
# -------------------- 3.1 采集参数 --------------------
Write-Host "=== 远程程序更新(Windows 端入口)===" -ForegroundColor Green
$serverIp = Read-NonEmpty "请输入服务器IP"
$sshPortStr = Read-NonEmpty "请输入SSH端口" "22"
$sshPort = [int]$sshPortStr
$username = Read-NonEmpty "请输入用户名" "root"
$securePwd = Read-Host "请输入密码" -AsSecureString
$plainPwd = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securePwd))
$remoteDir = Read-NonEmpty "请输入远端文件存放路径" "/home/Update/"
$platformType = Read-Choice "请选择平台类型:" @("新统一平台", "传统平台")
$systemType = Read-Choice "请选择更新系统类型:" @("会议预定系统", "运维集控系统", "讯飞转录系统")
$updateType = Read-Choice "请选择更新类型:" @("前端更新", "后端更新", "全量更新")
Write-Info "参数确认:IP=$serverIp Port=$sshPort User=$username RemoteDir=$remoteDir 平台=$platformType 系统=$systemType 更新=$updateType"
# -------------------- 工具检测 --------------------
$tools = Require-PuttyTools
$plink = $tools.plink
$pscp = $tools.pscp
# -------------------- 连接测试(3.1) --------------------
Invoke-PlinkCommand -PlinkPath $plink -HostName $serverIp -Port $sshPort -User $username -Password $plainPwd -Command "echo Connected; uname -a"
Write-Info "SSH 连接测试成功。"
# 1) 远端创建目录 + 检查 unzip
Invoke-PlinkCommand -PlinkPath $plink -HostName $serverIp -Port $sshPort -User $username -Password $plainPwd -Command "mkdir -p '$remoteDir'; command -v unzip >/dev/null 2>&1 || (echo '缺少 unzip,请安装:yum install -y unzip 或 apt-get install -y unzip' && exit 2)"
# ====== 3.2 本地准备:找到 zip 包 + program_update.sh ======
# 约定:zip 压缩包与本 remote_program_update.ps1 同级目录
$zipFiles = @(
Get-ChildItem -Path $PSScriptRoot -Filter *.zip -File |
Select-Object -ExpandProperty FullName
)
if ($zipFiles.Length -eq 0) {
throw "未找到 zip 压缩包:请将更新包(*.zip)放到脚本同级目录:$PSScriptRoot"
}
if ($zipFiles.Length -gt 1) {
Write-Warn "检测到多个 zip,默认使用第一个:$($zipFiles[0])"
}
$zipPath = $zipFiles[0]
$programUpdateSh = Join-Path $PSScriptRoot "program_update.sh"
if (-not (Test-Path $programUpdateSh)) {
throw "未找到 program_update.sh:$programUpdateSh(请放在脚本同级目录)"
}
Write-Info "将上传更新包:$zipPath"
Write-Info "将上传更新脚本:$programUpdateSh"
# ====== 3.2 本地准备结束 ======
# 2) 上传 zip + program_update.sh
Invoke-PscpUpload -PscpPath $pscp -HostName $serverIp -Port $sshPort -User $username -Password $plainPwd -LocalFiles @($zipPath, $programUpdateSh) -RemoteDir $remoteDir
# 3) 远端解压(解压到 remoteDir)
$zipName = Split-Path $zipPath -Leaf
Invoke-PlinkCommand -PlinkPath $plink -HostName $serverIp -Port $sshPort -User $username -Password $plainPwd -Command "cd '$remoteDir' && unzip -o '$zipName' -d '$remoteDir'"
# 可选执行入口
if ($runNow -eq "是") {
$cmd = "cd '$remoteDir' && chmod +x ./program_update.sh && ./program_update.sh --platform '$platformType' --system '$systemType' --update '$updateType' --workdir '$remoteDir'"
Invoke-PlinkCommand -PlinkPath $plink -HostName $serverIp -Port $sshPort -User $username -Password $plainPwd -Command $cmd
}
\ No newline at end of file
...@@ -10,12 +10,89 @@ ...@@ -10,12 +10,89 @@
remote_update.ps1为Windows执行脚本,用以远程更新程序 remote_update.ps1为Windows执行脚本,用以远程更新程序
program_update.sh为Linux执行脚本,用于在远程服务器上执行更新操作 program_update.sh为Linux执行脚本,用于在远程服务器上执行更新操作
### 三、功能需求: ### 三、功能需求:
#### 3.1.支持远程连接到指定服务器。 #### 3.1.支持远程连接到指定服务器。(remote_program_update.ps1)
- 输入服务器IP - 输入服务器IP
- ssh端口号 - ssh端口号
- 输入用户名密码 - 输入用户名密码
- 输入文件存放路径(默认为/home/Update/) - 输入文件存放路径(默认为/home/Update/)
#### 3.2.能够上传更新压缩文件以及更新脚本。 - 判断平台类型(新统一平台/传统平台)
- 将当前脚本同级目录下的压缩包和program_update.sh脚本上传到指定服务器的指定路径下。 - 输入更新系统类型(会议预定系统、运维集控系统、讯飞转录系统)
#### 3.3.自动停止相关服务,进行包的替换和更新。 - 输入更新类型(前端更新、后端更新、全量更新)
#### 3.4.重启服务并验证更新是否成功。
\ No newline at end of file #### 3.2.能够上传更新压缩文件以及更新脚本。(remote_program_update.ps1)
- 将当前脚本同级目录下的zip压缩包和program_update.sh脚本上传到指定服务器的指定路径下。
- 解压缩压缩包,通过unzip命令解压到指定目录(/home/Update/)。
#### 3.3.备份原有数据. (program_update.sh)
- 在执行更新操作前,先备份原有的前端或后端文件夹到备份目录(/home/Backup/)。
-- 创建备份目录:
执行mkdir -p /home/Backup/Bak时间戳
-- 备份前端文件夹:
cp -r 根据系统类型和更新类型选择对应的前端路径及文件 备份目录路径
-- 备份后端文件夹:
cp -r 根据系统类型和更新类型选择对应的后端路径及文件 备份目录路径
-- 备份数据库操作如下:
1.查询MySQL容器名称
2.进入MySQL容器
3.执行mysqldump -uroot -p 根据系统类型选择对应的数据库名称 > /备份目录路径/数据库名称_时间戳.sql
- 打压缩当前备份包,并导出至桌面
-- 执行tar -czvf /home/Backup/Bak时间戳.tar.gz /home/Backup/Bak时间戳
-- 将压缩包移动到桌面:mv /home/Backup/Bak时间戳.tar.gz remote_update.ps1所在路径
#### 3.4.更新服务(program_update.sh)
- 根据系统类型和更新类型选择对应的更新脚本执行更新操作
- 前端更新操作:
-- 传统平台
1.会议预定系统:
- 前台前端:
cd /home/Update/ubains-web-2.0
mv * /var/www/java/ubains-web-2.0/(覆盖操作)
- 后台前端:
cd /home/Update/ubains-web-admin
mv * /var/www/java/ubains-web-admin/(覆盖操作)
- 对内后端:
cd /home/Update/api-java-meeting2.0
mv * /var/www/java/api-java-meeting2.0/(覆盖操作)
- 对外后端:
cd /home/Update/external-meeting-api
mv * /var/www/java/external-meeting-api/(覆盖操作)
2.运维集控系统:
- 前端:
cd /home/Update/web-vue-rms
mv * /var/www/html/web-vue-rms/(覆盖操作)
- 后端:
cd /home/Update/cmdb
mv * /var/www/html/(覆盖操作)
3.讯飞转录系统:
- 前端:
cd /home/Update/web-vue-rms
mv * /var/www/html/web-vue-rms/(覆盖操作)
- 后端:
cd /home/Update/cmdb
mv * /var/www/html/(覆盖操作)
#### 3.5.重启服务并验证更新是否成功。
- 如果更新类型为前端更新,则无需重启服务
- 如果更新类型为后端更新,则需重启服务
-- 通过系统名称类型重启对应服务
1.会议预定系统:
- cd /var/www/java/external-meeting-api
- ./run.sh;tail -f logs/ubains-INFO-AND-ERROR.log
- docker exec -it ujava2 bash
- cd /var/www/java/api-java-meeting2.0
- ./run.sh;tail -f logs/ubains-INFO-AND-ERROR.log
2.运维集控系统:
- cd /var/www/html
- docker restart upython
- tail -f log/uinfo.log
3.讯飞转录系统:
- cd /var/www/html
- docker restart upython
- tail -f log/uinfo.log
### 四、不同平台的路径映射:
#### 4.1.传统平台路径映射:
| 系统名称 | 前端路径及文件 | 后端路径及文件 | 数据库名称 |
|:会议预定系统: | :前台前端:/var/www/java/ubains-web-2.0 *.js static/ index.html 后台前端:/var/www/java/ubains-web-admin index.html static/: | :对内后端:/var/www/java/api-java-meeting2.0 *.jar 对外后端:/var/www/java/external-meeting-api *.jar: | :数据库:ubains: |
|:运维集控系统: | :前端:/var/www/html/web-vue-rms static/ index.html: | :后端:/var/www/html cmdb/ UbainsDevOps/: | :数据库:devops: |
|:讯飞转录系统: | :前端:/var/www/html/web-vue-voice static/ index.html: | :后端:/var/www/html UbainsDevOps/: | :数据库:devops: |
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论