延續先前使用gitlab的CI流程,這次加入PowerShell完成後續CD的流程,筆記一下這次的內容
Yml
這次為yml檔加上deploy的stage,很單純的只呼叫ps1做事,
專案有兩個ps1,皆放在資料夾Ps1中
stages:
- deploy
before_script:
- chcp 65001
deploy:
stage: deploy
script:
- dotnet publish ./MyProject/ -c release -o ./output
- ./Ps1/PreDeploy.ps1 $env:DeployAccount_Stage $env:DeployPassword_Stage
chcp 65001
指定UTF-8編碼,頁碼頁
dotnet publish ./MyProject/ -c release -o ./output
指定release組態發佈,並且指定發佈的位置在 “./output”
$env:DeployAccount_Stage
PowerShell取得環境變數的方式,相關值會存在gitlab的 “Settings > Variables”
./Ps1/PreDeploy.ps1 $env:DeployAccount_Stage $env:DeployPassword_Stage
執行 PreDeploy.ps1,並且傳入兩個值
PreDeploy.ps1(GitLab Runner)
$account = $args[0]
$password = $args[1]
<# 取的傳入的參數值 #>
$serverName = "192.168.1.1"
<# 要部署的server位置 #>
$projectName = "MyProject"
$version = Get-Date -Format "yyyyMMddHHmmss"
$location = $(PWD)
<# 取得當下的絕對路徑,Get-Location的別名 #>
$publishPath = "$location\output"
$deployPsPath = "$location\Ps1\Deploy.ps1"
$remoteDeployPath = "C:\Deploy\"
<# 將publish的結果壓縮為.zip #>
echo "Compress files"
$zipDir = "$location\$projectName\"
if ((Test-Path $zipDir -PathType Any) -eq 0)
{
new-item $zipDir -itemtype directory
}
$zipFilePath = "$zipDir$version.zip";
$compress = @{
Path = $publishPath
CompressionLevel = "Fastest"
DestinationPath = $zipFilePath
}
Compress-Archive @compress -Update
if(!$?) { throw $LASTEXITCODE }
echo "Compress files $zipFilePath"
<# 遠端連線到目標主機 *註1 #>
echo "Get Session"
$pw = convertto-securestring -AsPlainText -Force -String $password
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $account, $pw
$session = New-PSSession -ComputerName $serverName -Credential $cred
if(!$?) { throw $LASTEXITCODE }
echo "Get Session done"
<# 遠端連線失敗則中斷script,並且返回錯誤訊息 #>
<# 將zip檔複製到遠端主機上 #>
echo "copy zip file"
$targetDir = "C:\Deploy\Zip\"
if ((Test-Path $targetDir -PathType Any) -eq 0)
{
Invoke-Command -Session $session -Command { New-Item $args[0] -ItemType directory -force } -Args $targetDir
}
$publishZipFile = "$targetDir$version.zip"
Copy-Item -path $zipFilePath -Destination $targetDir -ToSession $session
if(!$?) { throw $LASTEXITCODE }
echo "copy zip file $publishZipFile"
<# 複製失敗則中斷 #>
<# 將 deploy.ps1 複製到遠端主機,遠端主機的部署流程會放在這 #>
Copy-Item -path $deployPsPath -Destination $remoteDeployPath -ToSession $session
if(!$?) { throw $LASTEXITCODE }
<# 複製失敗則中斷 #>
<# 呼叫遠端主機執行 Deploy.ps1 #>
Invoke-Command -Session $session -scriptblock {
C:\deploy\Deploy.ps1 $args[0] $args[1]
} -ArgumentList $publishZipFile, $version
<# 關閉遠端連線 #>
$session | Remove-PSSession
Deploy.ps1(Target Server)
$zipPath = $args[0]
$version = $args[1]
<# 取得傳入的參數值 #>
$name = "MyProject"
$backupDirPath = "C:\Deploy\Backup"
$expandPath = "C:\Deploy\Expand"
$webSitePath = "C:\inetpub"
<# 解壓縮zip #>
echo "begin expand zip file"
Expand-Archive -LiteralPath $zipPath -DestinationPath $expandPath -Force
if(!$?) { throw $LASTEXITCODE }
<# 失敗則中斷 #>
echo "end expand zip file, path: $expandPath"
echo "---"
$pool = $name
<# 停止IIS上的 application pool #>
echo "begin stop application pool '$pool'"
$retryCount = 0;
$state = (Get-WebAppPoolState -Name $pool).Value
<# retry 30次,直到成功,每次失敗休息1秒 #>
while($state -Like "Start*")
{
Stop-WebAppPool -Name $pool
$state = (Get-WebAppPoolState -Name $pool).Value
if($state -Like "Start*")
{
$retryCount += 1;
echo "retry stop pool, $retryCount."
Start-Sleep -Milliseconds 1000
}
if($retryCount -eq 30)
{
throw "stop application pool '$pool' get 10 time error."
}
}
Start-Sleep -Milliseconds 1000
echo "end stop application pool '$pool'"
echo "---"
<# 將原本的檔案備份 #>
echo "begin backup folder"
$folderPath = "$webSitePath\$pool"
$backupPath = "$backupDirPath\$version"
if((Test-Path $backupPath -PathType Any) -eq 0)
{
new-item $backupPath -itemtype directory
}
Copy-Item -Path $folderPath -Recurse $backupPath -Force -Exclude ("*.log")
if(!$?) { throw $LASTEXITCODE }
echo "end move backup folder, source: '$folderPath' target: '$backupPath'"
echo "---"
<# zip解壓縮後的檔案複製過去 #>
echo "copy file to iis folder $pool"
[string]$expandFiles = "$expandPath\output\*"
[string]$targetPath = "$webSitePath\$pool"
Copy-item -Force -Recurse -Verbose $expandFiles -Destination $targetPath
echo "copy file to iis folder $pool, sourc: $expandFiles path: $targetPath"
<# 開啟IIS的 applcation pool #>
echo "begin start application pool '$pool'"
$retryCount = 0;
$state = (Get-WebAppPoolState -Name $pool).Value
while($state -Like "Stop*")
{
Start-WebAppPool -Name $pool
$state = (Get-WebAppPoolState -Name $pool).Value
if($state -Like "Stop*")
{
$retryCount += 1
echo "retry start pool, $retryCount."
Start-Sleep -Milliseconds 1000
}
if($retryCount -eq 30)
{
throw "start application pool '$pool' get 10 time error."
}
}
echo "end start application pool '$pool'"
echo "---"
<# 發request戳醒站台,並檢查是否正常 #>
$HTTP_Request = [System.Net.WebRequest]::Create('http://localhost:60000')
$StatusCode = $HTTP_Request.GetResponse().StatusCode
echo "Hms_1 $StatusCode"
if ($StatusCode -ne "OK")
{
throw "status = $StatusCode"
}
<# 刪除舊檔案 #>
$oldFiles = get-childitem $backupDirPath
foreach ($file in $oldFiles)
{
if($file.FullName -ne $backupPath)
{
echo "delete item: " ($file.FullName)
Remove-Item -Path $file.FullName -Confirm:$false -Force -Recurse
}
}
$oldDir = Split-Path -Path $zipPath
$oldFiles = get-childitem $oldDir
foreach ($file in $oldFiles)
{
echo "delete item: " ($file.FullName)
Remove-Item $file.FullName -Confirm:$false -Force -Recurse
}
echo "delete item: C:\deploy\Expand"
Remove-Item -Path C:\deploy\Expand -Confirm:$false -Force -Recurse
echo "delete item: C:\deploy\Deploy.ps1"
Remove-Item C:\deploy\Deploy.ps1 -Confirm:$false -Force -Recurse
return true
*註1
遠端前需要開啟相關功能及設定,可參考先前的文章,由gitlab執行時需要為服務"gitlab-runner"指定登入身份,否則可能會遇到無法遠端連線的訊息
GitLab Runner(PowerShell)
Shells supported by GitLab Runner
How to copy content of a folder to another specific folder using powershell?
Use PowerShell Copy-Item To File Transfer Over WinRM
How-to: Comparison Operators
What is $?
in Powershell?
筆記各種踩雷的過程,若有錯誤還請告知
Yml
這次為yml檔加上deploy的stage,很單純的只呼叫ps1做事,
專案有兩個ps1,皆放在資料夾Ps1中
stages: - deploy before_script: - chcp 65001 deploy: stage: deploy script: - dotnet publish ./MyProject/ -c release -o ./output - ./Ps1/PreDeploy.ps1 $env:DeployAccount_Stage $env:DeployPassword_Stage
chcp 65001
指定UTF-8編碼,頁碼頁
dotnet publish ./MyProject/ -c release -o ./output
指定release組態發佈,並且指定發佈的位置在 “./output”
$env:DeployAccount_Stage
PowerShell取得環境變數的方式,相關值會存在gitlab的 “Settings > Variables”
./Ps1/PreDeploy.ps1 $env:DeployAccount_Stage $env:DeployPassword_Stage
執行 PreDeploy.ps1,並且傳入兩個值
PreDeploy.ps1(GitLab Runner)
$account = $args[0] $password = $args[1] <# 取的傳入的參數值 #> $serverName = "192.168.1.1" <# 要部署的server位置 #> $projectName = "MyProject" $version = Get-Date -Format "yyyyMMddHHmmss" $location = $(PWD) <# 取得當下的絕對路徑,Get-Location的別名 #> $publishPath = "$location\output" $deployPsPath = "$location\Ps1\Deploy.ps1" $remoteDeployPath = "C:\Deploy\" <# 將publish的結果壓縮為.zip #> echo "Compress files" $zipDir = "$location\$projectName\" if ((Test-Path $zipDir -PathType Any) -eq 0) { new-item $zipDir -itemtype directory } $zipFilePath = "$zipDir$version.zip"; $compress = @{ Path = $publishPath CompressionLevel = "Fastest" DestinationPath = $zipFilePath } Compress-Archive @compress -Update if(!$?) { throw $LASTEXITCODE } echo "Compress files $zipFilePath" <# 遠端連線到目標主機 *註1 #> echo "Get Session" $pw = convertto-securestring -AsPlainText -Force -String $password $cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $account, $pw $session = New-PSSession -ComputerName $serverName -Credential $cred if(!$?) { throw $LASTEXITCODE } echo "Get Session done" <# 遠端連線失敗則中斷script,並且返回錯誤訊息 #> <# 將zip檔複製到遠端主機上 #> echo "copy zip file" $targetDir = "C:\Deploy\Zip\" if ((Test-Path $targetDir -PathType Any) -eq 0) { Invoke-Command -Session $session -Command { New-Item $args[0] -ItemType directory -force } -Args $targetDir } $publishZipFile = "$targetDir$version.zip" Copy-Item -path $zipFilePath -Destination $targetDir -ToSession $session if(!$?) { throw $LASTEXITCODE } echo "copy zip file $publishZipFile" <# 複製失敗則中斷 #> <# 將 deploy.ps1 複製到遠端主機,遠端主機的部署流程會放在這 #> Copy-Item -path $deployPsPath -Destination $remoteDeployPath -ToSession $session if(!$?) { throw $LASTEXITCODE } <# 複製失敗則中斷 #> <# 呼叫遠端主機執行 Deploy.ps1 #> Invoke-Command -Session $session -scriptblock { C:\deploy\Deploy.ps1 $args[0] $args[1] } -ArgumentList $publishZipFile, $version <# 關閉遠端連線 #> $session | Remove-PSSession
Deploy.ps1(Target Server)
$zipPath = $args[0] $version = $args[1] <# 取得傳入的參數值 #> $name = "MyProject" $backupDirPath = "C:\Deploy\Backup" $expandPath = "C:\Deploy\Expand" $webSitePath = "C:\inetpub" <# 解壓縮zip #> echo "begin expand zip file" Expand-Archive -LiteralPath $zipPath -DestinationPath $expandPath -Force if(!$?) { throw $LASTEXITCODE } <# 失敗則中斷 #> echo "end expand zip file, path: $expandPath" echo "---" $pool = $name <# 停止IIS上的 application pool #> echo "begin stop application pool '$pool'" $retryCount = 0; $state = (Get-WebAppPoolState -Name $pool).Value <# retry 30次,直到成功,每次失敗休息1秒 #> while($state -Like "Start*") { Stop-WebAppPool -Name $pool $state = (Get-WebAppPoolState -Name $pool).Value if($state -Like "Start*") { $retryCount += 1; echo "retry stop pool, $retryCount." Start-Sleep -Milliseconds 1000 } if($retryCount -eq 30) { throw "stop application pool '$pool' get 10 time error." } } Start-Sleep -Milliseconds 1000 echo "end stop application pool '$pool'" echo "---" <# 將原本的檔案備份 #> echo "begin backup folder" $folderPath = "$webSitePath\$pool" $backupPath = "$backupDirPath\$version" if((Test-Path $backupPath -PathType Any) -eq 0) { new-item $backupPath -itemtype directory } Copy-Item -Path $folderPath -Recurse $backupPath -Force -Exclude ("*.log") if(!$?) { throw $LASTEXITCODE } echo "end move backup folder, source: '$folderPath' target: '$backupPath'" echo "---" <# zip解壓縮後的檔案複製過去 #> echo "copy file to iis folder $pool" [string]$expandFiles = "$expandPath\output\*" [string]$targetPath = "$webSitePath\$pool" Copy-item -Force -Recurse -Verbose $expandFiles -Destination $targetPath echo "copy file to iis folder $pool, sourc: $expandFiles path: $targetPath" <# 開啟IIS的 applcation pool #> echo "begin start application pool '$pool'" $retryCount = 0; $state = (Get-WebAppPoolState -Name $pool).Value while($state -Like "Stop*") { Start-WebAppPool -Name $pool $state = (Get-WebAppPoolState -Name $pool).Value if($state -Like "Stop*") { $retryCount += 1 echo "retry start pool, $retryCount." Start-Sleep -Milliseconds 1000 } if($retryCount -eq 30) { throw "start application pool '$pool' get 10 time error." } } echo "end start application pool '$pool'" echo "---" <# 發request戳醒站台,並檢查是否正常 #> $HTTP_Request = [System.Net.WebRequest]::Create('http://localhost:60000') $StatusCode = $HTTP_Request.GetResponse().StatusCode echo "Hms_1 $StatusCode" if ($StatusCode -ne "OK") { throw "status = $StatusCode" } <# 刪除舊檔案 #> $oldFiles = get-childitem $backupDirPath foreach ($file in $oldFiles) { if($file.FullName -ne $backupPath) { echo "delete item: " ($file.FullName) Remove-Item -Path $file.FullName -Confirm:$false -Force -Recurse } } $oldDir = Split-Path -Path $zipPath $oldFiles = get-childitem $oldDir foreach ($file in $oldFiles) { echo "delete item: " ($file.FullName) Remove-Item $file.FullName -Confirm:$false -Force -Recurse } echo "delete item: C:\deploy\Expand" Remove-Item -Path C:\deploy\Expand -Confirm:$false -Force -Recurse echo "delete item: C:\deploy\Deploy.ps1" Remove-Item C:\deploy\Deploy.ps1 -Confirm:$false -Force -Recurse return true
*註1
遠端前需要開啟相關功能及設定,可參考先前的文章,由gitlab執行時需要為服務"gitlab-runner"指定登入身份,否則可能會遇到無法遠端連線的訊息
GitLab Runner(PowerShell)
Shells supported by GitLab Runner
How to copy content of a folder to another specific folder using powershell?
Use PowerShell Copy-Item To File Transfer Over WinRM
How-to: Comparison Operators
What is
$?
in Powershell?筆記各種踩雷的過程,若有錯誤還請告知