【脚本】一键部署脚本
背景:现场实施同事部署项目步骤繁琐、配置项容易搞错并且容易更错软件包;所以在想能不能写一个跨平台Shell/PowerShell脚本,自动完成Jdk安装、配置文件替换、服务启动等10+步骤等;经过一周的编写加调试,终于搞定,经实施同事确认,单次部署时间从2小时(人工)缩短至5分钟(脚本),实施效率提升24倍;部署流程标准化率100%,新员工培训成本至少减少70%;
deploy-wms.ps1
param([string]$ConfigFile = "wms-config.ps1"
)# Error handling
$ErrorActionPreference = "Stop"# Load configuration file
if (-Not (Test-Path $ConfigFile)) {throw "Error: Configuration file $ConfigFile not found!"
}
. (Resolve-Path $ConfigFile)# Validate required parameters
$requiredVars = @("DeployPath","MySqlUrl","BackendPackage","FrontendPackage","H5Package","NginxPath","BackendURL","NginxListenPort"
)foreach ($var in $requiredVars) {if (-Not (Get-Variable -Name $var -ErrorAction SilentlyContinue)) {throw "Error: Missing required configuration parameter $var"}
}# [1/9]创建部署目录
Write-Host "[1/9] Creating deployment directory..."
$directories = @("$DeployPath/backend","$DeployPath/frontend","$DeployPath/h5","$DeployPath/nginx"
)
$directories | ForEach-Object {New-Item -Path $_ -ItemType Directory -Force | Out-Null
}
# [2/9]安装JDK
Write-Host "[2/9] Install JDK..."
$jdkInstalled = $false
$javaVersion = (Get-Command java -ErrorAction SilentlyContinue).Versionif ($javaVersion) {Write-Host "JDK is already installed, version: $javaVersion"$jdkInstalled = $true
} else {Write-Host "JDK not detected, starting installation..."
}# If JDK is not installed, proceed with installation
if (-not $jdkInstalled) {# Specify the path to the already downloaded JDK installer$installerPath = ".\jdk\jdk-8u291-windows-x64.exe"if (-Not (Test-Path $installerPath)) {Write-Host "JDK installer not found, please check the path: $installerPath"exit 1}# Install JDKStart-Process -FilePath $installerPath -ArgumentList "/s" -Wait# Configure environment variables$javaHome = "C:\Program Files\Java\jdk-8"[System.Environment]::SetEnvironmentVariable("JAVA_HOME", $javaHome, [System.EnvironmentVariableTarget]::Machine)$env:JAVA_HOME = $javaHome$path = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::Machine)$newPath = "$javaHome\bin;" + $path[System.Environment]::SetEnvironmentVariable("Path", $newPath, [System.EnvironmentVariableTarget]::Machine)$env:Path = "$javaHome\bin;" + $env:PathWrite-Host "JDK installation complete and environment variables configured"
}
# [3/9]安装MySql
Write-Host "[3/9] Install MySQL..."
$mysqlInstalled = $false
if (Get-Service -Name "MySQL*" -ErrorAction SilentlyContinue) {Write-Host "The MySQL service already exists"$mysqlInstalled = $true
} elseif (Get-Command mysql -ErrorAction SilentlyContinue) {Write-Host "The MySQL client has been installed。"$mysqlInstalled = $true
}if (-not $mysqlInstalled) {$installerPath = ".\mysql\mysql-installer-community-8.0.34.0.msi"if (-not (Test-Path $installerPath)) {Write-Host "Error: The installation package cannot be found $installerPath"exit 1}$installArgs = @("/i","`"$installerPath`"","/qn","/L*v `"$env:TEMP\MySQLInstall.log`"","ADDLOCAL=Server,Client","INSTALLDIR=`"C:\Program Files\MySQL\MySQL Server 8.0`"","PORT=3306","ENABLETCPIP=1","AGREETOLICENSE=Yes","/norestart")# Carry out the installationStart-Process msiexec -ArgumentList $installArgs -Wait# Set environment variables$mysqlBinPath = "C:\Program Files\MySQL\MySQL Server 8.0\bin"[Environment]::SetEnvironmentVariable("Path", "$mysqlBinPath;$env:Path", "Machine")$env:Path += ";$mysqlBinPath"# Initialize the data directory and start the service& "$mysqlBinPath\mysqld" --initialize-insecure --user=mysqlStart-Service -Name "MySQL80"# Set the root password& "$mysqlBinPath\mysql" -u root -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '123456'; FLUSH PRIVILEGES;"try {mysql -u root -p123456 -e "SELECT @@version;" --silentWrite-Host "The MySQL installation was successful."} catch {Write-Host "Connection failed. Please check the log:"Get-Content "$env:ProgramData\MySQL\MySQL Server 8.0\Data\*.err" -Tail 20 -ErrorAction SilentlyContinueWrite-Host "Complete installation log:$env:TEMP\MySQLInstall.log"exit 1}
}
# [4/9]部署后端服务
Write-Host "[4/9] Deploying backend services..."
if (-Not (Test-Path $BackendPackage)) {throw "Error: Backend package $BackendPackage not found!"
}
# Stop existing backend process
$existingProcess = Get-Process -Name java -ErrorAction SilentlyContinue | Where-Object { $_.Id -ne $pid }
if ($existingProcess) {$existingProcess | Stop-Process -Force
}
# Clear and extract backend package
Remove-Item -Path "$DeployPath/backend/*" -Recurse -Force -ErrorAction SilentlyContinue
Expand-Archive -Path $BackendPackage -DestinationPath "$DeployPath/backend" -Force# Check required files
$jarFile = Get-ChildItem "$DeployPath/backend" -Filter *.jar | Select-Object -First 1
if (-Not $jarFile) {throw "No JAR file found, please check the backend package content"
}
# update yml configuration
$configFile = Join-Path -Path $DeployPath -ChildPath "backend/config/application.yml"
if (-Not (Test-Path $configFile)) {throw "Configuration file application.yml not found"
}
$content = Get-Content -Path $configFile -Raw -Encoding UTF8
$lines = $content -split "`r?`n"
for ($i = 0; $i -lt $lines.Length; $i++) {if ($lines[$i] -match "^\s*url:\s*jdbc:mariadb://.*") {if ($lines[$i] -match "^\s*") {$indentation = $matches[0]} else {$indentation = ''}$lines[$i] = "${indentation}url: $MySqlUrl"}
}
$updatedContent = [string]::Join("`n", $lines)
$bytes = [System.Text.Encoding]::UTF8.GetBytes($updatedContent)[System.IO.File]::WriteAllBytes($configFile, $bytes)
Write-Host "Configuration file updated successfully"# [5/9]启动后端服务
Write-Host "[5/9] Starting backend services..."
$jarFile = Get-ChildItem -Path "$DeployPath\backend" -Filter "*.jar" | Select-Object -First 1if (-Not $jarFile) {Write-Host "No .jar file found in directory: $($DeployPath)\backend"exit 1
}
$javaArgs = @("-Dfile.encoding=UTF-8","-Dsun.jnu.encoding=UTF-8","-jar","`"$($jarFile.FullName)`"","--spring.config.location=file:`"$configFile`""
)# Merge arguments into a string
$javaArgsString = $javaArgs -join " "# Print arguments for debugging
Write-Host "Java Arguments: $javaArgsString"# Define a script block to start the Java application with logging
$scriptBlock = {param($javaArgsString, $DeployPath)# Create logs directory$logDir = Join-Path $DeployPath "backend/logs"New-Item -ItemType Directory -Path $logDir -Force | Out-Null# Generate timestamp for log files$stdoutLog = Join-Path $logDir "stdout_logFile.log"$stderrLog = Join-Path $logDir "stderr_logFile.log"# Start Java process with output redirectionStart-Process -FilePath "java" `-ArgumentList $javaArgsString `-NoNewWindow `-PassThru `-RedirectStandardOutput $stdoutLog `-RedirectStandardError $stderrLog
}# Start the background job with parameters
$job = Start-Job -ScriptBlock $scriptBlock -ArgumentList $javaArgsString, $DeployPath# Wait for a moment to ensure the process starts
Start-Sleep -Seconds 5# Get the process ID
$process = Get-Process java -ErrorAction SilentlyContinue | Where-Object { $_.Id -ne $pid } | Select-Object -First 1# Check and output status
if ($null -ne $process -and -not $process.HasExited) {$process.Id | Out-File "$DeployPath/backend/backend.pid"Write-Host "Backend service started (PID: $($process.Id))"Write-Host "Logs directory: $DeployPath/backend/logs/"
} else {Write-Host "Failed to start the backend process."exit 1
}
# Output process ID to file
$process.Id | Out-File "$DeployPath/backend/backend.pid"# [6/9]部署前端服务
Write-Host "[6/9] Deploying frontend services..."
if (-Not (Test-Path $FrontendPackage)) {throw "Error: Frontend package $FrontendPackage not found!"
}Remove-Item -Path "$DeployPath/frontend/*" -Recurse -Force -ErrorAction SilentlyContinue
Expand-Archive -Path $FrontendPackage -DestinationPath "$DeployPath/frontend" -Force# Deploy H5
if (-Not (Test-Path $H5Package)) {throw "Error: Frontend package $H5Package not found!"
}
Remove-Item -Path "$DeployPath/h5/*" -Recurse -Force -ErrorAction SilentlyContinue
Expand-Archive -Path $H5Package -DestinationPath "$DeployPath/h5" -Force
#配置前端文件
$configJs = "$DeployPath/frontend/config.js"
$configH5Js = "$DeployPath/h5/static/config.js"
if (Test-Path $configJs) {Write-Host "Configuring front-end parameters..."try {$originalContent = [System.Text.Encoding]::UTF8.GetString([System.IO.File]::ReadAllBytes($configJs))$newContent = $originalContent -replace 'backendURL:.*', "backendURL: '$BackendURL',"[System.IO.File]::WriteAllBytes($configJs, [System.Text.Encoding]::UTF8.GetBytes($newContent))Write-Host "Front-end configuration updated successfully."} catch {Write-Error "Failed to update front-end configuration: $_"}
} else {Write-Warning "Front-end configuration file config.js not found"
}
if (Test-Path $configH5Js) {Write-Host "Configuring h5 parameters..."try {$originalContent = [System.Text.Encoding]::UTF8.GetString([System.IO.File]::ReadAllBytes($configH5Js))$newContent = $originalContent -replace 'backendURL:.*', "backendURL: '$BackendURL',"[System.IO.File]::WriteAllBytes($configH5Js, [System.Text.Encoding]::UTF8.GetBytes($newContent))Write-Host "h5 configuration updated successfully."} catch {Write-Error "Failed to update h5 configuration: $_"}
} else {Write-Warning "h5 configuration file config.js not found"
}
# [7/9]部署nginx服务
Write-Host "[7/9] Deploying Nginx services..."
if (-Not (Test-Path $NginxPath)) {throw "Error: Nginx package $NginxPath not found!"
}
# Stop old process (enhanced version)
if (Get-Process -Name "nginx" -ErrorAction SilentlyContinue) {taskkill /IM "nginx.exe" /F 2>&1 | Out-Null
}
# Clear and extract Nginx
Remove-Item -Path "$DeployPath/nginx/*" -Recurse -Force -ErrorAction SilentlyContinue
Expand-Archive -Path $NginxPath -DestinationPath "$DeployPath/nginx" -Force#前端配置目录移到nginx目录下的html文件夹下
Copy-Item -Path "$DeployPath/frontend" -Destination "$DeployPath/nginx/nginx-1.24.0/html/PC" -Recurse -Force
Copy-Item -Path "$DeployPath/h5" -Destination "$DeployPath/nginx/nginx-1.24.0/html/PDA" -Recurse -Force# [8/9]配置niginx
Write-Host "[8/9] Configuring Nginx services..."# Normalize paths
$nginxLogsPath = "$DeployPath\nginx\nginx-1.24.0\logs" -replace '\\', '\'
$nginxConfPath = "$DeployPath\nginx\nginx-1.24.0\conf\wms-nginx.conf"
$nginxExePath = "$DeployPath\nginx\nginx-1.24.0\nginx.exe"
$logsPath = "$DeployPath\logs"
$tempPath = "$DeployPath\temp"
# Create necessary directories
New-Item -Path $nginxLogsPath -ItemType Directory -Force | Out-Null$logFiles = @("access.log", "error.log", "nginx.pid")
if (-not (Test-Path $logsPath)) {New-Item -ItemType Directory -Path $logsPath
}
foreach ($logFile in $logFiles) {$logFilePath = "$logsPath\$logFile"if (-not (Test-Path $logFilePath)) {New-Item -ItemType File -Path $logFilePathWrite-Host "Created $logFile at: $logFilePath"}
}$tempFolders = @("client_body_temp", "fastcgi_temp", "proxy_temp", "scgi_temp", "uwsgi_temp")
if (-not (Test-Path $tempPath)) {New-Item -ItemType Directory -Path $tempPath
}
foreach ($tempFolder in $tempFolders) {$tempFolderPath = "$tempPath\$tempFolder"if (-not (Test-Path $tempFolderPath)) {New-Item -ItemType Directory -Path $tempFolderPathWrite-Host "Created $tempFolder at: $tempFolderPath"}
}
# Generate Nginx configuration file
$nginxConf = @"
#user nobody;
worker_processes 1;#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;#pid logs/nginx.pid;events {worker_connections 1024;
}http {include mime.types;default_type application/octet-stream;sendfile on;keepalive_timeout 65;map `$http_user_agent` `$root_path` {default $NginxDeployPath/nginx/nginx-1.24.0/html/PC;~*(android|iphone|ipad|mobile) $NginxDeployPath/nginx/nginx-1.24.0/html/PDA;}server {listen $NginxListenPort;server_name localhost;location /static/config.js {alias $NginxDeployPath/nginx/nginx-1.24.0/html/PC/config.js;add_header 'Access-Control-Allow-Origin' '*' always;}location / {root `$root_path`;index index.html index.htm;try_files `$uri` `$uri`/ /index.html;}error_page 500 502 503 504 /50x.html;location = /50x.html {root html;}}server {listen 1112;server_name $BackendAddress;location / {root $DeployPath\backend\upload;index index.html index.htm;autoindex on;}}
}"@# Write configuration file
# Convert string content to byte array (without BOM)
$bytes = [System.Text.Encoding]::UTF8.GetBytes($nginxConf)
# Write byte array to file
[System.IO.File]::WriteAllBytes($nginxConfPath, $bytes)# Check Nginx executable
if (-not (Test-Path $nginxExePath)) {throw "Nginx executable missing at: $nginxExePath"
}# Test configuration file
& "$nginxExePath" -t -c "$nginxConfPath"
if ($LASTEXITCODE -ne 0) {Write-Host "Nginx configuration test failed. Please check the configuration file."exit $LASTEXITCODE
} else {Write-Host "Nginx configuration test passed."
}
# [9/9]启动nginx服务
Write-Host "[9/9] Starting Nginx services..."
Start-Process -FilePath "$nginxExePath" -ArgumentList "-c $nginxConfPath" -NoNewWindow# Wait a few seconds to ensure Nginx has enough time to start
Start-Sleep -Seconds 5# Check Nginx process
$nginxProcess = Get-Process -Name "nginx" -ErrorAction SilentlyContinueif ($nginxProcess) {Write-Output "Nginx has started successfully."
} else {Write-Output "Nginx failed to start. Please check the configuration file and logs."
}Write-Host @"
==========================================
WMS system deployment successfully!
==========================================
"@
wms-config.ps1
# 基础部署路径
$DeployPath = "E:\wms-test-4"
$NginxDeployPath = "E:/wms-test-4"# 后端数据库配置
$MySqlUrl = "jdbc:mariadb://127.0.0.1:3306/wms_zhixiang_03_10?characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&serverTimezone=Asia/Shanghai"# 后端包路径
$BackendPackage = ".\wms-service-3.4.4.zhixiang.1-1.zip"# 前端包路径
$FrontendPackage = ".\wms3.0-frontend.zip"#前端 H5包路径
$H5Package = ".\h5.zip"# Nginx安装路径
$NginxPath = ".\nginx-1.24.0.zip"
#后端端口
$serverPort = "8082"
$newPort = "8082"
# 后端服务地址
$BackendURL = "http://10.14.240.208:8081"
$BackendAddress = "10.14.240.208:8081"# Nginx监听端口(前端端口)
$NginxListenPort = "8842"