[PowerShell] 筆記 - 搭配PowerShell完成自動化部屬

延續先前使用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?

筆記各種踩雷的過程,若有錯誤還請告知